当前位置:   article > 正文

【微信支付】【java】Springboot对接开发微信支付_wechatpay-java

wechatpay-java

本文章是介绍java对接(微信小程序)微信支付,包括微信预下单、支付、退款等等。 

目录

 一、微信配置申请

1、微信支付配置申请

二、开发环境

1、开发环境

2、maven依赖

3、application.yml文件配置

三、代码开发

1、配置类

2、初始化商户配置

3、JSAPI微信预下单

3.1、先建个WxPayService服务类

3.1、R实体类

3.2、CreateOrderReq类

4、微信支付回调通知 

5、根据商户订单号查询订单(out_trade_no)

5.1  QueryOrderReq类

6、根据支付订单号查询订单 (transaction_id)

7、微信申请退款

8、退款回调通知 

四、mysql表结构

五、controller类


 一、微信配置申请

1、微信支付配置申请

详细操作流程参考官方文档:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml#part-1

配置完成需要以下信息:

  • APPID
  • 商户号(mchid)
  • 商户API私钥(apiclient_key.pem)
  • 商户证书序列号
  • 商户APIv3密钥

二、开发环境

1、开发环境

开发语言:java ,编译工具:idea ,框架:springboot ,仓库:maven

2、maven依赖

  1. <dependency>
  2. <groupId>com.github.wechatpay-apiv3</groupId>
  3. <artifactId>wechatpay-java</artifactId>
  4. <version>0.2.10</version>
  5. </dependency>

3、application.yml文件配置

  1. #微信支付配置
  2. wx:
  3. pay:
  4. #应用id(小程序id)
  5. appId: wx6b5xxxxxxxxxxxx
  6. #商户号
  7. merchantId: 1xxxxxxxxx
  8. #商户API私钥
  9. privateKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  10. #商户证书序列号
  11. merchantSerialNumber: 315DDXXXXXXXXXXXXXXXXXXXXXXXXXXX
  12. #商户APIv3密钥
  13. apiV3Key: XXXXXXXXXXXXXXXXXXXXXXXXXX
  14. #支付通知地址
  15. payNotifyUrl: https://xxx.xxxx.xxx.xxx/xx/xxxx/xxxx/openapi/wx/payNotify
  16. #退款通知地址
  17. refundNotifyUrl: https://xxx.xxx.xxx.xxx/xxxx/xxxx/xxxx/openapi/wx/refundNotify

三、代码开发

1、配置类

  1. import lombok.Data;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. import org.springframework.stereotype.Component;
  4. /**
  5. * @author caozhen
  6. * @ClassName WxPayConfig
  7. * @description: 微信支付配置类
  8. * @date 2024年01月03日
  9. * @version: 1.0
  10. */
  11. @Data
  12. @Component
  13. @ConfigurationProperties(prefix = "wx.pay")
  14. public class WxPayConfig {
  15. //APPID
  16. private String appId;
  17. //mchid
  18. private String merchantId;
  19. //商户API私钥
  20. private String privateKey;
  21. //商户证书序列号
  22. private String merchantSerialNumber;
  23. //商户APIv3密钥
  24. private String apiV3Key;
  25. //支付通知地址
  26. private String payNotifyUrl;
  27. //退款通知地址
  28. private String refundNotifyUrl;
  29. }

2、初始化商户配置

  1. import com.wechat.pay.java.core.RSAAutoCertificateConfig;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import javax.annotation.Resource;
  5. /**
  6. * @author caozhen
  7. * @ClassName WxPayAutoCertificateConfig
  8. * @description: 微信支付证书自动更新配置
  9. * @date 2024年01月03日
  10. * @version: 1.0
  11. */
  12. @Configuration
  13. public class WxPayAutoCertificateConfig {
  14. @Resource
  15. private WxPayConfig wxPayConfig;
  16. /**
  17. * 初始化商户配置
  18. * @return
  19. */
  20. @Bean
  21. public RSAAutoCertificateConfig rsaAutoCertificateConfig() {
  22. RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
  23. .merchantId(wxPayConfig.getMerchantId())
  24. .privateKey(wxPayConfig.getPrivateKey())
  25. .merchantSerialNumber(wxPayConfig.getMerchantSerialNumber())
  26. .apiV3Key(wxPayConfig.getApiV3Key())
  27. .build();
  28. return config;
  29. }
  30. }

