当前位置:   article > 正文

Java接入微信小程序支付、退款、发货通知_微信小程序订单发货接入

微信小程序订单发货接入

一,准备工作

申请应用号:appid

申请商户号:mchid

设置APIV3密钥:apiV3Key

下载并配置商户证书,商户证书序列号:mchSerialNo ;商户API私钥路径:privateKey

详情流程可见微信支付官网

二,小程序支付流程

 需要后端完成的一共有三个接口

1,拿到订单参数后,向微信发送请求支付消息,把拿到的参数返回给前端,用于用户付款

2,前端输入密码后,微信会异步回调一个接口,成功扣款后做对应业务处理

3,查询支付结果返回给前端

 三,设置常量和基本配置信息

1,导入依赖
  1. <!--微信小程序支付-->
  2. <dependency>
  3. <groupId>com.github.wechatpay-apiv3</groupId>
  4. <artifactId>wechatpay-apache-httpclient</artifactId>
  5. <version>0.4.9</version>
  6. </dependency>
2,加载配置信息到yml文件中
  1. # 微信
  2. wx:
  3. # 小程序支付
  4. pay:
  5. # 应用号
  6. appId: ********
  7. # 商户号
  8. mchId: ********
  9. # 商户APIV3密钥(32位)
  10. apiV3Key: ********************************
  11. # 商户证书序列号
  12. mchSerialNo: ****************
  13. # 支付成功回调 url 需要公网可访问
  14. notifyUrl: http://改成自己的回调地址/system/order/wechatPayCallback
  15. # 退款成功回调 url 需要公网可访问
  16. refundNotifyUrl: http://改成自己的回调地址/system/order/wechatRefundBack
  17. # 商户API私钥路径 【证书路径】
  18. privateKey: "**********"
3,用工具类来保存配置信息WeChatToolConfig 
  1. @Data
  2. @Component
  3. public class WeChatToolConfig {
  4. /**
  5. * 应用id
  6. */
  7. @Value("${wx.pay.appId}")
  8. private String appId;
  9. /**
  10. * 商户id
  11. */
  12. @Value("${wx.pay.mchId}")
  13. private String mchId;
  14. /**
  15. * 商户APIV3密钥
  16. */
  17. @Value("${wx.pay.apiV3Key}")
  18. private String apiV3Key;
  19. /**
  20. * 商户证书序列号
  21. */
  22. @Value("${wx.pay.mchSerialNo}")
  23. private String mchSerialNo;
  24. /**
  25. * 商户私钥
  26. */
  27. @Value("${wx.pay.privateKey}")
  28. private String privateKey;
  29. /**
  30. * 支付成功回调url
  31. */
  32. @Value("${wx.pay.notifyUrl}")
  33. private String notifyUrl;
  34. /**
  35. * 退款成功回调url
  36. */
  37. @Value("${wx.pay.refundNotifyUrl}")
  38. private String refundNotifyUrl;
  39. }
4,定义一个枚举来保存微信支付API WxApiTypeEnum 
  1. public enum WxApiTypeEnum {
  2. /**
  3. * 小程序 下单API
  4. */
  5. CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"),
  6. /**
  7. * 申请退款API 通过 outTradeNo 商户订单号 退单
  8. */
  9. REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"),
  10. /**
  11. * 查询支付订单API ONE{}=>outTradeNo – 商户订单号 系统生 TOW{}=>mchId商户的商户号,由微信支付生成并下发。
  12. */
  13. QUERY_CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{}?mchid={}"),
  14. /**
  15. * 查询退款订单API {}=>outRefundNo 商户退款单号
  16. */
  17. QUERY_REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{}"),
  18. /**
  19. * 关闭订单API {}=>outTradeNo 商户订单号
  20. */
  21. CLOSE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{}/close"),
  22. /**
  23. * 货物录入
  24. */
  25. GOOD_ENTERING("https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token={}"),
  26. /**
  27. * 接口调用凭证
  28. */
  29. API_VOUCHER("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}");
  30. private final String value;
  31. WxApiTypeEnum(String value) {
  32. this.value = value;
  33. }
  34. public String getValue() {
  35. return value;
  36. }
  37. }
5,定义一个类保存HTTP请求头常量 WechatPayHttpHeaders 
  1. public class WechatPayHttpHeaders {
  2. // 请求头配置
  3. public static final String ACCEPT = "Accept";
  4. public static final String CONTENT_TYPE = "Content-type";
  5. public static final String APPLICATION_JSON = "application/json";
  6. public static final String APPLICATION_JSON_UTF = "application/json; charset=utf-8";
  7. /**
  8. * 微信回调参数==>微信序列号
  9. */
  10. public static final String WECHATPAY_SERIAL = "Wechatpay-Serial";
  11. /**
  12. * 微信回调参数==>应答随机串
  13. */
  14. public static final String WECHATPAY_NONCE = "Wechatpay-Nonce";
  15. /**
  16. * 微信回调参数==>应答时间戳
  17. */
  18. public static final String WECHATPAY_TIMESTAMP = "Wechatpay-Timestamp";
  19. /**
  20. * 微信回调参数==>应答签名
  21. */
  22. public static final String WECHATPAY_SIGNATURE = "Wechatpay-Signature";
  23. private WechatPayHttpHeaders() {
  24. // Don't allow instantiation
  25. }
  26. }
