From beeda8df0023376dbb2021148a021731dc4aedb0 Mon Sep 17 00:00:00 2001 From: jiangqs <jiangqs> Date: 星期日, 06 八月 2023 11:29:10 +0800 Subject: [PATCH] Merge branch 'master' of ssh://sinata.cn:20202/java/HongRuiTang into master --- ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java | 219 +++++++++++++++++++++++++++++++----------------------- 1 files changed, 127 insertions(+), 92 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 5dc6de6..775d9da 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,34 @@ package com.ruoyi.order.controller.miniapp; -import com.ruoyi.common.core.domain.R; +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.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.order.domain.vo.ProfitSharingNotifyNewResult; +import com.ruoyi.order.enums.WxPayNotifyEventTypeEnum; +import com.ruoyi.order.service.account.BackMessageService; 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 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 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.nio.charset.StandardCharsets; -import java.util.HashMap; +import java.security.GeneralSecurityException; import java.util.Map; +import java.util.Objects; /** * @program: ruoyi @@ -44,88 +40,82 @@ @RestController @RequestMapping("/app/notify") 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(); + @Autowired + private WxPayService wxService; + @Resource + private BackMessageService backMessageService; - PrivacyEncryptor encryptor = config.createEncryptor(); - String wechatPayCertificateSerialNumber = encryptor.getWechatpaySerial(); + @PostMapping(value = "/payNotify") + @ApiOperation(value = "微信支付/退款通知") + public String payNotify(@RequestBody String notifyData, HttpServletRequest request, HttpServletResponse response) throws WxPayException { + // 获取请求头 + SignatureHeader signatureHeader = getSignatureHeader(response); - 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"); + NotifyResponse responseData = GSON.fromJson(notifyData, NotifyResponse.class); + String eventType = responseData.getEventType(); - String requestBody=""; - - try { - BufferedReader reader = request.getReader(); - String line = ""; - StringBuffer inputString = new StringBuffer(); - while ( (line = reader.readLine()) != null ) { - inputString.append(line); + int resultType = 1; + String resultMessage = ""; + 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); } - if(inputString!=null && !"".equals(inputString)) { - requestBody = inputString.toString(); - } - reader.close(); - } catch (IOException e) { - e.printStackTrace(); + 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 = wxService.getEcommerceService().parseRefundNotifyResult(notifyData, signatureHeader); + orderService.orderRefundBack(result); + resultType = 2; + resultMessage = GSON.toJson(result); + } + // 保存支付/退款回调信息 + 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 + + // 获取请求头 + SignatureHeader signatureHeader = getSignatureHeader(response); + + + ProfitSharingNotifyNewResult notifyResult = getProfitSharingNotifyData(notifyData, signatureHeader); + ProfitSharingNotifyResult result = notifyResult.getResult(); + + String eventType = notifyResult.getRawData().getEventType(); + if(WxPayNotifyEventTypeEnum.PROFIT_SHARING_SUCCESS.getCode().equals(eventType)){ + // 分账通知回调 + orderService.profitSharingBack(result); } - RequestParam requestParam = new RequestParam.Builder() - .serialNumber(wechatPayCertificateSerialNumber) - .nonce(nonoc) - .signature(signature) - .timestamp(timestamp) - .body(requestBody) - .build(); + String resultMessage = GSON.toJson(notifyResult); + // 保存记录分账回调信息 + backMessageService.saveBackMessage(3, resultMessage); - 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")){ - orderService.payBack(transaction); - } - - Map map=new HashMap(); - map.put("code","SUCCESS"); - map.put("message","成功"); - - return map; + return WxPayNotifyV3Response.success("成功"); } @RequestMapping(value = "/shareNotify", method = RequestMethod.POST) @@ -135,4 +125,49 @@ 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 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(HttpServletResponse response){ + SignatureHeader signatureHeader = new SignatureHeader(); + signatureHeader.setSerialNo(response.getHeader(WECHAT_PAY_SERIAL)); + signatureHeader.setSigned(response.getHeader(WECHAT_PAY_SIGNATURE)); + signatureHeader.setNonce(response.getHeader(WECHAT_PAY_NONCE)); + signatureHeader.setTimeStamp(response.getHeader(WECHAT_PAY_TIMESTAMP)); + return signatureHeader; + } } -- Gitblit v1.7.1