|
@@ -2,6 +2,7 @@ package com.kym.service.wechat.impl;
|
|
|
|
|
|
|
|
import cn.dev33.satoken.stp.StpUtil;
|
|
import cn.dev33.satoken.stp.StpUtil;
|
|
|
import cn.hutool.core.io.IoUtil;
|
|
import cn.hutool.core.io.IoUtil;
|
|
|
|
|
+import cn.hutool.core.util.RandomUtil;
|
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
|
import com.kym.common.config.WxPayConfig;
|
|
import com.kym.common.config.WxPayConfig;
|
|
|
import com.kym.common.constant.ResponseEnum;
|
|
import com.kym.common.constant.ResponseEnum;
|
|
@@ -18,16 +19,11 @@ import com.wechat.pay.java.core.notification.NotificationConfig;
|
|
|
import com.wechat.pay.java.core.notification.NotificationParser;
|
|
import com.wechat.pay.java.core.notification.NotificationParser;
|
|
|
import com.wechat.pay.java.core.notification.RequestParam;
|
|
import com.wechat.pay.java.core.notification.RequestParam;
|
|
|
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
|
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
|
|
-import com.wechat.pay.java.service.payments.jsapi.model.Amount;
|
|
|
|
|
-import com.wechat.pay.java.service.payments.jsapi.model.CloseOrderRequest;
|
|
|
|
|
-import com.wechat.pay.java.service.payments.jsapi.model.Payer;
|
|
|
|
|
-import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
|
|
|
|
|
-import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
|
|
|
|
|
-import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByIdRequest;
|
|
|
|
|
-import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
|
|
|
|
|
|
|
+import com.wechat.pay.java.service.payments.jsapi.model.*;
|
|
|
import com.wechat.pay.java.service.payments.model.Transaction;
|
|
import com.wechat.pay.java.service.payments.model.Transaction;
|
|
|
import jakarta.annotation.PostConstruct;
|
|
import jakarta.annotation.PostConstruct;
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
|
|
+import lombok.SneakyThrows;
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
@@ -149,80 +145,86 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
service.closeOrder(request);
|
|
service.closeOrder(request);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public ResponseEntity.BodyBuilder wxNotify(HttpServletRequest request) throws IOException {
|
|
|
|
|
|
|
+ @SneakyThrows
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public ResponseEntity.BodyBuilder wxNotify(HttpServletRequest request) {
|
|
|
|
|
+ var no = RandomUtil.randomInt(1000, 9999);
|
|
|
var signature = request.getHeader("Wechatpay-Signature");
|
|
var signature = request.getHeader("Wechatpay-Signature");
|
|
|
var serial = request.getHeader("Wechatpay-Serial");
|
|
var serial = request.getHeader("Wechatpay-Serial");
|
|
|
var nonce = request.getHeader("Wechatpay-Nonce");
|
|
var nonce = request.getHeader("Wechatpay-Nonce");
|
|
|
var timestamp = request.getHeader("Wechatpay-Timestamp");
|
|
var timestamp = request.getHeader("Wechatpay-Timestamp");
|
|
|
var signatureType = request.getHeader("Wechatpay-Signature-Type");
|
|
var signatureType = request.getHeader("Wechatpay-Signature-Type");
|
|
|
|
|
|
|
|
|
|
+ LOGGER.info("微信支付回调{}:\n Request参数:\n signature:{},serial:{},nonce:{},timestamp:{},signatureType:{}", no, signature, serial, nonce, timestamp, signatureType);
|
|
|
|
|
+
|
|
|
// request中获取body
|
|
// request中获取body
|
|
|
BufferedReader br = request.getReader();
|
|
BufferedReader br = request.getReader();
|
|
|
String str;
|
|
String str;
|
|
|
var requestBody = new StringBuilder();
|
|
var requestBody = new StringBuilder();
|
|
|
while ((str = br.readLine()) != null) {
|
|
while ((str = br.readLine()) != null) {
|
|
|
requestBody.append(str);
|
|
requestBody.append(str);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ LOGGER.info("微信支付回调{}:\nBody数据:\n{}", no, requestBody);
|
|
|
|
|
|
|
|
- // 构造 RequestParam
|
|
|
|
|
- RequestParam requestParam = new RequestParam.Builder()
|
|
|
|
|
- .serialNumber(serial)
|
|
|
|
|
- .nonce(nonce) // 随机数
|
|
|
|
|
- .signature(signature)
|
|
|
|
|
- .timestamp(timestamp)
|
|
|
|
|
- .body(requestBody.toString())
|
|
|
|
|
- .build();
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
|
|
|
|
|
- // 初始化 NotificationParser
|
|
|
|
|
- NotificationParser parser = new NotificationParser((NotificationConfig) config);
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- // 以支付通知回调为例,验签、解密并转换成 Transaction
|
|
|
|
|
- Transaction transaction = parser.parse(requestParam, Transaction.class);
|
|
|
|
|
- // 判断是否已经接收处理过通知
|
|
|
|
|
- if (payLogService.lambdaQuery().eq(PayLog::getOutTradeNo, transaction.getOutTradeNo()).one() != null) {
|
|
|
|
|
- return ResponseEntity.status(HttpStatus.OK);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 资金流水
|
|
|
|
|
- var walletDetail = walletDetailService.getWalletDetailByOrderNo(transaction.getOutTradeNo());
|
|
|
|
|
- if (walletDetail != null) {
|
|
|
|
|
- walletDetail.setType(1); // 充值
|
|
|
|
|
- walletDetail.setStatus(1); //已确认
|
|
|
|
|
- walletDetail.setCurrency(transaction.getAmount().getCurrency());
|
|
|
|
|
- walletDetail.setAmount(transaction.getAmount().getTotal());
|
|
|
|
|
-
|
|
|
|
|
- // 支付记录
|
|
|
|
|
- var payLog = new PayLog();
|
|
|
|
|
- payLog.setUserId(walletDetail.getUserId());
|
|
|
|
|
- payLog.setOpenid(transaction.getPayer().getOpenid());
|
|
|
|
|
- payLog.setBankType(transaction.getBankType());
|
|
|
|
|
- payLog.setMchId(transaction.getMchid());
|
|
|
|
|
- payLog.setOutTradeNo(transaction.getOutTradeNo());
|
|
|
|
|
- payLog.setTransactionId(transaction.getTransactionId());
|
|
|
|
|
- payLog.setSuccessTime(transaction.getSuccessTime());
|
|
|
|
|
- payLog.setTradeType(transaction.getTradeType().name());
|
|
|
|
|
- payLog.setTradeState(transaction.getTradeState().name());
|
|
|
|
|
- payLog.setAttach(transaction.getAttach());
|
|
|
|
|
- payLog.setTotal(transaction.getAmount().getTotal());
|
|
|
|
|
- payLog.setCurrency(transaction.getAmount().getCurrency());
|
|
|
|
|
- payLog.setPayerTotal(transaction.getAmount().getPayerTotal());
|
|
|
|
|
- payLog.setPayerCurrency(transaction.getAmount().getPayerCurrency());
|
|
|
|
|
- payLogService.save(payLog);
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- LOGGER.error("微信支付通知处理异常,资金流水为空,回调信息:{}", transaction);
|
|
|
|
|
- return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- } catch (ValidationException e) {
|
|
|
|
|
- // 签名验证失败,返回 401 UNAUTHORIZED 状态码
|
|
|
|
|
- LOGGER.error("微信支付通知眼前失败", e);
|
|
|
|
|
- throw e;
|
|
|
|
|
|
|
+ // 构造 RequestParam
|
|
|
|
|
+ RequestParam requestParam = new RequestParam.Builder()
|
|
|
|
|
+ .serialNumber(serial)
|
|
|
|
|
+ .nonce(nonce) // 随机数
|
|
|
|
|
+ .signature(signature)
|
|
|
|
|
+ .timestamp(timestamp)
|
|
|
|
|
+ .body(requestBody.toString())
|
|
|
|
|
+ .build();
|
|
|
|
|
+ LOGGER.info("微信支付回调{}:构造 RequestParam完毕", no);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
|
|
|
|
|
+ // 初始化 NotificationParser
|
|
|
|
|
+ NotificationParser parser = new NotificationParser((NotificationConfig) config);
|
|
|
|
|
+
|
|
|
|
|
+ LOGGER.info("微信支付回调{}:初始化NotificationParser完毕", no);
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 以支付通知回调为例,验签、解密并转换成 Transaction
|
|
|
|
|
+ Transaction transaction = parser.parse(requestParam, Transaction.class);
|
|
|
|
|
+ LOGGER.info("微信支付回调{}:验签解密完毕,数据:\n{}", no, transaction);
|
|
|
|
|
+ // 判断是否已经接收处理过通知
|
|
|
|
|
+ if (payLogService.lambdaQuery().eq(PayLog::getOutTradeNo, transaction.getOutTradeNo()).one() != null) {
|
|
|
|
|
+ return ResponseEntity.status(HttpStatus.OK);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 资金流水
|
|
|
|
|
+ var walletDetail = walletDetailService.getWalletDetailByOrderNo(transaction.getOutTradeNo());
|
|
|
|
|
+ if (walletDetail != null) {
|
|
|
|
|
+ walletDetail.setType(1); // 充值
|
|
|
|
|
+ walletDetail.setStatus(1); //已确认
|
|
|
|
|
+ walletDetail.setCurrency(transaction.getAmount().getCurrency());
|
|
|
|
|
+ walletDetail.setAmount(transaction.getAmount().getTotal());
|
|
|
|
|
+
|
|
|
|
|
+ // 支付记录
|
|
|
|
|
+ var payLog = new PayLog();
|
|
|
|
|
+ payLog.setUserId(walletDetail.getUserId());
|
|
|
|
|
+ payLog.setOpenid(transaction.getPayer().getOpenid());
|
|
|
|
|
+ payLog.setBankType(transaction.getBankType());
|
|
|
|
|
+ payLog.setMchId(transaction.getMchid());
|
|
|
|
|
+ payLog.setOutTradeNo(transaction.getOutTradeNo());
|
|
|
|
|
+ payLog.setTransactionId(transaction.getTransactionId());
|
|
|
|
|
+ payLog.setSuccessTime(transaction.getSuccessTime());
|
|
|
|
|
+ payLog.setTradeType(transaction.getTradeType().name());
|
|
|
|
|
+ payLog.setTradeState(transaction.getTradeState().name());
|
|
|
|
|
+ payLog.setAttach(transaction.getAttach());
|
|
|
|
|
+ payLog.setTotal(transaction.getAmount().getTotal());
|
|
|
|
|
+ payLog.setCurrency(transaction.getAmount().getCurrency());
|
|
|
|
|
+ payLog.setPayerTotal(transaction.getAmount().getPayerTotal());
|
|
|
|
|
+ payLog.setPayerCurrency(transaction.getAmount().getPayerCurrency());
|
|
|
|
|
+ payLogService.save(payLog);
|
|
|
|
|
+ LOGGER.info("微信支付回调{}:业务处理结束", no);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ LOGGER.error("微信支付通知处理异常,资金流水为空,回调信息:{}", transaction);
|
|
|
|
|
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (ValidationException e) {
|
|
|
|
|
+ // 签名验证失败,返回 401 UNAUTHORIZED 状态码
|
|
|
|
|
+ LOGGER.error("微信支付通知眼前失败", e);
|
|
|
|
|
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 处理成功,返回 200 OK 状态码
|
|
// 处理成功,返回 200 OK 状态码
|