6,微信小程序支付工具类
  1. public class WeChatUtil {
  2. private static final Logger log = LoggerFactory.getLogger(WeChatUtil.class);
  3. /**
  4. * 签名生成 计算签名
  5. *
  6. * @param message 签名体
  7. * @param privateKey 商户私钥
  8. * @return String
  9. */
  10. public static String sign(byte[] message, PrivateKey privateKey) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
  11. Signature sign = Signature.getInstance("SHA256withRSA");
  12. sign.initSign(privateKey);
  13. sign.update(message);
  14. return Base64.getEncoder().encodeToString(sign.sign());
  15. }
  16. /**
  17. * 构造HttpClient 实现 微信申请接口 调用功能
  18. *
  19. * @param verifier 微信验签器
  20. * @return CloseableHttpClient
  21. */
  22. public static CloseableHttpClient getHttpClient(WeChatToolConfig config, Verifier verifier) {
  23. PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(config.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
  24. // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
  25. WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
  26. .withMerchant(config.getMchId(), config.getMchSerialNo(), merchantPrivateKey)
  27. .withValidator(new WechatPay2Validator(verifier));
  28. return builder.build();
  29. }
  30. /**
  31. * 构造HttpClient 实现 微信申请接口 调用功能 不用微信签名认证 账单申请中可用到
  32. *
  33. * @param verifier 微信验签器
  34. * @return CloseableHttpClient
  35. */
  36. public static CloseableHttpClient getHttpClientNoSign(WeChatToolConfig config, Verifier verifier) {
  37. PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(config.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
  38. // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
  39. WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
  40. .withMerchant(config.getMchId(), config.getMchSerialNo(), merchantPrivateKey)
  41. .withValidator(new WechatPay2Validator(verifier))
  42. .withValidator(response -> true);
  43. return builder.build();
  44. }
  45. /**
  46. * 获取验证功能
  47. *
  48. * @return Verifier 微信验签器
  49. */
  50. public static Verifier getVerifier(WeChatToolConfig config) {
  51. try {
  52. PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(config.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
  53. // 定时更新平台证书功能
  54. // 获取证书管理器实例
  55. CertificatesManager certificatesManager = CertificatesManager.getInstance();
  56. // 向证书管理器增加需要自动更新平台证书的商户信息
  57. certificatesManager.putMerchant(config.getMchId(), new WechatPay2Credentials(config.getMchId(),
  58. new PrivateKeySigner(config.getMchSerialNo(), merchantPrivateKey)), config.getApiV3Key().getBytes(StandardCharsets.UTF_8));
  59. // 从证书管理器中获取verifier=>验签器
  60. return certificatesManager.getVerifier(config.getMchId());
  61. } catch (Exception e) {
  62. log.warn("验证出错");
  63. throw new CustomException("微信证书出错 联系客服");
  64. }
  65. }
  66. /**
  67. * 回调验证
  68. *
  69. * @param request 微信回调请求
  70. * @return String
  71. */
  72. public static Notification verifyBack(HttpServletRequest request, WeChatToolConfig config) throws IOException, ValidationException, ParseException {
  73. // 应答报文主体
  74. BufferedReader br = request.getReader();
  75. String str;
  76. StringBuilder builder = new StringBuilder();
  77. while ((str = br.readLine()) != null) {
  78. builder.append(str);
  79. }
  80. // 构建request,传入必要参数
  81. // 参数 1.微信序列号 2.应答随机串 3.应答时间戳 4.应答签名 5.应答报文主体
  82. NotificationRequest notificationRequest = new NotificationRequest.Builder()
  83. .withSerialNumber(request.getHeader(WechatPayHttpHeaders.WECHATPAY_SERIAL))
  84. .withNonce(request.getHeader(WechatPayHttpHeaders.WECHATPAY_NONCE))
  85. .withTimestamp(request.getHeader(WechatPayHttpHeaders.WECHATPAY_TIMESTAMP))
  86. .withSignature(request.getHeader(WechatPayHttpHeaders.WECHATPAY_SIGNATURE))
  87. .withBody(builder.toString())
  88. .build();
  89. NotificationHandler handler = new NotificationHandler(WeChatUtil.getVerifier(config), config.getApiV3Key().getBytes(StandardCharsets.UTF_8));
  90. // 验签和解析请求体
  91. log.info("验签和解析请求体==============================开始验证==============================");
  92. return handler.parse(notificationRequest);
  93. }
  94. /**
  95. * 验证用户支付金额 场景 微信回调验证
  96. *
  97. * @param jsonObject 微信回调json 返回参数
  98. * @param total 数据库记录金额
  99. * @return Boolean
  100. */
  101. public static Boolean verifyMoney(JSONObject jsonObject, Integer total) {
  102. // 总金额计数值 用户支付计算
  103. int userPayTotal = WeChatPayParam.NUM_ZERO;
  104. // 1.验证订单金额
  105. // 用户支付金额
  106. int payerTotal = (int) jsonObject.getJSONObject(WeChatPayParam.AMOUNT).get(WeChatPayParam.AMOUNT_PAYER_TOTAL);
  107. userPayTotal += payerTotal;
  108. // CASH充值型代金券 要加上优惠金额 银行优惠 获取
  109. // 排空 如果没有优惠则跳过
  110. if (!ObjectUtil.isEmpty(jsonObject.get(WeChatPayParam.PROMOTION_DETAIL))) {
  111. JSONArray jsonArray = jsonObject.getJSONArray(WeChatPayParam.PROMOTION_DETAIL);
  112. for (Object object : jsonArray) {
  113. JSONObject json = (JSONObject) object;
  114. // 如果优惠类型为CASH 则要和 用户支付金额 累加
  115. if (WeChatPayParam.WX_DISCOUNT_TYPE.equals(json.get(WeChatPayParam.PROMOTION_DETAIL_TYPE).toString())) {
  116. userPayTotal += (int) json.get(WeChatPayParam.AMOUNT);
  117. }
  118. }
  119. }
  120. // 2.总金额 预支付时的 金额 与 total 用户支付金额
  121. // 微信端返回的支付总金额
  122. int wxTotal = (int) jsonObject.getJSONObject(WeChatPayParam.AMOUNT).get(WeChatPayParam.AMOUNT_TOTAL);
  123. // 校验通知的信息是否与商户侧的信息一致,防止数据泄露导致出现“假通知”,造成资金损失。
  124. log.info("微信回调金额===比较=== " + "微信端返回的支付总金额" + jsonObject.getJSONObject(WeChatPayParam.AMOUNT).get(WeChatPayParam.AMOUNT_TOTAL) + "================用户支付总金额计算" + userPayTotal);
  125. return wxTotal == userPayTotal && total == wxTotal;
  126. }
  127. /**
  128. * 获取接口调用凭证
  129. */
  130. public static JSONObject getAccessToken(WeChatToolConfig config) throws Exception {
  131. log.info("initAccessToken:开始运行...");
  132. // 获取secret
  133. String secret = WxMaConfiguration.getMaService(config.getAppId()).getWxMaConfig().getSecret();
  134. // 获取url
  135. String url = StrFormatter.format(WxApiTypeEnum.API_VOUCHER.getValue(), config.getAppId(), secret);
  136. return getBodyAsJsonByGet(url, config);
  137. }
  138. /**
  139. * 调用微信支付 get请求 统一配置
  140. * 要微信签名认证
  141. *
  142. * @param url 请求url
  143. * @return JSONObject
  144. */
  145. public static JSONObject getBodyAsJsonByGet(String url, WeChatToolConfig config) throws IOException {
  146. // 1.构造httpGet请求
  147. HttpGet httpGet = new HttpGet(url);
  148. httpGet.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
  149. // 2.调起微信查询订单接口
  150. CloseableHttpResponse response = WeChatUtil.getHttpClient(config, WeChatUtil.getVerifier(config)).execute(httpGet);
  151. // 3.返回结果信息
  152. String bodyAsString = EntityUtils.toString(response.getEntity());
  153. // 转为JSON格式返回
  154. return JSON.parseObject(bodyAsString);
  155. }
  156. /**
  157. * 调用微信支付 post请求 统一配置
  158. * 要微信签名认证
  159. *
  160. * @param url 请求url
  161. * @param requestParam 请求参数
  162. * @param config 基本配置
  163. * @return JSONObject
  164. */
  165. public static JSONObject getBodyAsJsonByPost(String url, JSONObject requestParam, WeChatToolConfig config) throws Exception {
  166. // 1.设置请求url和请求头
  167. HttpPost httpPost = new HttpPost(url);
  168. httpPost.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
  169. httpPost.addHeader(WechatPayHttpHeaders.CONTENT_TYPE, WechatPayHttpHeaders.APPLICATION_JSON_UTF);
  170. // 2.传入参数
  171. String jsonString = JSON.toJSONString(requestParam);
  172. httpPost.setEntity(new StringEntity(jsonString, StandardCharsets.UTF_8));
  173. // 3.调用接口 获取预支付交易会话标识 prepay_id
  174. CloseableHttpResponse response = WeChatUtil.getHttpClient(config, WeChatUtil.getVerifier(config)).execute(httpPost);
  175. // 4.获取返回值 转为JSON
  176. String bodyAsString = EntityUtils.toString(response.getEntity());
  177. return JSON.parseObject(bodyAsString);
  178. }
  179. /**
  180. * 获取签名
  181. *
  182. * @param appId appId
  183. * @param timestamp 时间戳
  184. * @param nonce 随机字符串
  185. * @param wxPackage 订单详情扩展字符串
  186. * @param privateKey 商户私钥
  187. */
  188. public static String getSign(String appId, String timestamp, String nonce, String wxPackage, String privateKey) throws Exception {
  189. // APP调起支付API 构造签名串
  190. // 应用id
  191. String builder = appId + "\n" +
  192. // 时间戳
  193. timestamp + "\n" +
  194. // 随机字符串
  195. nonce + "\n" +
  196. // 预支付交易会话标识 prepay_id=wx201410272009395522657a690389285100 必须以此格式
  197. wxPackage + "\n";
  198. // 读取privateKey商户私钥
  199. PrivateKey merchantPrivateKey = PemUtils.getPrivateKey(privateKey);
  200. // 计算签名
  201. return WeChatUtil.sign(builder.getBytes(StandardCharsets.UTF_8), merchantPrivateKey);
  202. }
  203. }
7,微信支付参数 WeChatPayParam
  1. public class WeChatPayParam {
  2. /**
  3. * 应用ID
  4. */
  5. public final static String APPID = "appid";
  6. /**
  7. * 直连商户号
  8. */
  9. public final static String MCHID = "mchid";
  10. /**
  11. * 用户支付状态
  12. */
  13. public final static String TRADE_STATE = "trade_state";
  14. /**
  15. * 用户退款状态
  16. */
  17. public final static String STATUS = "status";
  18. /**
  19. * 商品描述
  20. */
  21. public final static String DESCRIPTION = "description";
  22. /**
  23. * 通知地址
  24. */
  25. public final static String NOTIFY_URL = "notify_url";
  26. /**
  27. * 预支付交易会话标识
  28. */
  29. public final static String PREPAY_ID = "prepay_id";
  30. /**
  31. * 商户订单号
  32. */
  33. public final static String OUT_TRADE_NO = "out_trade_no";
  34. /**
  35. * 商户退款单号
  36. */
  37. public final static String OUT_REFUND_NO = "out_refund_no";
  38. /**
  39. * 微信支付系统生成的订单号
  40. */
  41. public final static String TRANSACTION_ID = "transaction_id";
  42. /**
  43. * 微信支付系统生成的订单号
  44. */
  45. public final static String REFUND_ID = "refund_id";
  46. /**
  47. * 订单金额
  48. */
  49. public final static String AMOUNT = "amount";
  50. /**
  51. * 总金额 下单时系统计算金额 单位为分
  52. */
  53. public final static String AMOUNT_TOTAL = "total";
  54. /**
  55. * 支付者
  56. */
  57. public final static String PAYER = "payer";
  58. /**
  59. * 用户在直连商户appid下的唯一标识。 下单前需获取到用户的Openid
  60. */
  61. public final static String OPENID = "openid";
  62. /**
  63. * 总金额 退款时 退款金额
  64. */
  65. public final static String AMOUNT_REFUND = "refund";
  66. /**
  67. * 总金额 退款时 币种
  68. */
  69. public final static String AMOUNT_CURRENCY = "currency";
  70. /**
  71. * 用户支付金额
  72. */
  73. public final static String AMOUNT_PAYER_TOTAL = "payer_total";
  74. /**
  75. * 优惠功能
  76. */
  77. public final static String PROMOTION_DETAIL = "promotion_detail";
  78. /**
  79. * 优惠类型
  80. */
  81. public final static String PROMOTION_DETAIL_TYPE = "type";
  82. /**
  83. * 微信优惠 CASH:充值型代金券
  84. */
  85. public final static String WX_DISCOUNT_TYPE = "CASH";
  86. /**
  87. * 下单回调给微信支付成功信息
  88. */
  89. public final static String WX_BACK_OK = "SUCCESS";
  90. /**
  91. * 退款回调 退款状态
  92. */
  93. public final static String REFUND_STATUS = "refund_status";
  94. /**
  95. * 微信回调 通知数据
  96. */
  97. public final static String RESOURCE = "resource";
  98. /**
  99. * 微信账单类型 交易账单
  100. */
  101. public final static String TRADE_BILL = "tradebill";
  102. /**
  103. * 微信账单类型 资金账单
  104. */
  105. public final static String FUND_FLOW_BILL = "fundflowbill";
  106. /**
  107. * 微信账单下载地址
  108. */
  109. public final static String DOWNLOAD_URL = "download_url";
  110. /**
  111. * 微信回调 通知数据=>数据密文
  112. */
  113. public final static String RESOURCE_CIPHERTEXT = "ciphertext";
  114. /**
  115. * 微信回调 通知数据=>附加数据
  116. */
  117. public final static String RESOURCE_ASSOCIATED_DATA = "associated_data";
  118. /**
  119. * 微信回调 通知数据=>随机串
  120. */
  121. public final static String RESOURCE_NONCE = "nonce";
  122. /**
  123. * 发货信息 状态码
  124. */
  125. public final static String ERR_CODE = "errcode";
  126. /**
  127. * 发货信息 状态信息
  128. */
  129. public final static String ERR_MSG = "errmsg";
  130. /**
  131. * 请求支付 错误状态码
  132. */
  133. public final static String CODE = "code";
  134. /**
  135. * 请求支付 状态信息
  136. */
  137. public final static String MESSAGE = "message";
  138. /**
  139. * 固定支付参数 package
  140. */
  141. public final static String WX_PACKAGE = "prepay_id=";
  142. /**
  143. * 币种 RMB
  144. */
  145. public final static String CURRENCY_RMB = "CNY";
  146. /**
  147. * 支付成功
  148. */
  149. public final static String PAY_SUCCESS = "支付成功";
  150. /**
  151. * 退款成功
  152. */
  153. public final static String REFUND_SUCCESS = "退款成功";
  154. /**
  155. * 订单单号类型
  156. */
  157. public final static String ORDER_NUMBER_TYPE = "order_number_type";
  158. /**
  159. * 商品信息
  160. */
  161. public final static String ITEM_DESC = "item_desc";
  162. /**
  163. * 订单
  164. */
  165. public final static String ORDER_KEY = "order_key";
  166. /**
  167. * 物流模式
  168. */
  169. public final static String LOGISTICS_TYPE = "logistics_type";
  170. /**
  171. * 发货模式
  172. */
  173. public final static String DELIVERY_MODE = "delivery_mode";
  174. /**
  175. * 物流信息列表
  176. */
  177. public final static String SHIPPING_LIST = "shipping_list";
  178. /**
  179. * 上传时间
  180. */
  181. public final static String UPLOAD_TIME = "upload_time";
  182. /**
  183. * 获取到的凭证
  184. */
  185. public final static String ACCESS_TOKEN = "access_token";
  186. /**
  187. * 数字 0~11
  188. */
  189. public final static int NUM_NEGATIVE_ONE = -1;
  190. public final static int NUM_ZERO = 0;
  191. public final static int NUM_ONE = 1;
  192. public final static int NUM_TWO = 2;
  193. public final static int NUM_THREE = 3;
  194. public final static int NUM_FOUR = 4;
  195. public final static int NUM_FIVE = 5;
  196. public final static int NUM_SIX = 6;
  197. public final static int NUM_SEVEN = 7;
  198. public final static int NUM_EIGHT = 8;
  199. public final static int NUM_NINE = 9;
  200. public final static int NUM_TEN = 10;
  201. public final static int NUM_ELEVEN = 11;
  202. public final static int NUM_15 = 15;
  203. public final static int NUM_16 = 16;
  204. public final static int NUM_19 = 19;
  205. public final static int NUM_TWENTY = 20;
  206. public final static int NUM_30 = 30;
  207. public final static int NUM_32 = 32;
  208. public final static int NUM_50 = 50;
  209. public final static int NUM_60 = 60;
  210. public final static int NUM_64 = 64;
  211. public final static int NUM_90 = 90;
  212. public final static int NUM_100 = 100;
  213. public final static int NUM_200 = 200;
  214. public final static int NUM_1024 = 1024;
  215. public final static int NUM_5000 = 5000;
  216. public final static int NUM_24_time = 86400; // 60*60*60*24 一天
  217. }

四,微信支付请求下单接口

1,控制层 拿到需要支付订单id进行一系列操作
  1. @Autowired
  2. private WaybillService waybillService;
  3. /**
  4. * 微信请求下单支付
  5. *
  6. * @param waybillId 运单id
  7. * @return 付款所需参数
  8. */
  9. @RepeatSubmit
  10. @GetMapping("/weChatCreateOrder/{waybillId}")
  11. @Operation(summary = "微信请求下单支付")
  12. public AjaxResult<CreateOrderVo> weChatCreateOrder(@PathVariable("waybillId") String waybillId) {
  13. return waybillService.weChatCreateOrder(waybillId);
  14. }
2,返回对象 CreateOrderVo 用户付款需要的参数
  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. @EqualsAndHashCode(callSuper = false)
  5. public class CreateOrderVo implements Serializable {
  6. // 微信小程序需要参数
  7. // "appId": "wx499********7c70e", // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
  8. // "timeStamp": 1597935292, // 时间戳(单位:秒)
  9. // "nonceStr": "c5sEwbaNPiXAF3iv", // 随机字符串
  10. // "package": "wx202254********************fbe90000", // 小程序下单接口返回的prepay_id参数值,提交格式如:prepay_id=***;示例值:prepay_id=wx201410272009395522657a690389285100
  11. // "signType": "RSA" 签名类型,默认为RSA,仅支持RSA。
  12. // "paySign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
  13. @Serial
  14. private static final long serialVersionUID = 1L;
  15. /**
  16. * 时间戳
  17. */
  18. @Schema(description = "时间戳")
  19. private String timeStamp;
  20. /**
  21. * 随机字符串
  22. */
  23. @Schema(description = "随机字符串")
  24. private String nonceStr;
  25. /**
  26. * 订单详情扩展字符串 package
  27. */
  28. @Schema(description = "订单详情扩展字符串 package")
  29. private String wxPackage;
  30. /**
  31. * 签名方式
  32. */
  33. @Schema(description = "签名方式")
  34. private String signType;
  35. /**
  36. * 签名
  37. */
  38. @Schema(description = "签名")
  39. private String paySign;
  40. /**
  41. * 运单号
  42. */
  43. @Schema(description = "运单号")
  44. private String outTradeNo;
  45. }
3,业务层 请求下单获取prepay_id构造签名
  1. // 第三节中保存的微信配置信息 注入进来
  2. @Autowired
  3. private WeChatToolConfig config;
  4. @Autowired
  5. private PayService payService;
  6. /**
  7. * 微信请求下单支付
  8. *
  9. * @param waybillId 运单id
  10. * @return 付款所需参数
  11. */
  12. @Override
  13. public AjaxResult<CreateOrderVo> weChatCreateOrder(String waybillId) {
  14. // 查询运单
  15. Waybill waybill = getById(waybillId, "运单id不存在");
  16. // 调用微信请求下单接口
  17. int total = waybill.getGoodTotalPrice().multiply(new BigDecimal("100.00")).intValue();
  18. // 获取付款所需参数
  19. CreateOrderVo createOrder = payService.createPayOrder(waybill.getGoodName(), waybillId, waybill.getOpenId(), total, config);
  20. log.info("支付返回" + createOrder);
  21. return AjaxResult.success(createOrder);
  22. }
  1. /**
  2. * 小程序请求下单
  3. *
  4. * @param description 商品描述
  5. * @param outTradeNo 商户订单号
  6. * @param openId appid下的唯一标识
  7. * @param total 总金额
  8. * @param config 基本配置
  9. * @return 小程序下单前端Vo
  10. */
  11. @Override
  12. public CreateOrderVo createPayOrder(String description, String outTradeNo, String openId, int total, WeChatToolConfig config) {
  13. // 配置下单参数
  14. JSONObject requestParam = new JSONObject();
  15. // 商户id
  16. requestParam.put(WeChatPayParam.MCHID, config.getMchId());
  17. // 应用id
  18. requestParam.put(WeChatPayParam.APPID, config.getAppId());
  19. // 商品描述
  20. requestParam.put(WeChatPayParam.DESCRIPTION, description);
  21. // 回调地址
  22. requestParam.put(WeChatPayParam.NOTIFY_URL, config.getNotifyUrl());
  23. // 订单号
  24. requestParam.put(WeChatPayParam.OUT_TRADE_NO, outTradeNo);
  25. // 金额
  26. JSONObject amount = new JSONObject();
  27. // 金额 单位 分
  28. amount.put(WeChatPayParam.AMOUNT_TOTAL, "dev".equals(SpringUtils.getActiveProfile()) ? 1 : total);
  29. // 货币类型 人民币
  30. amount.put(WeChatPayParam.AMOUNT_CURRENCY, WeChatPayParam.CURRENCY_RMB);
  31. // 金额
  32. requestParam.put(WeChatPayParam.AMOUNT, amount);
  33. // 支付者
  34. JSONObject payer = new JSONObject();
  35. // 微信登录时生成的openid,创建订单时存入订单中
  36. payer.put(WeChatPayParam.OPENID, openId);
  37. // 支付者
  38. requestParam.put(WeChatPayParam.PAYER, payer);
  39. try {
  40. // 调用post请求
  41. JSONObject jsonObject = WeChatUtil.getBodyAsJsonByPost(WxApiTypeEnum.CREATE_ORDER.getValue(), requestParam, config);
  42. // 异常情况
  43. if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
  44. throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
  45. }
  46. // 时间戳
  47. String timestamp = String.valueOf(DateUtil.currentSeconds());
  48. // 随机字符串
  49. String nonce = RandomUtil.randomString(WeChatPayParam.NUM_32);
  50. // 订单详情扩展字符串 prepay_id=wx201410272009395522657a690389285100 必须以此格式
  51. String wxPackage = WeChatPayParam.WX_PACKAGE + jsonObject.get(WeChatPayParam.PREPAY_ID);
  52. // 获取签名
  53. String sign = WeChatUtil.getSign(config.getAppId(), timestamp, nonce, wxPackage, config.getPrivateKey());
  54. return new CreateOrderVo(timestamp, nonce, wxPackage, "RSA", sign, outTradeNo);
  55. } catch (Exception e) {
  56. log.error("请求下单失败:" + outTradeNo);
  57. log.error(e.getMessage());
  58. throw new CustomException("请求下单失败:" + e.getMessage());
  59. }
  60. }

五,微信回调接口 注:需使用工具解决内网穿透问题 例:路由侠

1,控制层
  1. /**
  2. * 支付回调给微信确认
  3. */
  4. @Operation(summary = "支付回调给微信确认")
  5. @IgnoreAuth
  6. @PostMapping("/wechatPayCallback")
  7. public Map<String, String> wechatCallback(HttpServletRequest request) {
  8. Map<String, String> result = new HashMap<>(WeChatPayParam.NUM_TWO);
  9. // 判断支付是否成功
  10. if (waybillService.verifyCreateOrder(request)) {
  11. result.put(WeChatPayParam.CODE, WeChatPayParam.WX_BACK_OK);
  12. } else {
  13. result.put(WeChatPayParam.CODE, "FAIL");
  14. result.put(WeChatPayParam.MESSAGE, "失败");
  15. }
  16. return result;
  17. }
2,业务层 判断验证是否成功
  1. /**
  2. * 微信支付回调验证判定 核对成功 数据异步入库
  3. */
  4. @Override
  5. @Transactional
  6. public Boolean verifyCreateOrder(HttpServletRequest request) {
  7. log.info("===================================进入微信支付回调核对订单中========================================");
  8. // 获取微信通知详情
  9. JSONObject decryptData = payService.getDecryptData(request, config);
  10. // 获取运单号
  11. String waybillId = decryptData.get(WeChatPayParam.OUT_TRADE_NO).toString();
  12. // 获取微信支付生成的订单号
  13. String transactionId = decryptData.get(WeChatPayParam.TRANSACTION_ID).toString();
  14. log.info(decryptData.get(WeChatPayParam.OUT_TRADE_NO).toString() + "订单回调信息记录:订单状态:" + waybillId);
  15. // 判断支付是否成功
  16. if (StrUtil.equals(WeChatPayParam.WX_BACK_OK, decryptData.get(WeChatPayParam.TRADE_STATE).toString())) {
  17. // 查询运单
  18. Waybill waybill = getById(waybillId, "运单id不存在");
  19. // 判断金额是否与数据库一致
  20. if (WeChatUtil.verifyMoney(decryptData, getAmountByOrderNo(waybillId))) {
  21. // 修改订单状态,保存微信支付订单号
  22. updateStatus(waybill, transactionId);
  23. // 判断发货是否成功
  24. if (payService.verifyDeliverGood(waybill.getGoodName(), waybill.getOpenId(), transactionId, config)) {
  25. // 修改发货状态 确认
  26. updateDeliverGood(waybill, ShipmentEnum.OK);
  27. } else {
  28. // 修改发货状态 未确认
  29. updateDeliverGood(waybill, ShipmentEnum.NOT);
  30. }
  31. return true;
  32. }
  33. }
  34. return false;
  35. }
  1. /**
  2. * 获取通知
  3. *
  4. * @param request 请求
  5. * @param config 微信配置
  6. * @return 通知详情
  7. */
  8. @Override
  9. public JSONObject getDecryptData(HttpServletRequest request, WeChatToolConfig config) {
  10. try {
  11. // 解析微信通知
  12. Notification notification = WeChatUtil.verifyBack(request, config);
  13. // 获取通知简要说明
  14. String summary = notification.getSummary();
  15. // 判断支付状态
  16. if (WeChatPayParam.PAY_SUCCESS.equals(summary) || WeChatPayParam.REFUND_SUCCESS.equals(summary)) {
  17. // 返回详情信息
  18. return JSON.parseObject(notification.getDecryptData());
  19. } else {
  20. // 支付失败
  21. throw new CustomException(summary);
  22. }
  23. } catch (Exception e) {
  24. log.error("回调失败验证" + e);
  25. e.printStackTrace();
  26. throw new CustomException("支付回调失败:" + e.getMessage());
  27. }
  28. }
  1. /**
  2. * 判断发货是否成功
  3. *
  4. * @param description 商品描述
  5. * @param openId appid下的唯一标识
  6. * @param transactionId 微信支付生成订单号
  7. * @param config 基本配置
  8. * @return 是否成功
  9. */
  10. @Override
  11. public Boolean verifyDeliverGood(String description, String openId, String transactionId, WeChatToolConfig config) {
  12. try {
  13. // 获取接口调用凭证
  14. JSONObject jsonObject = WeChatUtil.getAccessToken(config);
  15. // 异常情况
  16. if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
  17. throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
  18. }
  19. String accessToken = jsonObject.get(WeChatPayParam.ACCESS_TOKEN).toString();
  20. // 构建请求参数
  21. JSONObject requestParam = new JSONObject();
  22. // 订单
  23. JSONObject orderKey = new JSONObject();
  24. orderKey.put(WeChatPayParam.ORDER_NUMBER_TYPE, OrderNumberTypeEnum.WECHAT.getCode());
  25. orderKey.put(WeChatPayParam.TRANSACTION_ID, transactionId);
  26. requestParam.put(WeChatPayParam.ORDER_KEY, orderKey);
  27. // 物流模式 用户自提
  28. requestParam.put(WeChatPayParam.LOGISTICS_TYPE, LogisticsTypeEnum.VIRTUAL.getCode());
  29. // 发货模式 统一发货
  30. requestParam.put(WeChatPayParam.DELIVERY_MODE, DeliveryModeEnum.UNIFIED_DELIVERY.getCode());
  31. // 物流信息列表
  32. List<JSONObject> shippingLists = new ArrayList<>();
  33. Map<String, Object> map = new HashMap<>();
  34. map.put(WeChatPayParam.ITEM_DESC, description);
  35. shippingLists.add(new JSONObject(map));
  36. requestParam.put(WeChatPayParam.SHIPPING_LIST, shippingLists);
  37. // 上传时间
  38. requestParam.put(WeChatPayParam.UPLOAD_TIME, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()));
  39. // 支付者
  40. JSONObject payer = new JSONObject();
  41. // 微信登录时生成的openid,创建订单时存入订单中
  42. payer.put(WeChatPayParam.OPENID, openId);
  43. requestParam.put(WeChatPayParam.PAYER, payer);
  44. // 设置请求url
  45. String url = StrFormatter.format(WxApiTypeEnum.GOOD_ENTERING.getValue(), accessToken);
  46. // 发送请求
  47. JSONObject object = WeChatUtil.getBodyAsJsonByPost(url, requestParam, config);
  48. // 发货失败
  49. if (!object.get(WeChatPayParam.ERR_CODE).equals(WeChatPayParam.NUM_ZERO)) {
  50. log.error("发货失败:" + object.get(WeChatPayParam.ERR_CODE) + " " + object.get(WeChatPayParam.ERR_MSG));
  51. return false;
  52. }
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. throw new CustomException(e.getMessage());
  56. }
  57. return true;
  58. }
  1. /**
  2. * 更新订单,运单状态 已完成
  3. *
  4. * @param waybill 运单
  5. * @param transactionId 微信支付订单号
  6. */
  7. public void updateStatus(Waybill waybill, String transactionId) {
  8. // 修改运单状态
  9. waybill.setWaybillStatus(WaybillStatusEnum.COMPLETED);
  10. waybill.setPayId(transactionId);
  11. updateById(waybill);
  12. // 新增散户流水
  13. individualAddFlow(waybill);
  14. // 查询订单
  15. final OrderService orderService = SpringUtils.getBean(OrderService.class);
  16. LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
  17. queryWrapper.eq(Order::getId, waybill.getOrderId());
  18. Order order = orderService.getOne(queryWrapper);
  19. // 修改订单状态
  20. LambdaUpdateWrapper<Order> orderWrapper = new LambdaUpdateWrapper<>();
  21. orderWrapper.eq(Order::getId, waybill.getOrderId());
  22. orderWrapper.set(Order::getOrderStatus, OrderStatusEnum.COMPLETED);
  23. orderWrapper.set(Order::getGoodWeight, waybill.getNetWeight());
  24. orderWrapper.set(Order::getGoodTotalPrice, waybill.getNetWeight().multiply(order.getGoodPrice()));
  25. orderService.update(orderWrapper);
  26. }
  27. /**
  28. * 修改运单确认发货
  29. *
  30. * @param waybill 运单
  31. * @param shipment 确认发货枚举
  32. */
  33. private void updateDeliverGood(JkwlWaybill waybill, ShipmentEnum shipment) {
  34. waybill.setShipment(shipment);
  35. updateById(waybill);
  36. }