3、JSAPI微信预下单

3.1、先建个WxPayService服务类

  1. import com.alibaba.fastjson.JSONObject;
  2. import com.baomidou.mybatisplus.mapper.EntityWrapper;
  3. import com.baomidou.mybatisplus.mapper.Wrapper;
  4. import com.hvit.user.exception.DataAccessException;
  5. import com.hvit.user.util.DateUtils;
  6. import com.hvit.user.util.R;
  7. import com.hvit.user.yst.entity.WxOrderEntity;
  8. import com.hvit.user.yst.entity.WxPayLogEntity;
  9. import com.hvit.user.yst.request.CreateOrderReq;
  10. import com.hvit.user.yst.request.QueryOrderReq;
  11. import com.hvit.user.yst.request.WxNotifyReq;
  12. import com.hvit.user.yst.service.WKShoppingMallService;
  13. import com.hvit.user.yst.service.data.WxOrderDataService;
  14. import com.hvit.user.yst.service.data.WxPayLogDataService;
  15. import com.wechat.pay.java.core.RSAAutoCertificateConfig;
  16. import com.wechat.pay.java.core.exception.HttpException;
  17. import com.wechat.pay.java.core.exception.MalformedMessageException;
  18. import com.wechat.pay.java.core.exception.ServiceException;
  19. import com.wechat.pay.java.core.notification.NotificationParser;
  20. import com.wechat.pay.java.core.notification.RequestParam;
  21. import com.wechat.pay.java.service.payments.jsapi.*;
  22. import com.wechat.pay.java.service.payments.jsapi.model.*;
  23. import com.wechat.pay.java.service.payments.jsapi.model.Amount;
  24. import com.wechat.pay.java.service.payments.model.Transaction;
  25. import com.wechat.pay.java.service.refund.RefundService;
  26. import com.wechat.pay.java.service.refund.model.*;
  27. import io.swagger.annotations.ApiModelProperty;
  28. import io.swagger.models.auth.In;
  29. import lombok.extern.slf4j.Slf4j;
  30. import org.apache.commons.lang3.StringUtils;
  31. import org.springframework.beans.factory.annotation.Autowired;
  32. import org.springframework.scheduling.annotation.Async;
  33. import org.springframework.stereotype.Service;
  34. import org.springframework.transaction.annotation.Transactional;
  35. import javax.annotation.Resource;
  36. import javax.servlet.ServletInputStream;
  37. import javax.servlet.http.HttpServletRequest;
  38. import java.io.BufferedReader;
  39. import java.io.IOException;
  40. import java.io.InputStreamReader;
  41. import java.math.BigDecimal;
  42. import java.util.Date;
  43. import java.util.HashMap;
  44. import java.util.LinkedHashMap;
  45. import java.util.Map;
  46. /**
  47. * @author caozhen
  48. * @ClassName WxPayService
  49. * @description: 微信支付
  50. * @date 2024年01月03日
  51. * @version: 1.0
  52. */
  53. @Slf4j
  54. @Service
  55. public class WxPayService {
  56. @Resource
  57. private WxPayConfig wxPayConfig;
  58. @Autowired
  59. private RSAAutoCertificateConfig rsaAutoCertificateConfig;
  60. @Autowired
  61. private WxOrderDataService wxOrderDataService;
  62. @Autowired
  63. private WxPayLogDataService wxPayLogDataService;
  64. /***
  65. * 预支付订单
  66. * @param req
  67. * @return
  68. */
  69. public R createOrder(CreateOrderReq req) throws Exception {
  70. if (req == null) {
  71. return R.error("创建订单失败,缺少参数!");
  72. }
  73. //先解密
  74. String orderNo = req.getOutTradeNo();
  75. Integer totalFee = req.getTotal();
  76. //创建初始化订单
  77. //todo,创建订单这边你们自己来(后面我会放出表结构)
  78. //请求微信支付相关配置
  79. JsapiServiceExtension service =
  80. new JsapiServiceExtension.Builder()
  81. .config(rsaAutoCertificateConfig)
  82. .signType("RSA") // 不填默认为RSA
  83. .build();
  84. PrepayWithRequestPaymentResponse response = new PrepayWithRequestPaymentResponse();
  85. try {
  86. PrepayRequest request = new PrepayRequest();
  87. request.setAppid(wxPayConfig.getAppId());
  88. request.setMchid(wxPayConfig.getMerchantId());
  89. request.setDescription(description);
  90. request.setOutTradeNo(orderNo);
  91. request.setNotifyUrl(wxPayConfig.getPayNotifyUrl());
  92. Amount amount = new Amount();
  93. //amount.setTotal(totalFee.multiply(new BigDecimal("100")).intValue());
  94. amount.setTotal(totalFee);
  95. request.setAmount(amount);
  96. Payer payer = new Payer();
  97. payer.setOpenid(req.getWxOpenId());
  98. request.setPayer(payer);
  99. log.info("请求预支付下单,请求参数:{}", JSONObject.toJSONString(request));
  100. // 调用预下单接口
  101. response = service.prepayWithRequestPayment(request);
  102. log.info("订单【{}】发起预支付成功,返回信息:{}", orderNo, response);
  103. } catch (HttpException e) { // 发送HTTP请求失败
  104. log.error("微信下单发送HTTP请求失败,错误信息:{}", e.getHttpRequest());
  105. return R.error("下单失败");
  106. } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
  107. log.error("微信下单服务状态错误,错误信息:{}", e.getErrorMessage());
  108. return R.error("下单失败");
  109. } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
  110. log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
  111. return R.error("下单失败");
  112. }
  113. return R.ok().put("data", response);
  114. }
  115. }

