bug
jiangqs
2023-08-16 2e9c442b4961dc30423e8b8fa1361c45e63ef620
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package com.ruoyi.order.controller.miniapp;
 
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.vo.ProfitSharingNotifyNewResult;
import com.ruoyi.order.enums.WxPayNotifyEventTypeEnum;
import com.ruoyi.order.service.account.BackMessageService;
import com.ruoyi.order.service.order.OrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.Objects;
 
/**
 * @program: ruoyi
 * @author: linqingsong
 * @create: 2023-07-22 17:20
 * @description: 成都软思同创科技有限公司
 **/
@Api(value = "微信通知控制", tags = "微信通知控制", description = "微信通知控制")
@RestController
@RequestMapping("/app/notify")
public class NotifyController extends BaseController {
 
    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;
 
    @Autowired
    private WxPayService wxService;
    @Resource
    private BackMessageService backMessageService;
 
    @PostMapping(value = "/payNotify")
    @ApiOperation(value = "微信支付/退款通知")
    public String payNotify(@RequestBody String notifyData, HttpServletRequest request, HttpServletResponse response) throws WxPayException {
 
        // 获取请求头
        SignatureHeader signatureHeader = getSignatureHeader(response);
 
        NotifyResponse responseData = GSON.fromJson(notifyData, NotifyResponse.class);
        String eventType = responseData.getEventType();
 
        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);
            }
            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);
        }
 
        String resultMessage = GSON.toJson(notifyResult);
        // 保存记录分账回调信息
        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 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;
    }
}