六,查询支付结果

1,控制层
  1. /**
  2. * 查询微信支付订单状态
  3. *
  4. * @param waybillId 运单id
  5. */
  6. @GetMapping("/getPayOrder/{waybillId}")
  7. @Operation(summary = "查询微信支付订单状态")
  8. public AjaxResult<Void> getPayOrder(@PathVariable("waybillId") String waybillId) {
  9. return waybillService.getPayOrder(waybillId);
  10. }
2,业务层
  1. /**
  2. * 查询微信支付是否成功
  3. *
  4. * @param waybillId 运单id
  5. */
  6. @Override
  7. public AjaxResult<Void> getPayOrder(String waybillId) {
  8. try {
  9. // 查询微信支付信息
  10. JSONObject jsonObject = payService.getPayState(waybillId, config);
  11. // 返回查单结果信息
  12. final String res = jsonObject.get(WeChatPayParam.TRADE_STATE).toString();
  13. // 支付成功
  14. if (WeChatPayParam.WX_BACK_OK.equals(res)) {
  15. // 根据业务 该干嘛干嘛
  16. // 例: 修改订单
  17. // updateStatus(orderId);
  18. return AjaxResult.success("SUCCESS");
  19. } catch (Exception e) {
  20. log.error("支付查单失败" + orderId);
  21. e.printStackTrace();
  22. }
  23. return AjaxResult.error();
  24. }
  1. /**
  2. * 获取支付状态
  3. *
  4. * @param waybillId 运单id
  5. * @param config 配置
  6. * @return 状态详情
  7. */
  8. @Override
  9. public JSONObject getPayState(String waybillId, WeChatToolConfig config) throws IOException {
  10. // 查单 微信接口 编辑 微信订单号 + 商户号
  11. String url = StrFormatter.format(WxApiTypeEnum.QUERY_CREATE_ORDER.getValue(), waybillId, config.getMchId());
  12. // 调用微信接口
  13. JSONObject jsonObject = WeChatUtil.getBodyAsJsonByGet(url, config);
  14. // 异常情况
  15. if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
  16. throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
  17. }
  18. return jsonObject;
  19. }