3.1、R实体类

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. /**
  4. *
  5. * @author 曹震
  6. * @date 2024-1-03
  7. */
  8. public class R extends HashMap<String, Object> {
  9. private static final long serialVersionUID = 1L;
  10. public R() {
  11. put("code", 0);
  12. }
  13. public R(Integer code) {
  14. put("code", code);
  15. put("data", new HashMap<String, Object>());
  16. }
  17. public R(Integer code, String msg) {
  18. put("code", code);
  19. put("msg", msg);
  20. put("data", new HashMap<String, Object>());
  21. }
  22. public static R error() {
  23. return error(500, "未知异常,请联系管理员");
  24. }
  25. public static R errorDebug(String message) {
  26. return error(500, "未知异常 " + message + ",请联系管理员");
  27. }
  28. public static R error(String msg) {
  29. return error(500, msg);
  30. }
  31. public static R error(int code, String msg) {
  32. R r = new R();
  33. r.put("code", code);
  34. r.put("msg", msg);
  35. return r;
  36. }
  37. public R errorInfo(String msg) {
  38. this.put("errorMsg", msg);
  39. return this;
  40. }
  41. public static R ok(String msg) {
  42. R r = new R();
  43. r.put("msg", msg);
  44. r.put("data", new HashMap<String, Object>());
  45. return r;
  46. }
  47. public static R ok(Map<String, Object> map) {
  48. R r = new R();
  49. r.putAll(map);
  50. r.put("data", new HashMap<String, Object>());
  51. return r;
  52. }
  53. public static R ok() {
  54. return new R().put("msg", "success").put("data", new HashMap<String, Object>());
  55. }
  56. public static R ok(Integer size) {
  57. return new R().put("data", new HashMap<String, Object>((int)Math.round(size / 0.75)));
  58. }
  59. @Override
  60. public R put(String key, Object value) {
  61. super.put(key, value);
  62. return this;
  63. }
  64. /**
  65. * 添加返回结果数据
  66. *
  67. * @param key
  68. * @param value
  69. * @return
  70. */
  71. public R putData(String key, Object value) {
  72. Map<String, Object> map = (HashMap<String, Object>)this.get("data");
  73. map.put(key, value);
  74. return this;
  75. }
  76. }

