From 1af77abfa06a1a0d537bb120ae0c362aae9d3b83 Mon Sep 17 00:00:00 2001
From: huliguo <2023611923@qq.com>
Date: 星期三, 30 七月 2025 10:14:40 +0800
Subject: [PATCH] bug修改
---
ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java | 360 ++++++++++++++++++++++++++++++++++++++++++++---------------
1 files changed, 269 insertions(+), 91 deletions(-)
diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java
index f885ddf..6574ab5 100644
--- a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java
+++ b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java
@@ -1,38 +1,52 @@
package com.ruoyi.order.controller.miniapp;
+import com.alibaba.fastjson.JSONObject;
+import com.github.binarywang.wxpay.bean.ecommerce.*;
+import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Response;
+import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingNotifyData;
+import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingNotifyResult;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.ProfitSharingV3Service;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.v3.auth.Verifier;
+import com.github.binarywang.wxpay.v3.util.AesUtils;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.order.domain.dto.AppSureOrderDto;
-import com.ruoyi.order.domain.dto.WXPayNotifyDto;
-import com.ruoyi.order.domain.vo.AppSureOrderVo;
+import com.ruoyi.common.redis.service.RedisService;
+import com.ruoyi.order.domain.dto.WechatPaymentRefundDto;
+import com.ruoyi.order.domain.dto.WeixinPaymentNotifyDto;
+import com.ruoyi.order.domain.pojo.account.OrderRefund;
+import com.ruoyi.order.domain.vo.ProfitSharingNotifyNewResult;
+import com.ruoyi.order.domain.vo.WeixinPaymentNotifyVo;
+import com.ruoyi.order.domain.vo.WeixinPaymentRefundVo;
+import com.ruoyi.order.enums.RefundStatusEnum;
+import com.ruoyi.order.enums.WxPayNotifyEventTypeEnum;
+import com.ruoyi.order.enums.dict.IDict;
+import com.ruoyi.order.service.account.BackMessageService;
+import com.ruoyi.order.service.account.OrderRefundService;
import com.ruoyi.order.service.order.OrderService;
-import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
-import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
-import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
-import com.wechat.pay.java.core.Config;
-import com.wechat.pay.java.core.RSAAutoCertificateConfig;
-import com.wechat.pay.java.core.RSAConfig;
-import com.wechat.pay.java.core.cipher.PrivacyEncryptor;
-import com.wechat.pay.java.core.notification.NotificationConfig;
-import com.wechat.pay.java.core.notification.NotificationParser;
-import com.wechat.pay.java.core.notification.RequestParam;
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
+import com.ruoyi.order.util.HuiFuTianXiaUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
-import net.bytebuddy.asm.Advice;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.BufferedReader;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
+import java.security.GeneralSecurityException;
+import java.util.Collection;
+import java.util.Enumeration;
import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
/**
* @program: ruoyi
@@ -43,90 +57,254 @@
@Api(value = "微信通知控制", tags = "微信通知控制", description = "微信通知控制")
@RestController
@RequestMapping("/app/notify")
+@Log4j2
public class NotifyController extends BaseController {
- /** 商户号 */
- public static String merchantId = "";
- /** 商户API私钥路径 */
- public static String privateKeyPath = "";
- /** 商户证书序列号 */
- public static String merchantSerialNumber = "";
- /** 微信支付平台证书路径 */
- public static String wechatPayCertificatePath = "";
- /** 商户APIV3密钥 */
- public static String apiV3key = "...";
+
+ public static final String WECHAT_PAY_SERIAL = "Wechatpay-Serial";
+ public static final String WECHAT_PAY_SIGNATURE = "Wechatpay-Signature";
+ public static final String WECHAT_PAY_TIMESTAMP = "Wechatpay-Timestamp";
+ public static final String WECHAT_PAY_NONCE = "Wechatpay-Nonce";
+
+ private static final Gson GSON = new GsonBuilder().create();
@Resource
private OrderService orderService;
- @RequestMapping(value = "/payNotify", method = RequestMethod.POST)
- @ApiOperation(value = "微信支付通知")
- public Map payNotify(HttpServletRequest request, HttpServletResponse response) {
- Config config =
- new RSAConfig.Builder()
- .merchantId(merchantId)
- .privateKeyFromPath(privateKeyPath)
- .merchantSerialNumber(merchantSerialNumber)
- .wechatPayCertificatesFromPath(wechatPayCertificatePath)
- .build();
+ @Resource
+ private WxPayService wxService;
+ @Resource
+ private BackMessageService backMessageService;
- PrivacyEncryptor encryptor = config.createEncryptor();
- String wechatPayCertificateSerialNumber = encryptor.getWechatpaySerial();
+ @Resource
+ private OrderRefundService orderRefundService;
+ @Resource
+ private RedisService redisService;
- String nonoc=request.getHeader("Wechatpay-Nonce");
- String signature=request.getHeader("Wechatpay-Signature");
- String timestamp=request.getHeader("Wechatpay-Timestamp");
- String serial=request.getHeader("Wechatpay-Serial");
- String signatureType=request.getHeader("Wechatpay-Signature-Type");
+ @PostMapping(value = "/payNotify")
+ @ApiOperation(value = "微信支付/退款通知")
+ public String payNotify(@RequestBody String notifyData, HttpServletRequest request, HttpServletResponse response) throws WxPayException {
- String requestBody="";
+ // 获取请求头
+ SignatureHeader signatureHeader = getSignatureHeader(request);
+
+ log.info("微信支付/退款通知: {}", notifyData);
+
+ NotifyResponse responseData = GSON.fromJson(notifyData, NotifyResponse.class);
+ String eventType = responseData.getEventType();
+
+ int resultType = 1;
+ String resultMessage = notifyData;
try {
- BufferedReader reader = request.getReader();
- String line = "";
- StringBuffer inputString = new StringBuffer();
- while ( (line = reader.readLine()) != null ) {
- inputString.append(line);
+ if (WxPayNotifyEventTypeEnum.TRANSACTION_SUCCESS.getCode().equals(eventType)) {
+ PartnerTransactionsNotifyResult notifyResult = wxService.getEcommerceService().parsePartnerNotifyResult(notifyData, signatureHeader);
+ PartnerTransactionsResult result = notifyResult.getResult();
+ // 支付通知回调
+ if ("SUCCESS".equals(result.getTradeState())) {
+ orderService.payBack(result, BigDecimal.ONE);
+ }
+ resultMessage = GSON.toJson(notifyResult);
+ } else if (WxPayNotifyEventTypeEnum.REFUND_SUCCESS.getCode().equals(eventType)
+ || WxPayNotifyEventTypeEnum.REFUND_ABNORMAL.getCode().equals(eventType)
+ || WxPayNotifyEventTypeEnum.REFUND_CLOSED.getCode().equals(eventType)) {
+
+ RefundNotifyResult result = this.parseRefundNotifyResult(notifyData, signatureHeader);
+ orderService.orderRefundBack(result);
+ resultType = 2;
+ resultMessage = GSON.toJson(result);
}
- if(inputString!=null && !"".equals(inputString)) {
- requestBody = inputString.toString();
- }
- reader.close();
- } catch (IOException e) {
+
+ }catch (Exception e){
e.printStackTrace();
+ log.info("微信支付/退款通知异常: {}", e.getMessage());
}
-
- RequestParam requestParam = new RequestParam.Builder()
- .serialNumber(wechatPayCertificateSerialNumber)
- .nonce(nonoc)
- .signature(signature)
- .timestamp(timestamp)
- .body(requestBody)
- .build();
-
- NotificationConfig notifiConfig = new RSAAutoCertificateConfig.Builder()
- .merchantId(merchantId)
- .privateKeyFromPath(privateKeyPath)
- .merchantSerialNumber(merchantSerialNumber)
- .apiV3Key(apiV3key)
- .build();
-
- NotificationParser parser = new NotificationParser(notifiConfig);
-
- Transaction transaction = parser.parse(requestParam, Transaction.class);
-
-
- String tradeStateEnum=transaction.getTradeState().toString();
- if(tradeStateEnum.equals("success")){
- String outTradeNo=transaction.getOutTradeNo();
- orderService.payBack(outTradeNo);
- }
-
- Map map=new HashMap();
- map.put("code","SUCCESS");
- map.put("message","成功");
-
- return map;
+ // 保存支付/退款回调信息
+ backMessageService.saveBackMessage(resultType, resultMessage);
+ return WxPayNotifyV3Response.success("成功");
}
+ @PostMapping(value = "/profitSharingNotify")
+ @ApiOperation(value = "微信分账通知")
+ public String profitSharingNotify(@RequestBody String notifyData, HttpServletRequest request, HttpServletResponse response) throws WxPayException {
+ ProfitSharingV3Service sharingV3Service = wxService.getProfitSharingV3Service();
+ // ProfitSharingNotifyResult
+ log.info("微信分账通知: {}", notifyData);
+
+ // 获取请求头
+ SignatureHeader signatureHeader = getSignatureHeader(request);
+
+ ProfitSharingNotifyNewResult notifyResult = getProfitSharingNotifyData(notifyData, signatureHeader);
+ ProfitSharingNotifyResult result = notifyResult.getResult();
+ String eventType = "-1";
+ String resultMessage = notifyData;
+ try {
+ eventType = notifyResult.getRawData().getEventType();
+ if (WxPayNotifyEventTypeEnum.PROFIT_SHARING_SUCCESS.getCode().equals(eventType)) {
+ // 分账通知回调
+ orderService.profitSharingBack(result);
+ }
+
+ resultMessage = GSON.toJson(notifyResult);
+ }catch (Exception e){
+ log.info("微信分账通知通知异常: {}", e.getMessage());
+ }
+ // 保存记录分账回调信息
+ backMessageService.saveBackMessage(3, resultMessage);
+
+ return WxPayNotifyV3Response.success("成功");
+ }
+
+ @RequestMapping(value = "/shareNotify", method = RequestMethod.POST)
+ @ApiOperation(value = "微信支付通知")
+ public Map shareNotify(HttpServletRequest request, HttpServletResponse response) {
+
+ return null;
+ }
+
+ public ProfitSharingNotifyNewResult getProfitSharingNotifyData(String notifyData, SignatureHeader header) throws WxPayException {
+ if (Objects.nonNull(header) && !this.verifyNotifySign(header, notifyData)) {
+ throw new WxPayException("非法请求,头部信息验证失败");
+ }
+ ProfitSharingNotifyData response = GSON.fromJson(notifyData, ProfitSharingNotifyData.class);
+
+ ProfitSharingNotifyData.Resource resource = response.getResource();
+ String cipherText = resource.getCipherText();
+ String associatedData = resource.getAssociatedData();
+ String nonce = resource.getNonce();
+ String apiV3Key = this.wxService.getConfig().getApiV3Key();
+ try {
+ String result = AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key);
+ ProfitSharingNotifyResult profitSharingResult = GSON.fromJson(result, ProfitSharingNotifyResult.class);
+
+ ProfitSharingNotifyNewResult notifyResult = new ProfitSharingNotifyNewResult();
+ notifyResult.setRawData(response);
+ notifyResult.setResult(profitSharingResult);
+ return notifyResult;
+ } catch (GeneralSecurityException | IOException e) {
+ throw new WxPayException("解析报文异常!", e);
+ }
+ }
+
+ private RefundNotifyResult parseRefundNotifyResult(String notifyData, SignatureHeader header) throws WxPayException {
+
+ NotifyResponse response = GSON.fromJson(notifyData, NotifyResponse.class);
+ NotifyResponse.Resource resource = response.getResource();
+ String cipherText = resource.getCiphertext();
+ String associatedData = resource.getAssociatedData();
+ String nonce = resource.getNonce();
+ String apiV3Key = this.wxService.getConfig().getApiV3Key();
+ try {
+ String result = AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key);
+ RefundNotifyResult notifyResult = GSON.fromJson(result, RefundNotifyResult.class);
+ notifyResult.setRawData(response);
+ return notifyResult;
+ } catch (GeneralSecurityException | IOException e) {
+ throw new WxPayException("解析报文异常!", e);
+ }
+ }
+
+ private boolean verifyNotifySign(SignatureHeader header, String data) throws WxPayException {
+ String beforeSign = String.format("%s\n%s\n%s\n",
+ header.getTimeStamp(),
+ header.getNonce(),
+ data);
+ Verifier verifier = this.wxService.getConfig().getVerifier();
+ if (verifier == null) {
+ throw new WxPayException("证书检验对象为空");
+ }
+ return verifier.verify(header.getSerialNo(),
+ beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned());
+ }
+
+ private SignatureHeader getSignatureHeader(HttpServletRequest request){
+ SignatureHeader signatureHeader = new SignatureHeader();
+ signatureHeader.setSerialNo(request.getHeader(WECHAT_PAY_SERIAL));
+ signatureHeader.setSigned(request.getHeader(WECHAT_PAY_SIGNATURE));
+ signatureHeader.setNonce(request.getHeader(WECHAT_PAY_NONCE));
+ signatureHeader.setTimeStamp(request.getHeader(WECHAT_PAY_TIMESTAMP));
+
+ log.info("timeStamp:{} nonce : {} signed:{} serialNo:{}",
+ signatureHeader.getTimeStamp(),
+ signatureHeader.getNonce(),
+ signatureHeader.getSigned(),
+ signatureHeader.getSerialNo());
+
+ return signatureHeader;
+ }
+
+
+
+ @RequestMapping(value = "/wechatPaymentCallback", method = RequestMethod.POST)
+ @ApiOperation(value = "微信支付通知(汇付天下)")
+ public void wechatPaymentCallback(WeixinPaymentNotifyDto dto, HttpServletResponse response){
+ R<WeixinPaymentNotifyVo> r = HuiFuTianXiaUtil.weixinPaymentNotify(dto);
+ if(r.getCode() == 200){
+ WeixinPaymentNotifyVo data = r.getData();
+ String transStat = data.getTransStat();
+ if("S".equals(transStat)){
+ PartnerTransactionsResult transaction = new PartnerTransactionsResult();
+ transaction.setOutTradeNo(data.getReqSeqId());
+
+ //防止回调频繁导致时间处理异常
+ Object cacheObject = redisService.getCacheObject(data.getReqSeqId());
+ if(null == cacheObject){
+ redisService.setCacheObject(data.getReqSeqId(), "", 10L, TimeUnit.SECONDS);
+ }else{
+ return;
+ }
+ //开始处理业务数据
+ orderService.payBack(transaction, data.getFeeFlag() == 1 ? BigDecimal.ZERO : new BigDecimal(data.getFeeAmount()));
+
+ response.setStatus(200);
+ PrintWriter out = null;
+ try {
+ out = response.getWriter();
+ out.print("RECV_ORD_ID_" + data.getReqSeqId());
+ out.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }finally {
+ out.close();
+ }
+
+ }
+ }
+ }
+
+
+
+ @RequestMapping(value = "/wechatPaymentRefundCallback", method = RequestMethod.POST)
+ @ApiOperation(value = "微信支付退款通知(汇付天下)")
+ public void wechatPaymentRefundCallback(WechatPaymentRefundDto dto, HttpServletResponse response){
+ R<WeixinPaymentRefundVo> r = HuiFuTianXiaUtil.weixinPaymentRefundNotify(dto);
+ if(r.getCode() == 200){
+ WeixinPaymentRefundVo data = r.getData();
+ String transStat = data.getTransStat();
+ if("S".equals(transStat)){
+ //开始处理业务数据
+ String reqSeqId = data.getReqSeqId();
+ OrderRefund orderRefund = orderRefundService.getById(reqSeqId);
+ if(null != orderRefund && orderRefund.getRefundStatus() != 2){
+ orderRefund.setWxRefundId(data.getPartyOrderId());
+ orderRefund.setBackTime(data.getTransDate() + data.getTransTime());
+ orderRefund.setRefundStatus(2);
+ orderRefundService.saveOrUpdate(orderRefund);
+ }
+
+ response.setStatus(200);
+ PrintWriter out = null;
+ try {
+ out = response.getWriter();
+ out.print("RECV_ORD_ID_" + data.getReqSeqId());
+ out.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }finally {
+ out.close();
+ }
+
+ }
+ }
+ }
}
--
Gitblit v1.7.1