七,微信退款

  1. /**
  2. * 微信退款
  3. *
  4. * @param waybillId 运单id
  5. */
  6. @RepeatSubmit
  7. @GetMapping("/weChatRefundOrder/{waybillId}/{amount}")
  8. @Operation(summary = "微信退款")
  9. @IgnoreAuth
  10. public AjaxResult<Void> weChatRefundOrder(@PathVariable("waybillId") String waybillId, @PathVariable("amount") int amount) {
  11. return waybillService.weChatRefundOrder(waybillId, amount);
  12. }
  1. /**
  2. * 微信退款
  3. *
  4. * @param waybillId 运单id
  5. */
  6. @Override
  7. public AjaxResult<Void> weChatRefundOrder(String waybillId, int amount) {
  8. // 非开发环境 输入多少退多少
  9. if (!"dev".equals(SpringUtils.getActiveProfile())) {
  10. // 从数据库获取运单退款金额
  11. amount = getAmountByOrderNo(waybillId);
  12. }
  13. // 调用微信退款接口
  14. JSONObject jsonObject = payService.refundOrder(waybillId, amount, config);
  15. // 获取微信退款状态
  16. String status = jsonObject.get(WeChatPayParam.STATUS).toString();
  17. return switch (status) {
  18. // 退款关闭
  19. case "CLOSED" -> AjaxResult.success("退款关闭");
  20. // 退款处理中
  21. case "PROCESSING" -> AjaxResult.success("退款处理中 请稍后");
  22. // 退款成功
  23. case "SUCCESS" -> {
  24. // 可拓展 退款成功后进行的操作 例:修改订单退款订单,运单状态 微信退款入数据库
  25. // updateStatus(orderId);
  26. yield AjaxResult.success("退款申请成功 注意退款查收");
  27. }
  28. // 退款异常
  29. default -> AjaxResult.error("退款账户异常 请联系管理人员");
  30. };
  31. }
  1. /**
  2. * 微信退款
  3. *
  4. * @param waybillId 运单id
  5. * @param refundAmount 退款金额
  6. * @param config 配置
  7. * @return 状态详情
  8. */
  9. @Override
  10. public JSONObject refundOrder(String waybillId, Integer refundAmount, WeChatToolConfig config) {
  11. // 配置参数
  12. JSONObject requestParam = new JSONObject();
  13. // 商户订单号 orderId
  14. requestParam.put(WeChatPayParam.OUT_TRADE_NO, waybillId);
  15. // 商户退款单号
  16. requestParam.put(WeChatPayParam.OUT_REFUND_NO, waybillId);
  17. // 退款回调地址
  18. requestParam.put(WeChatPayParam.NOTIFY_URL, config.getRefundNotifyUrl());
  19. // 金额信息 amount (单位都是分)
  20. JSONObject amount = new JSONObject();
  21. // 原订单金额 total
  22. amount.put(WeChatPayParam.AMOUNT_TOTAL, refundAmount);
  23. // 退款金额 refund
  24. amount.put(WeChatPayParam.AMOUNT_REFUND, refundAmount);
  25. // 退款币种 CNY 人民币
  26. amount.put(WeChatPayParam.AMOUNT_CURRENCY, WeChatPayParam.CURRENCY_RMB);
  27. // 金额信息 amount: 原订单金额 total 退款金额 refund (单位都是分)
  28. requestParam.put(WeChatPayParam.AMOUNT, amount);
  29. try {
  30. // 调用请求接口
  31. JSONObject jsonObject = WeChatUtil.getBodyAsJsonByPost(WxApiTypeEnum.REFUND_ORDER.getValue(), requestParam, config);
  32. // 异常情况
  33. if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
  34. throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
  35. }
  36. log.info("微信申请退款返回结果" + "response:" + jsonObject);
  37. return jsonObject;
  38. } catch (Exception e) {
  39. log.info("微信退款" + waybillId + "失败");
  40. e.printStackTrace();
  41. throw new CustomException("退款失败:" + e.getMessage());
  42. }
  43. }