3.2、CreateOrderReq类

  1. import io.swagger.annotations.ApiModelProperty;
  2. import lombok.Data;
  3. /**
  4. * @author caozhen
  5. * @ClassName CreateOrderReq
  6. * @description: TODO
  7. * @date 2024年01月03日
  8. * @version: 1.0
  9. */
  10. @Data
  11. public class CreateOrderReq {
  12. @ApiModelProperty(name = "description", value = "商品描述")
  13. private String description;
  14. @ApiModelProperty(name = "wxOpenId", value = "用户小程序openid")
  15. private String wxOpenId;
  16. @ApiModelProperty(name = "outTradeNo", value = "商户订单号")
  17. private String outTradeNo;
  18. @ApiModelProperty(name = "totalFee", value = "支付金额,单位:分")
  19. private Long totalFee;

4、微信支付回调通知 

  1. /***
  2. * 微信支付回调通知
  3. * @param request
  4. * @return
  5. * @throws IOException
  6. */
  7. @Transactional
  8. public synchronized String payNotify(HttpServletRequest request) throws Exception {
  9. log.info("------收到支付通知------");
  10. // 请求头Wechatpay-Signature
  11. String signature = request.getHeader("Wechatpay-Signature");
  12. // 请求头Wechatpay-nonce
  13. String nonce = request.getHeader("Wechatpay-Nonce");
  14. // 请求头Wechatpay-Timestamp
  15. String timestamp = request.getHeader("Wechatpay-Timestamp");
  16. // 微信支付证书序列号
  17. String serial = request.getHeader("Wechatpay-Serial");
  18. // 签名方式
  19. String signType = request.getHeader("Wechatpay-Signature-Type");
  20. // 构造 RequestParam
  21. RequestParam requestParam = new RequestParam.Builder()
  22. .serialNumber(serial)
  23. .nonce(nonce)
  24. .signature(signature)
  25. .timestamp(timestamp)
  26. .signType(signType)
  27. .body(HttpServletUtils.getRequestBody(request))
  28. .build();
  29. // 初始化 NotificationParser
  30. NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
  31. // 以支付通知回调为例,验签、解密并转换成 Transaction
  32. log.info("验签参数:{}", requestParam);
  33. Transaction transaction = parser.parse(requestParam, Transaction.class);
  34. log.info("验签成功!-支付回调结果:{}", transaction.toString());
  35. Map<String, String> returnMap = new HashMap<>(2);
  36. returnMap.put("code", "FAIL");
  37. returnMap.put("message", "失败");
  38. //修改订单前,建议主动请求微信查询订单是否支付成功,防止恶意post
  39. Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
  40. wrapper.eq("out_trade_no", transaction.getOutTradeNo());
  41. //wrapper.eq("transaction_id", transaction.getTransactionId());
  42. WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
  43. if (wxOrderEntity != null) {
  44. if (wxOrderEntity.getPayStatus() == 1) {
  45. //此时已经是支付成功,不在处理订单信息
  46. returnMap.put("code", "SUCCESS");
  47. returnMap.put("message", "成功");
  48. return JSONObject.toJSONString(returnMap);
  49. }
  50. }
  51. if (Transaction.TradeStateEnum.SUCCESS != transaction.getTradeState()) {
  52. log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", transaction.getOutTradeNo(), transaction.getTransactionId());
  53. if (wxOrderEntity != null) {
  54. wxOrderEntity.setUpdateTime(new Date());
  55. wxOrderEntity.setPayStatus(2);
  56. wxOrderEntity.setPayNonce(nonce);
  57. wxOrderEntity.setTransactionId(transaction.getTransactionId());
  58. //修改订单信息
  59. wxOrderDataService.updateById(wxOrderEntity);
  60. }
  61. return JSONObject.toJSONString(returnMap);
  62. }
  63. if (wxOrderEntity != null) {
  64. wxOrderEntity.setUpdateTime(new Date());
  65. wxOrderEntity.setPayTime(DateUtils.stringToDateTime(transaction.getSuccessTime()));
  66. wxOrderEntity.setPayDate(DateUtils.stringToDateTime(transaction.getSuccessTime()));
  67. wxOrderEntity.setPayStatus(1);
  68. wxOrderEntity.setPayNonce(nonce);
  69. wxOrderEntity.setTransactionId(transaction.getTransactionId());
  70. //修改订单信息
  71. wxOrderDataService.updateById(wxOrderEntity);
  72. //同时处理支付记录
  73. Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
  74. wrapper.eq("out_trade_no", transaction.getOutTradeNo());
  75. wrapper.eq("pay_status", 1);//支付
  76. WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
  77. if (wxPayLogEntity == null) {
  78. wxPayLogEntity = new WxPayLogEntity();
  79. wxPayLogEntity.setCreateTime(new Date());
  80. wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
  81. wxPayLogEntity.setPayStatus(1);
  82. wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
  83. wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());
  84. wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
  85. wxPayLogDataService.insert(wxPayLogEntity);
  86. }
  87. }
  88. returnMap.put("code", "SUCCESS");
  89. returnMap.put("message", "成功");
  90. return JSONObject.toJSONString(returnMap);
  91. }

