赞
踩
前言:最近写了微信及支付宝支付,整理了一下,方便直接CV,遇到有支付的问题,不要犹豫,直接问微信客服,解决起来方便快捷,代码可以直接CV过去就能用,配置一下application.yml里面微信支付的所需参数就可以了.
以下是gitee项目地址,代码在dev分支
https://gitee.com/yuyuyuyulv/gjj-ry/tree/dev/
<!-- 微信支付 --> <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-miniapp</artifactId> <version>4.4.2.B</version> </dependency> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-pay</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> <version>4.4.0</version> </dependency>
具体如何获得微信支付所需参数appid等,可以去找其他文章,或者直接找公司要
wx:
pay:
appId: #微信公众号或者小程序等的appid
secret:
mchId: #微信支付商户号
mchKey: #微信支付商户密钥
notifyUrl: http://8.130.135.74:8053/api/order/student/pay/wxCallback #支付回调地址
具体如何获得微信支付所需参数appid等,可以去找其他文章,或者直接找公司要,沙箱环境也需要商户账号才能使用沙箱
package com.ruoyi.common.wx; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author Binary Wang */ @Configuration @ConditionalOnClass(WxPayService.class) @EnableConfigurationProperties(WxPayProperties.class) @AllArgsConstructor public class WxPayConfiguration { private WxPayProperties properties; @Bean @ConditionalOnMissingBean public WxPayService wxService() { WxPayConfig payConfig = new WxPayConfig(); payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId())); payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId())); payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey())); WxPayService wxPayService = new WxPayServiceImpl(); wxPayService.setConfig(payConfig); return wxPayService; } }
package com.ruoyi.common.wx; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; /** * wxpay pay properties. * * @author Binary Wang */ @Data @ConfigurationProperties(prefix = "wx.pay") public class WxPayProperties { /** * 设置微信公众号或者小程序等的appid */ private String appId; private String secret; /** * 微信支付商户号 */ private String mchId; /** * 微信支付商户密钥 */ private String mchKey; /** * 回调地址 */ private String notifyUrl; }
package com.ruoyi.common.wx; import com.alibaba.fastjson.JSONObject; import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.bean.result.WxPayRefundResult; import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult; import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.util.SignUtils; import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.*; /** * @description: 支付相关通用服务 */ @Service public class PayService { @Autowired private WxPayService wxPayService; /** * 根据传入的tradeType来进行不同类型的支付 * @param dto 商品参数 * @param tradeType WxPayConstants.TradeType.MWEB为H5支付/WxPayConstants.TradeType.NATIVE为扫码支付/WxPayConstants.TradeType.JSAPI为JSAPI支付 * @return */ public Object transactions(WxPayDTO dto,String tradeType) { try { if (tradeType != null && !tradeType.isEmpty()){ if (WxPayConstants.TradeType.MWEB.equals(tradeType)){ //H5支付 return noMiniappPay(dto, tradeType); }else if (WxPayConstants.TradeType.NATIVE.equals(tradeType)){ //NATIVE支付 return noMiniappPay(dto, tradeType); }else if (WxPayConstants.TradeType.JSAPI.equals(tradeType)){ //JSAPI支付 return miniappPay(dto); } } } catch (Exception e) { // 处理异常 e.printStackTrace(); return null; } return null; } private String noMiniappPay(WxPayDTO dto, String tradeType) throws WxPayException { //设置请求参数 WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); request.setOutTradeNo(dto.getOutTradeNo()); request.setTotalFee(dto.getTotalFee()); request.setBody(dto.getBody()); HttpServletRequest httpServletRequest = getHttpServletRequest(); request.setSpbillCreateIp(httpServletRequest.getRemoteAddr()); request.setNotifyUrl(dto.getNotifyUrl()); request.setProductId(dto.getOutTradeNo()); //设置下单方式 request.setTradeType(tradeType); // 调用统一下单接口 WxPayNativeOrderResult result = wxPayService.createOrder(request); // Native支付返回的二维码/H5支付返回的跳转链接 String codeUrl = result.getCodeUrl(); // 返回codeUrl给前端 return codeUrl; } /** * * @param dto * @return */ @SneakyThrows public Map<String, String> miniappPay(WxPayDTO dto){ //设置请求参数 WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() .body(dto.getBody()) .totalFee(dto.getTotalFee()) .spbillCreateIp(this.getIpAddress(this.getHttpServletRequest())) .notifyUrl(dto.getNotifyUrl()) .tradeType(WxPayConstants.TradeType.JSAPI) .openid(dto.getOpenId()) .outTradeNo(dto.getOutTradeNo()) .timeStart(dto.getTimeStart()) .timeExpire(dto.getTimeExpire()) .build(); request.setSignType(WxPayConstants.SignType.MD5); //发起微信 统一下单 WxPayUnifiedOrderResult result = null; result = this.wxPayService.unifiedOrder(request); //前端启动支付配置 if (StringUtils.isBlank(result.getPrepayId())) { return null; } //返回前端调取jsapi支付的所需参数 return getWxJsapiPayParam(result); } /** * 微信退款 * @param body * @return */ public void wxRefund(WxRefundDTO body) { WxPayRefundRequest refundRequest = new WxPayRefundRequest(); refundRequest.setOutTradeNo(body.getOutTradeNo()); refundRequest.setOutRefundNo(body.getOutRefundNo()); refundRequest.setTotalFee(body.getTotalFee()); refundRequest.setRefundFee(body.getRefundFee()); refundRequest.setRefundDesc("商品退款"); refundRequest.setNotifyUrl(body.getNotifyUrl()); try { WxPayRefundResult result = wxPayService.refund(refundRequest); System.out.println("微信退款成功,返回参数{}" + JSONObject.toJSONString(result)); } catch (WxPayException e) { System.out.println("微信退款异常,返回参数{}" + JSONObject.toJSONString(e)); } } /** * 获取请求对象 * * @return */ private HttpServletRequest getHttpServletRequest() { HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String key = headerNames.nextElement(); System.out.println("请求头:" + key + "值:" + request.getHeader(key)); } return request; } /** * 获取到JS支付相关配置 * * @param weiXinPayOrder * @return */ private Map<String, String> getWxJsapiPayParam(WxPayUnifiedOrderResult weiXinPayOrder) { WxPayWebDTO wxPayParam = new WxPayWebDTO(); String package_ = "prepay_id=" + weiXinPayOrder.getPrepayId(); wxPayParam.setAppId(weiXinPayOrder.getAppid()); wxPayParam.setTimeStamp(System.currentTimeMillis() / 1000 + ""); wxPayParam.setNonceStr(UUID.randomUUID().toString().replace("-", "")); wxPayParam.setPackage1(package_); wxPayParam.setSignType(WxPayConstants.SignType.MD5); //WxPayParam中属性package1,签名使用key是package Map<String, String> signParam = new LinkedHashMap<String, String>(); signParam.put("appId", weiXinPayOrder.getAppid()); signParam.put("nonceStr", wxPayParam.getNonceStr()); signParam.put("package", package_); signParam.put("signType", WxPayConstants.SignType.MD5); signParam.put("timeStamp", wxPayParam.getTimeStamp()); String paySign = SignUtils.createSign(signParam,WxPayConstants.SignType.MD5, this.wxPayService.getConfig().getMchKey(), new String[0]); signParam.put("paySign", paySign); return signParam; } }
package com.ruoyi.web.controller.system; import com.alibaba.fastjson.JSONObject; import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.wxpay.sdk.WXPayUtil; import com.ruoyi.common.utils.DateUtil; import com.ruoyi.common.wx.PayService; import com.ruoyi.common.wx.StreamUtils; import com.ruoyi.common.wx.WxPayDTO; import com.ruoyi.common.wx.WxPayProperties; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Date; import java.util.HashMap; import java.util.Map; @Api(tags = "微信支付相关接口") @RestController @Slf4j @Validated @RequiredArgsConstructor @RequestMapping("/pay") public class WechatPayController { @Resource private PayService payService; @Resource private WxPayProperties wxPayProperties; @ApiOperation(value = "微信native下单,返回支付二维码") @GetMapping("/nativePay") public Object nativePay(@RequestParam("orderNumber") String orderNumber) { //todo 业务操作-根据订单编号查询订单信息 //将订单信息中的数据存到WxPayDTO WxPayDTO payDTO = new WxPayDTO(); payDTO.setBody("商品描述"); //订单总金额,单位为分 payDTO.setTotalFee(1); //支付回调地址 payDTO.setNotifyUrl(wxPayProperties.getNotifyUrl()); //商品订单编号 payDTO.setOutTradeNo(orderNumber); //获取时间 Date date = new Date(); String timeStart = DateUtil.formatDateToString(date, "yyyyMMddHHmmss"); //结束时间设置在30分钟后 String timeExpire = DateUtil.formatDateToString(DateUtil.addMinutesToDate(date, 30),"yyyyMMddHHmmss"); //交易起始时间 payDTO.setTimeStart(timeStart); //交易结束时间 payDTO.setTimeExpire(timeExpire); Object url = payService.transactions(payDTO, WxPayConstants.TradeType.NATIVE); return url; } @ApiOperation(value = "微信JSAPI下单,返回JS支付相关配置") @GetMapping("/jsapiPay") public Object jsapiPay(@RequestParam("orderNumber") String orderNumber) { //todo 业务操作-根据订单编号查询订单信息 //将订单信息中的数据存到WxPayDTO WxPayDTO payDTO = new WxPayDTO(); payDTO.setBody("商品描述"); //订单总金额,单位为分 payDTO.setTotalFee(1); //支付回调地址 payDTO.setNotifyUrl(wxPayProperties.getNotifyUrl()); payDTO.setOutTradeNo("商户订单号"); //获取时间 Date date = new Date(); String timeStart = DateUtil.formatDateToString(date, "yyyyMMddHHmmss"); //结束时间设置在30分钟后 String timeExpire = DateUtil.formatDateToString(DateUtil.addMinutesToDate(date, 30),"yyyyMMddHHmmss"); //交易起始时间 payDTO.setTimeStart(timeStart); //交易结束时间 payDTO.setTimeExpire(timeExpire); //todo jsapi下单需要用户的openid payDTO.setOpenId("openid"); Object url = payService.transactions(payDTO, WxPayConstants.TradeType.JSAPI); return url; } @ApiOperation(value = "微信H5下单,返回跳转链接") @GetMapping("/h5Pay") public Object h5Pay(@RequestParam("orderNumber") String orderNumber, HttpServletRequest request) { //todo 业务操作-根据订单编号查询订单信息 //将订单信息中的数据存到WxPayDTO WxPayDTO payDTO = new WxPayDTO(); payDTO.setBody("商品描述"); //订单总金额,单位为分 payDTO.setTotalFee(1); //支付回调地址 payDTO.setNotifyUrl(wxPayProperties.getNotifyUrl()); payDTO.setOutTradeNo("商户订单号"); //获取时间 Date date = new Date(); String timeStart = DateUtil.formatDateToString(date, "yyyyMMddHHmmss"); //结束时间设置在30分钟后 String timeExpire = DateUtil.formatDateToString(DateUtil.addMinutesToDate(date, 30),"yyyyMMddHHmmss"); //交易起始时间 payDTO.setTimeStart(timeStart); //交易结束时间 payDTO.setTimeExpire(timeExpire); //todo H5下单需要用户的用户的客户端IP String remoteAddr = request.getRemoteAddr(); payDTO.setPayerClientIp(remoteAddr); Object url = payService.transactions(payDTO, WxPayConstants.TradeType.JSAPI); return url; } @ApiOperation(value = "微信支付回调") @PostMapping("/wxCallback") public Object wxCallback(HttpServletRequest request, HttpServletResponse response) { ServletInputStream inputStream = null; try { inputStream = request.getInputStream(); String notifyXml = StreamUtils.inputStream2String(inputStream, "utf-8"); log.info(notifyXml); // 解析返回结果 Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml); String jsonString = JSONObject.toJSONString(notifyMap); log.info(jsonString); // 判断支付是否成功 if ("SUCCESS".equals(notifyMap.get("result_code"))) { //todo 修改订单状态 // 支付成功:给微信发送我已接收通知的响应 创建响应对象 Map<String, String> returnMap = new HashMap<>(); returnMap.put("return_code", "SUCCESS"); returnMap.put("return_msg", "OK"); String returnXml = WXPayUtil.mapToXml(returnMap); response.setContentType("text/xml"); log.info("支付成功"); return returnXml; }else { //保存回调信息,方便排除问题 } // 创建响应对象:微信接收到校验失败的结果后,会反复的调用当前回调函数 Map<String, String> returnMap = new HashMap<>(); returnMap.put("return_code", "FAIL"); returnMap.put("return_msg", ""); String returnXml = WXPayUtil.mapToXml(returnMap); response.setContentType("text/xml"); log.info("校验失败"); return returnXml; } catch (Exception e) { e.printStackTrace(); } return null; } }
package com.ruoyi.common.wx; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) public class WxPayDTO { /** * openId */ private String openId; /** * 字段名:商品描述. * 变量名:body * 是否必填:是 * 类型:String(128) * 示例值: 腾讯充值中心-QQ会员充值 * 描述:商品简单描述,该字段须严格按照规范传递,具体请见参数规定 */ private String body; /** * 字段名:总金额. * 变量名:total_fee * 是否必填:是 * 类型:Int * 示例值: 888 * 描述:订单总金额,单位为分,详见支付金额 */ private Integer totalFee; /** * 字段名:通知地址. * 变量名:notify_url * 是否必填:是 * 类型:String(256) * 示例值:http://www.weixin.qq.com/wxpay/pay.php * 描述:接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。 */ private String notifyUrl; /** * 字段名:商户订单号. * 变量名:out_trade_no * 是否必填:是 * 类型:String(32) * 示例值:20150806125346 * 描述:商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号 */ private String outTradeNo; /** * 字段名:交易起始时间. * 变量名:time_start * 是否必填:否 * 类型:String(14) * 示例值:20091225091010 * 描述:订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则 */ private String timeStart; /** * 字段名:交易结束时间. * 变量名:time_expire * 是否必填:否 * 类型:String(14) * 示例值:20091227091010 * 描述:订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则 * 注意:最短失效时间间隔必须大于5分钟 */ private String timeExpire; /** * 字段名:用户的客户端IP * 变量名:payer_client_ip * 是否必填:是 * 类型:String(14) * 示例值:14.23.150.211 * 描述:用户的客户端IP,支持IPv4和IPv6两种格式的IP地址。 * 注意:最短失效时间间隔必须大于5分钟 */ private String payerClientIp; }
package com.ruoyi.common.wx; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) @ApiModel public class WxPayWebDTO { /** * 公众号id */ @ApiModelProperty("公众号id") private String appId; /** * 时间戳 */ @ApiModelProperty("时间戳") private String timeStamp; /** * 随机字符串 */ @ApiModelProperty("随机字符串") private String nonceStr; /** * 订单详情扩展字符串 */ @ApiModelProperty("订单详情扩展字符串") private String package1; /** * 签名方式 */ @ApiModelProperty("签名方式") private String signType; /** * 签名 */ @ApiModelProperty("签名") private String paySign; }
package com.ruoyi.common.wx; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class WxRefundDTO { /** * 商户订单号 */ private String outTradeNo; /** * 商户退款单号 */ private String outRefundNo; /** * 订单金额 单位:分 */ private Integer totalFee; /** * 退款金额 单位:分 */ private Integer refundFee; /** * 退款结果通知url */ private String notifyUrl; }
可以自己先用测试数据进行测试,搞清楚后再进行业务逻辑的书写
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。