八、退款回调

  1. /**
  2. * 微信退款回调接口
  3. */
  4. @IgnoreAuth
  5. @Operation(summary = "微信退款回调接口")
  6. @PostMapping("/wechatRefundBack")
  7. public Map<String, String> wechatRefundBack(HttpServletRequest request) {
  8. Map<String, String> result = new HashMap<>(WeChatPayParam.NUM_TWO);
  9. // 根据退款返回结果 更新订单状态 返回结果
  10. if (waybillService.verifyRefundOrder(request)) {
  11. log.info("==============================微信退款成功订单=====================================");
  12. result.put(WeChatPayParam.CODE, WeChatPayParam.WX_BACK_OK);
  13. } else {
  14. result.put(WeChatPayParam.CODE, "FAIL");
  15. result.put(WeChatPayParam.MESSAGE, "失败");
  16. }
  17. return result;
  18. }
  1. @Override
  2. public Boolean verifyRefundOrder(HttpServletRequest request) {
  3. // 获取微信通知详情
  4. JSONObject decryptData = jkwlPayService.getDecryptData(request, config);
  5. // 商户退款单号
  6. String outRefundNo = decryptData.get(WeChatPayParam.OUT_REFUND_NO).toString();
  7. log.info("微信退款成功订单:" + outRefundNo);
  8. // 退款状态
  9. String refundStatus = decryptData.get(WeChatPayParam.REFUND_STATUS).toString();
  10. // 数据库核对 如果退款状态已退款说明已处理 直接返回即可
  11. if (WaybillStatusEnum.CANCELED.equals(getStatus(outRefundNo))) {
  12. return true;
  13. }
  14. return switch (refundStatus) {
  15. // 退款关闭
  16. case "CLOSED" -> Boolean.FALSE;
  17. // 退款成功
  18. case "SUCCESS" -> {
  19. // 修改订单退款订单,运单状态 微信退款入数据库
  20. // updateStatus(outRefundNo);
  21. yield Boolean.TRUE;
  22. }
  23. // 退款异常
  24. default -> Boolean.FALSE;
  25. };
  26. }