5、根据商户订单号查询订单(out_trade_no)

  1. /***
  2. * 根据商户订单号查询订单 outTradeNo
  3. * @param req
  4. * @return
  5. */
  6. @Transactional
  7. public R queryOrderByOrderNo(QueryOrderReq req) {
  8. QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
  9. queryRequest.setMchid(wxPayConfig.getMerchantId());
  10. queryRequest.setOutTradeNo(req.getOrderNo());
  11. try {
  12. JsapiServiceExtension service =
  13. new JsapiServiceExtension.Builder()
  14. .config(rsaAutoCertificateConfig)
  15. .signType("RSA") // 不填默认为RSA
  16. .build();
  17. Transaction result = service.queryOrderByOutTradeNo(queryRequest);
  18. LinkedHashMap retmap = new LinkedHashMap();
  19. //支付成功
  20. if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {
  21. log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());
  22. retmap.put("out_trade_no", result.getOutTradeNo());
  23. retmap.put("transaction_id", result.getTransactionId());
  24. retmap.put("success", true);
  25. retmap.put("msg", "支付成功!");
  26. retmap.put("success_time", DateUtils.getDateTimeString(DateUtils.stringToDateTime(result.getSuccessTime())));
  27. //主动查询
  28. Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
  29. wrapper.eq("out_trade_no", req.getOrderNo());
  30. WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
  31. if (wxOrderEntity != null) {
  32. if (wxOrderEntity.getPayStatus() != 1) {
  33. wxOrderEntity.setPayStatus(1);
  34. wxOrderEntity.setTransactionId(result.getTransactionId());
  35. wxOrderEntity.setPayDate(DateUtils.stringToDateTime(result.getSuccessTime()));
  36. wxOrderEntity.setPayTime(DateUtils.stringToDateTime(result.getSuccessTime()));
  37. wxOrderEntity.setUpdateTime(new Date());
  38. wxOrderDataService.updateById(wxOrderEntity);
  39. //同时处理支付记录
  40. Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
  41. wrapper.eq("out_trade_no", req.getOrderNo());
  42. WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
  43. if (wxPayLogEntity == null) {
  44. wxPayLogEntity = new WxPayLogEntity();
  45. wxPayLogEntity.setCreateTime(new Date());
  46. wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
  47. wxPayLogEntity.setPayStatus(1);
  48. wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
  49. wxPayLogEntity.setTransactionId(result.getTransactionId());
  50. wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
  51. wxPayLogDataService.insert(wxPayLogEntity);
  52. }
  53. }
  54. }
  55. } else {
  56. log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());
  57. retmap.put("out_trade_no", result.getOutTradeNo());
  58. retmap.put("transaction_id", result.getTransactionId());
  59. retmap.put("success", false);
  60. retmap.put("msg", "支付失败!");
  61. retmap.put("success_time", null);
  62. }
  63. return R.ok().put("data", retmap);
  64. } catch (ServiceException e) {
  65. log.error("订单查询失败,返回码:{},返回信息:{}", e.getErrorCode(), e.getErrorMessage());
  66. return R.error("订单查询失败!");
  67. }
  68. }

5.1  QueryOrderReq类

  1. mport io.swagger.annotations.ApiModelProperty;
  2. import lombok.Data;
  3. /**
  4. * @author caozhen
  5. * @ClassName QueryOrderReq
  6. * @description: 支付查询
  7. * @date 2024年01月04日
  8. * @version: 1.0
  9. */
  10. @Data
  11. public class QueryOrderReq {
  12. @ApiModelProperty(name = "paymentNo", value = "微信支付订单号,同:transaction_id")
  13. private String paymentNo;
  14. @ApiModelProperty(name = "orderNo", value = "商户订单号,同:out_trade_no")
  15. private String orderNo;
  16. }

6、根据支付订单号查询订单 (transaction_id)

  1. /***
  2. * 根据支付订单号查询订单 paymentNo
  3. * @param req
  4. * @return
  5. */
  6. @Transactional
  7. public R queryOrderByPaymentNo(QueryOrderReq req) {
  8. QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
  9. queryRequest.setMchid(wxPayConfig.getMerchantId());
  10. queryRequest.setTransactionId(req.getPaymentNo());
  11. try {
  12. JsapiServiceExtension service =
  13. new JsapiServiceExtension.Builder()
  14. .config(rsaAutoCertificateConfig)
  15. .signType("RSA") // 不填默认为RSA
  16. .build();
  17. Transaction result = service.queryOrderById(queryRequest);
  18. LinkedHashMap map = new LinkedHashMap();
  19. //支付成功
  20. if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {
  21. log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());
  22. map.put("out_trade_no", result.getOutTradeNo());
  23. map.put("transaction_id", result.getTransactionId());
  24. map.put("success", true);
  25. map.put("msg", "支付成功!");
  26. map.put("success_time", DateUtils.getDateTimeString(DateUtils.stringToDateTime(result.getSuccessTime())));
  27. //主动查询
  28. Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
  29. wrapper.eq("transaction_id", req.getPaymentNo());
  30. WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
  31. if (wxOrderEntity != null) {
  32. if (wxOrderEntity.getPayStatus() != 1) {
  33. wxOrderEntity.setPayStatus(1);
  34. wxOrderEntity.setPayDate(DateUtils.stringToDateTime(result.getSuccessTime()));
  35. wxOrderEntity.setPayTime(DateUtils.stringToDateTime(result.getSuccessTime()));
  36. wxOrderEntity.setUpdateTime(new Date());
  37. wxOrderDataService.updateById(wxOrderEntity);
  38. //同时处理支付记录
  39. Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
  40. wrapper.eq("transaction_id", req.getPaymentNo());
  41. WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
  42. if (wxPayLogEntity == null) {
  43. wxPayLogEntity = new WxPayLogEntity();
  44. wxPayLogEntity.setCreateTime(new Date());
  45. wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
  46. wxPayLogEntity.setPayStatus(1);
  47. wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
  48. wxPayLogEntity.setTransactionId(result.getTransactionId());
  49. wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
  50. wxPayLogDataService.insert(wxPayLogEntity);
  51. }
  52. }
  53. }
  54. } else {
  55. log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());
  56. map.put("out_trade_no", result.getOutTradeNo());
  57. map.put("transaction_id", result.getTransactionId());
  58. map.put("success", false);
  59. map.put("msg", "支付失败!");
  60. map.put("success_time", null);
  61. }
  62. return R.ok().put("data", map);
  63. } catch (ServiceException e) {
  64. log.error("订单查询失败,返回码:{},返回信息:{}", e.getErrorCode(), e.getErrorMessage());
  65. return R.error("订单查询失败!");
  66. }
  67. }