九,查询退款订单

  1. /**
  2. * 查询退款订单
  3. *
  4. * @param waybillId 运单id
  5. */
  6. @Operation(summary = "查询退款订单")
  7. @GetMapping("/getRefundOrder/{waybillId}")
  8. public AjaxResult<Void> getRefundOrder(@PathVariable("waybillId") String waybillId) {
  9. return waybillService.getRefundOrder(waybillId);
  10. }
  1. /**
  2. * 查询退款订单
  3. *
  4. * @param waybillId 运单id
  5. */
  6. @Override
  7. public AjaxResult<Void> getRefundOrder(String waybillId) {
  8. try {
  9. // 调用微信查询退款订单接口
  10. JSONObject jsonObject = payService.getRefundState(waybillId, config);
  11. // 获取退款状态
  12. String string = jsonObject.get(WeChatPayParam.STATUS).toString();
  13. return switch (string) {
  14. // 退款关闭
  15. case "CLOSED" -> AjaxResult.success("退款关闭");
  16. // 退款处理中
  17. case "PROCESSING" -> AjaxResult.success("退款处理中 请稍后");
  18. // 退款成功
  19. case "SUCCESS" -> AjaxResult.success("退款申请成功 注意退款查收");
  20. // 退款异常
  21. default -> AjaxResult.error("退款账户异常 请联系管理人员");
  22. };
  23. } catch (Exception e) {
  24. log.error("支付查单失败" + waybillId);
  25. e.printStackTrace();
  26. }
  27. return AjaxResult.error();
  28. }
  1. /**
  2. * 获取退款状态
  3. *
  4. * @param waybillId 运单id
  5. * @param config 配置
  6. * @return 状态详情
  7. */
  8. @Override
  9. public JSONObject getRefundState(String waybillId, WeChatToolConfig config) throws IOException {
  10. // 查单 微信接口 拼接url
  11. String url = StrFormatter.format(WxApiTypeEnum.QUERY_REFUND_ORDER.getValue(), waybillId);
  12. // 调用微信接口
  13. JSONObject jsonObject = WeChatUtil.getBodyAsJsonByGet(url, config);
  14. // 异常情况
  15. if (Objects.nonNull(jsonObject.get(WeChatPayParam.CODE))) {
  16. throw new CustomException(jsonObject.get(WeChatPayParam.MESSAGE).toString());
  17. }
  18. return jsonObject;
  19. }

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

闽ICP备14008679号