7、微信申请退款

  1. /***
  2. * 微信申请退款
  3. * @param outTradeNo 商户订单号
  4. * @param totalAmount
  5. * @return
  6. */
  7. public R createRefund(String outTradeNo, Long totalAmount) {
  8. //返回参数
  9. LinkedHashMap map = new LinkedHashMap();
  10. map.put("out_trade_no", outTradeNo);
  11. map.put("success", false);
  12. map.put("msg", "正在申请退款中!");
  13. String outRefundNo = "REFUND_" + outTradeNo;
  14. map.put("out_refund_no", outRefundNo);
  15. //申请退款订单,需要变更订单记录
  16. Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
  17. wrapper.eq("out_trade_no", outTradeNo);
  18. WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
  19. if (wxOrderEntity == null) {
  20. return R.error("订单不存在,申请退款不存在!");
  21. }
  22. wxOrderEntity.setPayStatus(4);//退款中
  23. wxOrderEntity.setUpdateTime(new Date());
  24. wxOrderDataService.updateById(wxOrderEntity);
  25. try {
  26. // 构建退款service
  27. RefundService service = new RefundService.Builder()
  28. .config(rsaAutoCertificateConfig)
  29. .build();
  30. CreateRequest request = new CreateRequest();
  31. // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
  32. request.setOutTradeNo(outTradeNo);
  33. request.setOutRefundNo(outRefundNo);
  34. AmountReq amount = new AmountReq();
  35. amount.setTotal(totalAmount);
  36. amount.setRefund(totalAmount);
  37. amount.setCurrency("CNY");
  38. request.setAmount(amount);
  39. request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());
  40. //接收退款返回参数
  41. Refund refund = service.create(request);
  42. log.info("退款返回信息:{}", refund);
  43. if (refund.getStatus().equals(Status.SUCCESS)) {
  44. map.put("success", true);
  45. map.put("msg", "退款成功!");
  46. //说明退款成功,开始接下来的业务操作
  47. //主动查询
  48. Wrapper againWrapper = new EntityWrapper<WxOrderEntity>();
  49. againWrapper.eq("out_trade_no", outTradeNo);
  50. WxOrderEntity orderEntity = wxOrderDataService.selectOne(againWrapper);
  51. if (orderEntity != null) {
  52. orderEntity.setPayStatus(3);//退款成功
  53. orderEntity.setUpdateTime(new Date());
  54. wxOrderDataService.updateById(orderEntity);
  55. //同时处理退款记录
  56. Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
  57. payWrapper.eq("out_trade_no", outTradeNo);
  58. payWrapper.eq("pay_status", 2);//退款
  59. WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
  60. if (wxPayLogEntity == null) {
  61. wxPayLogEntity = new WxPayLogEntity();
  62. wxPayLogEntity.setCreateTime(new Date());
  63. wxPayLogEntity.setOutTradeNo(outTradeNo);
  64. wxPayLogEntity.setPayStatus(2);
  65. wxPayLogEntity.setTotalFee(totalAmount.intValue());
  66. wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());
  67. wxPayLogEntity.setOutRefundNo(outRefundNo);
  68. wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
  69. wxPayLogDataService.insert(wxPayLogEntity);
  70. }
  71. }
  72. }
  73. } catch (ServiceException e) {
  74. log.error("退款失败!,错误信息:{}", e.getMessage());
  75. return R.error("退款失败!");
  76. } catch (Exception e) {
  77. log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
  78. return R.error("退款失败!");
  79. }
  80. return R.ok().put("data", map);
  81. }

8、退款回调通知 

待续......有需要的再联系我!

四、mysql表结构

  1. SET NAMES utf8mb4;
  2. SET FOREIGN_KEY_CHECKS = 0;
  3. -- ----------------------------
  4. -- Table structure for t_wx_order
  5. -- ----------------------------
  6. DROP TABLE IF EXISTS `t_wx_order`;
  7. CREATE TABLE `t_wx_order` (
  8. `uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  9. `trade_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '商品名称',
  10. `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '订单描述',
  11. `out_trade_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '(商户)订单流水号',
  12. `transaction_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '微信订单号',
  13. `total_fee` int(10) NULL DEFAULT NULL COMMENT '订单金额(单位:分)',
  14. `pay_nonce` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '支付成功后的随机32位字符串',
  15. `pay_time` datetime NULL DEFAULT NULL COMMENT '支付时间',
  16. `pay_date` date NULL DEFAULT NULL COMMENT '支付日期',
  17. `pay_status` int(3) NULL DEFAULT 0 COMMENT '0:待支付,1:支付成功,2:支付失败,3:退款成功,4:正在退款中,5:未知',
  18. `wx_open_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '微信小程序openid',
  19. `status` int(2) NULL DEFAULT 0 COMMENT '0:未删除,1:已删除',
  20. `create_time` datetime NULL DEFAULT NULL COMMENT '创建订单时间',
  21. `update_time` datetime NULL DEFAULT NULL COMMENT '修改订单时间',
  22. PRIMARY KEY (`uuid`) USING BTREE
  23. ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '微信商品订单表' ROW_FORMAT = Dynamic;
  24. -- ----------------------------
  25. -- Table structure for t_wx_pay_log
  26. -- ----------------------------
  27. DROP TABLE IF EXISTS `t_wx_pay_log`;
  28. CREATE TABLE `t_wx_pay_log` (
  29. `uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  30. `wx_open_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '微信用户openid',
  31. `out_trade_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '(商户)订单流水号',
  32. `out_refund_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '(商户)退款流水号',
  33. `transaction_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '微信订单号',
  34. `total_fee` int(10) NULL DEFAULT NULL COMMENT '支付金额',
  35. `pay_status` int(2) NULL DEFAULT NULL COMMENT '1:支付,2:退款',
  36. `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  37. PRIMARY KEY (`uuid`) USING BTREE
  38. ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '微信用户支付记录表' ROW_FORMAT = Dynamic;
  39. SET FOREIGN_KEY_CHECKS = 1;

五、controller类

退款回调通知,和controller就不写了,如果需要,联系我即可!

哎呀呀呀,缺少了一个类,代码如下:

  1. import javax.servlet.ServletInputStream;
  2. import javax.servlet.http.HttpServletRequest;
  3. import java.io.BufferedReader;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. /**
  7. * @author caozhen
  8. * @ClassName HttpServletUtils
  9. * @description: TODO
  10. * @date 2024年01月04日
  11. * @version: 1.0
  12. */
  13. public class HttpServletUtils {
  14. /**
  15. * 获取请求体
  16. *
  17. * @param request
  18. * @return
  19. * @throws IOException
  20. */
  21. public static String getRequestBody(HttpServletRequest request) throws IOException {
  22. ServletInputStream stream = null;
  23. BufferedReader reader = null;
  24. StringBuffer sb = new StringBuffer();
  25. try {
  26. stream = request.getInputStream();
  27. // 获取响应
  28. reader = new BufferedReader(new InputStreamReader(stream));
  29. String line;
  30. while ((line = reader.readLine()) != null) {
  31. sb.append(line);
  32. }
  33. } catch (IOException e) {
  34. throw new IOException("读取返回支付接口数据流出现异常!");
  35. } finally {
  36. reader.close();
  37. }
  38. return sb.toString();
  39. }
  40. }

如果你在微信支付回调通知中出现 “签名错误”,并且你是windows服务器,请在HttpServletUtils 类中,将reader = new BufferedReader(new InputStreamReader(stream));   替换成:reader = new BufferedReader(new InputStreamReader(stream,"UTF-8"));

替换完整代码:

  1. import javax.servlet.ServletInputStream;
  2. import javax.servlet.http.HttpServletRequest;
  3. import java.io.BufferedReader;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. /**
  7. * @author caozhen
  8. * @ClassName HttpServletUtils
  9. * @description: TODO
  10. * @date 2024年01月04日
  11. * @version: 1.0
  12. */
  13. public class HttpServletUtils {
  14. /**
  15. * 获取请求体
  16. *
  17. * @param request
  18. * @return
  19. * @throws IOException
  20. */
  21. public static String getRequestBody(HttpServletRequest request) throws IOException {
  22. ServletInputStream stream = null;
  23. BufferedReader reader = null;
  24. StringBuffer sb = new StringBuffer();
  25. try {
  26. stream = request.getInputStream();
  27. // 获取响应
  28. reader = new BufferedReader(new InputStreamReader(stream,"UTF-8"));
  29. String line;
  30. while ((line = reader.readLine()) != null) {
  31. sb.append(line);
  32. }
  33. } catch (IOException e) {
  34. throw new IOException("读取返回支付接口数据流出现异常!");
  35. } finally {
  36. reader.close();
  37. }
  38. return sb.toString();
  39. }
  40. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/832997
推荐阅读
相关标签
  

闽ICP备14008679号