Commit a2bfa7a95aede05244f41cccf21ccef194fc1f77

Authored by YunaiV
1 parent 59234e1e

feat:weixin-java from 4.7.2.B => 4.7.4.B

feat:微信支付 v3 从平台证书切换成微信支付公钥
feat:微信支付 v3 增加 header 解析
yudao-dependencies/pom.xml
@@ -75,7 +75,7 @@ @@ -75,7 +75,7 @@
75 <justauth.version>1.16.7</justauth.version> 75 <justauth.version>1.16.7</justauth.version>
76 <justauth-starter.version>1.4.0</justauth-starter.version> 76 <justauth-starter.version>1.4.0</justauth-starter.version>
77 <jimureport.version>1.9.4</jimureport.version> 77 <jimureport.version>1.9.4</jimureport.version>
78 - <weixin-java.version>4.7.2.B</weixin-java.version> 78 + <weixin-java.version>4.7.4.B</weixin-java.version>
79 </properties> 79 </properties>
80 80
81 <dependencyManagement> 81 <dependencyManagement>
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
@@ -66,7 +66,8 @@ public class PayNotifyController { @@ -66,7 +66,8 @@ public class PayNotifyController {
66 @TenantIgnore 66 @TenantIgnore
67 public String notifyOrder(@PathVariable("channelId") Long channelId, 67 public String notifyOrder(@PathVariable("channelId") Long channelId,
68 @RequestParam(required = false) Map<String, String> params, 68 @RequestParam(required = false) Map<String, String> params,
69 - @RequestBody(required = false) String body) { 69 + @RequestBody(required = false) String body,
  70 + @RequestHeader Map<String, String> headers) {
70 log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body); 71 log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body);
71 // 1. 校验支付渠道是否存在 72 // 1. 校验支付渠道是否存在
72 PayClient payClient = channelService.getPayClient(channelId); 73 PayClient payClient = channelService.getPayClient(channelId);
@@ -76,7 +77,7 @@ public class PayNotifyController { @@ -76,7 +77,7 @@ public class PayNotifyController {
76 } 77 }
77 78
78 // 2. 解析通知数据 79 // 2. 解析通知数据
79 - PayOrderRespDTO notify = payClient.parseOrderNotify(params, body); 80 + PayOrderRespDTO notify = payClient.parseOrderNotify(params, body, headers);
80 orderService.notifyOrder(channelId, notify); 81 orderService.notifyOrder(channelId, notify);
81 return "success"; 82 return "success";
82 } 83 }
@@ -87,7 +88,8 @@ public class PayNotifyController { @@ -87,7 +88,8 @@ public class PayNotifyController {
87 @TenantIgnore 88 @TenantIgnore
88 public String notifyRefund(@PathVariable("channelId") Long channelId, 89 public String notifyRefund(@PathVariable("channelId") Long channelId,
89 @RequestParam(required = false) Map<String, String> params, 90 @RequestParam(required = false) Map<String, String> params,
90 - @RequestBody(required = false) String body) { 91 + @RequestBody(required = false) String body,
  92 + @RequestHeader Map<String, String> headers) {
91 log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body); 93 log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body);
92 // 1. 校验支付渠道是否存在 94 // 1. 校验支付渠道是否存在
93 PayClient payClient = channelService.getPayClient(channelId); 95 PayClient payClient = channelService.getPayClient(channelId);
@@ -97,7 +99,7 @@ public class PayNotifyController { @@ -97,7 +99,7 @@ public class PayNotifyController {
97 } 99 }
98 100
99 // 2. 解析通知数据 101 // 2. 解析通知数据
100 - PayRefundRespDTO notify = payClient.parseRefundNotify(params, body); 102 + PayRefundRespDTO notify = payClient.parseRefundNotify(params, body, headers);
101 refundService.notifyRefund(channelId, notify); 103 refundService.notifyRefund(channelId, notify);
102 return "success"; 104 return "success";
103 } 105 }
@@ -108,7 +110,8 @@ public class PayNotifyController { @@ -108,7 +110,8 @@ public class PayNotifyController {
108 @TenantIgnore 110 @TenantIgnore
109 public String notifyTransfer(@PathVariable("channelId") Long channelId, 111 public String notifyTransfer(@PathVariable("channelId") Long channelId,
110 @RequestParam(required = false) Map<String, String> params, 112 @RequestParam(required = false) Map<String, String> params,
111 - @RequestBody(required = false) String body) { 113 + @RequestBody(required = false) String body,
  114 + @RequestHeader Map<String, String> headers) {
112 log.info("[notifyTransfer][channelId({}) 回调数据({}/{})]", channelId, params, body); 115 log.info("[notifyTransfer][channelId({}) 回调数据({}/{})]", channelId, params, body);
113 // 1. 校验支付渠道是否存在 116 // 1. 校验支付渠道是否存在
114 PayClient payClient = channelService.getPayClient(channelId); 117 PayClient payClient = channelService.getPayClient(channelId);
@@ -118,7 +121,7 @@ public class PayNotifyController { @@ -118,7 +121,7 @@ public class PayNotifyController {
118 } 121 }
119 122
120 // 2. 解析通知数据 123 // 2. 解析通知数据
121 - PayTransferRespDTO notify = payClient.parseTransferNotify(params, body); 124 + PayTransferRespDTO notify = payClient.parseTransferNotify(params, body, headers);
122 payTransferService.notifyTransfer(channelId, notify); 125 payTransferService.notifyTransfer(channelId, notify);
123 return "success"; 126 return "success";
124 } 127 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
@@ -89,7 +89,7 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -89,7 +89,7 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
89 } 89 }
90 90
91 @Override 91 @Override
92 - protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) { 92 + protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) {
93 throw new UnsupportedOperationException("钱包支付无支付回调"); 93 throw new UnsupportedOperationException("钱包支付无支付回调");
94 } 94 }
95 95
@@ -144,7 +144,7 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -144,7 +144,7 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
144 } 144 }
145 145
146 @Override 146 @Override
147 - protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) { 147 + protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
148 throw new UnsupportedOperationException("钱包支付无退款回调"); 148 throw new UnsupportedOperationException("钱包支付无退款回调");
149 } 149 }
150 150
@@ -178,7 +178,7 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -178,7 +178,7 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
178 } 178 }
179 179
180 @Override 180 @Override
181 - protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable { 181 + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
182 throw new UnsupportedOperationException("未实现"); 182 throw new UnsupportedOperationException("未实现");
183 } 183 }
184 184
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
@@ -39,9 +39,10 @@ public interface PayClient { @@ -39,9 +39,10 @@ public interface PayClient {
39 * 39 *
40 * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 40 * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
41 * @param body HTTP 回调接口的 request body 41 * @param body HTTP 回调接口的 request body
  42 + * @param headers HTTP 回调接口的 request headers
42 * @return 支付订单信息 43 * @return 支付订单信息
43 */ 44 */
44 - PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body); 45 + PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body, Map<String, String> headers);
45 46
46 /** 47 /**
47 * 获得支付订单信息 48 * 获得支付订单信息
@@ -66,9 +67,10 @@ public interface PayClient { @@ -66,9 +67,10 @@ public interface PayClient {
66 * 67 *
67 * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 68 * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
68 * @param body HTTP 回调接口的 request body 69 * @param body HTTP 回调接口的 request body
  70 + * @param headers HTTP 回调接口的 request headers
69 * @return 支付订单信息 71 * @return 支付订单信息
70 */ 72 */
71 - PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body); 73 + PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body, Map<String, String> headers);
72 74
73 /** 75 /**
74 * 获得退款订单信息 76 * 获得退款订单信息
@@ -103,8 +105,9 @@ public interface PayClient { @@ -103,8 +105,9 @@ public interface PayClient {
103 * 105 *
104 * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 106 * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
105 * @param body HTTP 回调接口的 request body 107 * @param body HTTP 回调接口的 request body
  108 + * @param headers HTTP 回调接口的 request headers
106 * @return 转账信息 109 * @return 转账信息
107 */ 110 */
108 - PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body); 111 + PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body, Map<String, String> headers);
109 112
110 } 113 }
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java
1 package cn.iocoder.yudao.framework.pay.core.client; 1 package cn.iocoder.yudao.framework.pay.core.client;
2 2
  3 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
3 import com.fasterxml.jackson.annotation.JsonTypeInfo; 4 import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 -  
5 import jakarta.validation.Validator; 5 import jakarta.validation.Validator;
6 6
7 /** 7 /**
@@ -14,6 +14,7 @@ import jakarta.validation.Validator; @@ -14,6 +14,7 @@ import jakarta.validation.Validator;
14 // @JsonTypeInfo 注解的作用,Jackson 多态 14 // @JsonTypeInfo 注解的作用,Jackson 多态
15 // 1. 序列化到时数据库时,增加 @class 属性。 15 // 1. 序列化到时数据库时,增加 @class 属性。
16 // 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 16 // 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型
  17 +@JsonIgnoreProperties(ignoreUnknown = true) // 目的:忽略未知的属性,避免反序列化失败
17 public interface PayClientConfig { 18 public interface PayClientConfig {
18 19
19 /** 20 /**
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
@@ -101,19 +101,19 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -101,19 +101,19 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
101 throws Throwable; 101 throws Throwable;
102 102
103 @Override 103 @Override
104 - public final PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) { 104 + public final PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) {
105 try { 105 try {
106 - return doParseOrderNotify(params, body); 106 + return doParseOrderNotify(params, body, headers);
107 } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 107 } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
108 throw ex; 108 throw ex;
109 } catch (Throwable ex) { 109 } catch (Throwable ex) {
110 - log.error("[parseOrderNotify][客户端({}) params({}) body({}) 解析失败]",  
111 - getId(), params, body, ex); 110 + log.error("[parseOrderNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
  111 + getId(), params, body, headers, ex);
112 throw buildPayException(ex); 112 throw buildPayException(ex);
113 } 113 }
114 } 114 }
115 115
116 - protected abstract PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) 116 + protected abstract PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers)
117 throws Throwable; 117 throws Throwable;
118 118
119 @Override 119 @Override
@@ -155,19 +155,19 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -155,19 +155,19 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
155 protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; 155 protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
156 156
157 @Override 157 @Override
158 - public final PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) { 158 + public final PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
159 try { 159 try {
160 - return doParseRefundNotify(params, body); 160 + return doParseRefundNotify(params, body, headers);
161 } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 161 } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
162 throw ex; 162 throw ex;
163 } catch (Throwable ex) { 163 } catch (Throwable ex) {
164 - log.error("[parseRefundNotify][客户端({}) params({}) body({}) 解析失败]",  
165 - getId(), params, body, ex); 164 + log.error("[parseRefundNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
  165 + getId(), params, body, headers, ex);
166 throw buildPayException(ex); 166 throw buildPayException(ex);
167 } 167 }
168 } 168 }
169 169
170 - protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) 170 + protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers)
171 throws Throwable; 171 throws Throwable;
172 172
173 @Override 173 @Override
@@ -220,19 +220,19 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -220,19 +220,19 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
220 } 220 }
221 221
222 @Override 222 @Override
223 - public final PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body) { 223 + public final PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
224 try { 224 try {
225 - return doParseTransferNotify(params, body); 225 + return doParseTransferNotify(params, body, headers);
226 } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 226 } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
227 throw ex; 227 throw ex;
228 } catch (Throwable ex) { 228 } catch (Throwable ex) {
229 - log.error("[doParseTransferNotify][客户端({}) params({}) body({}) 解析失败]",  
230 - getId(), params, body, ex); 229 + log.error("[doParseTransferNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
  230 + getId(), params, body, headers, ex);
231 throw buildPayException(ex); 231 throw buildPayException(ex);
232 } 232 }
233 } 233 }
234 234
235 - protected abstract PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) 235 + protected abstract PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers)
236 throws Throwable; 236 throws Throwable;
237 237
238 @Override 238 @Override
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
@@ -79,7 +79,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -79,7 +79,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
79 } 79 }
80 80
81 @Override 81 @Override
82 - public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) throws Throwable { 82 + public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) throws Throwable {
83 // 1. 校验回调数据 83 // 1. 校验回调数据
84 Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); 84 Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
85 AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(), 85 AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(),
@@ -175,7 +175,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -175,7 +175,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
175 } 175 }
176 176
177 @Override 177 @Override
178 - public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) { 178 + public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
179 // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。 179 // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。
180 // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调 180 // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调
181 // ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有 181 // ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有
@@ -327,7 +327,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -327,7 +327,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
327 327
328 // TODO @chihuo:这里是不是也要实现,支付宝的。 328 // TODO @chihuo:这里是不是也要实现,支付宝的。
329 @Override 329 @Override
330 - protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable { 330 + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
331 throw new UnsupportedOperationException("未实现"); 331 throw new UnsupportedOperationException("未实现");
332 } 332 }
333 333
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
@@ -58,17 +58,17 @@ public class MockPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -58,17 +58,17 @@ public class MockPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
58 } 58 }
59 59
60 @Override 60 @Override
61 - protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable { 61 + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
62 throw new UnsupportedOperationException("未实现"); 62 throw new UnsupportedOperationException("未实现");
63 } 63 }
64 64
65 @Override 65 @Override
66 - protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) { 66 + protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
67 throw new UnsupportedOperationException("模拟支付无退款回调"); 67 throw new UnsupportedOperationException("模拟支付无退款回调");
68 } 68 }
69 69
70 @Override 70 @Override
71 - protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) { 71 + protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) {
72 throw new UnsupportedOperationException("模拟支付无支付回调"); 72 throw new UnsupportedOperationException("模拟支付无支付回调");
73 } 73 }
74 74
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
@@ -18,10 +18,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.WxPayTransferPart @@ -18,10 +18,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.WxPayTransferPart
18 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 18 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
19 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; 19 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
20 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; 20 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
21 -import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;  
22 -import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;  
23 -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;  
24 -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result; 21 +import com.github.binarywang.wxpay.bean.notify.*;
25 import com.github.binarywang.wxpay.bean.request.*; 22 import com.github.binarywang.wxpay.bean.request.*;
26 import com.github.binarywang.wxpay.bean.result.*; 23 import com.github.binarywang.wxpay.bean.result.*;
27 import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest; 24 import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest;
@@ -67,13 +64,14 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -67,13 +64,14 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
67 protected void doInit(String tradeType) { 64 protected void doInit(String tradeType) {
68 // 创建 config 配置 65 // 创建 config 配置
69 WxPayConfig payConfig = new WxPayConfig(); 66 WxPayConfig payConfig = new WxPayConfig();
70 - BeanUtil.copyProperties(config, payConfig, "keyContent", "privateKeyContent"); 67 + BeanUtil.copyProperties(config, payConfig, "keyContent", "privateKeyContent", "publicKeyContent");
71 payConfig.setTradeType(tradeType); 68 payConfig.setTradeType(tradeType);
72 // weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决 69 // weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决
73 if (Objects.equals(config.getApiVersion(), API_VERSION_V2)) { 70 if (Objects.equals(config.getApiVersion(), API_VERSION_V2)) {
74 payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath()); 71 payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath());
75 } else if (Objects.equals(config.getApiVersion(), API_VERSION_V3)) { 72 } else if (Objects.equals(config.getApiVersion(), API_VERSION_V3)) {
76 payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath()); 73 payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath());
  74 + payConfig.setPublicKeyPath(FileUtils.createTempFile(config.getPublicKeyContent()).getPath());
77 } 75 }
78 76
79 // 创建 client 客户端 77 // 创建 client 客户端
@@ -157,12 +155,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -157,12 +155,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
157 } 155 }
158 156
159 @Override 157 @Override
160 - public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) throws WxPayException { 158 + public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) throws WxPayException {
161 switch (config.getApiVersion()) { 159 switch (config.getApiVersion()) {
162 case API_VERSION_V2: 160 case API_VERSION_V2:
163 return doParseOrderNotifyV2(body); 161 return doParseOrderNotifyV2(body);
164 case API_VERSION_V3: 162 case API_VERSION_V3:
165 - return doParseOrderNotifyV3(body); 163 + return doParseOrderNotifyV3(body, headers);
166 default: 164 default:
167 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); 165 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
168 } 166 }
@@ -179,9 +177,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -179,9 +177,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
179 response.getOutTradeNo(), body); 177 response.getOutTradeNo(), body);
180 } 178 }
181 179
182 - private PayOrderRespDTO doParseOrderNotifyV3(String body) throws WxPayException { 180 + private PayOrderRespDTO doParseOrderNotifyV3(String body, Map<String, String> headers) throws WxPayException {
183 // 1. 解析回调 181 // 1. 解析回调
184 - WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, null); 182 + SignatureHeader signatureHeader = getRequestHeader(headers);
  183 + WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, signatureHeader);
185 WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult(); 184 WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult();
186 // 2. 构建结果 185 // 2. 构建结果
187 Integer status = parseStatus(result.getTradeState()); 186 Integer status = parseStatus(result.getTradeState());
@@ -321,12 +320,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -321,12 +320,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
321 } 320 }
322 321
323 @Override 322 @Override
324 - public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) throws WxPayException { 323 + public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) throws WxPayException {
325 switch (config.getApiVersion()) { 324 switch (config.getApiVersion()) {
326 case API_VERSION_V2: 325 case API_VERSION_V2:
327 return doParseRefundNotifyV2(body); 326 return doParseRefundNotifyV2(body);
328 case API_VERSION_V3: 327 case API_VERSION_V3:
329 - return parseRefundNotifyV3(body); 328 + return parseRefundNotifyV3(body, headers);
330 default: 329 default:
331 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); 330 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
332 } 331 }
@@ -344,9 +343,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -344,9 +343,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
344 return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); 343 return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
345 } 344 }
346 345
347 - private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException { 346 + private PayRefundRespDTO parseRefundNotifyV3(String body, Map<String, String> headers) throws WxPayException {
348 // 1. 解析回调 347 // 1. 解析回调
349 - WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null); 348 + SignatureHeader signatureHeader = getRequestHeader(headers);
  349 + WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, signatureHeader);
350 WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult(); 350 WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult();
351 // 2. 构建结果 351 // 2. 构建结果
352 if (Objects.equals("SUCCESS", result.getRefundStatus())) { 352 if (Objects.equals("SUCCESS", result.getRefundStatus())) {
@@ -357,10 +357,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -357,10 +357,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
357 } 357 }
358 358
359 @Override 359 @Override
360 - public PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws WxPayException { 360 + public PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) throws WxPayException {
361 switch (config.getApiVersion()) { 361 switch (config.getApiVersion()) {
362 case API_VERSION_V3: 362 case API_VERSION_V3:
363 - return parseTransferNotifyV3(body); 363 + return parseTransferNotifyV3(body, headers);
364 case API_VERSION_V2: 364 case API_VERSION_V2:
365 throw new UnsupportedOperationException("V2 版本暂不支持,建议使用 V3 版本"); 365 throw new UnsupportedOperationException("V2 版本暂不支持,建议使用 V3 版本");
366 default: 366 default:
@@ -368,10 +368,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -368,10 +368,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
368 } 368 }
369 } 369 }
370 370
371 - private PayTransferRespDTO parseTransferNotifyV3(String body) throws WxPayException { 371 + private PayTransferRespDTO parseTransferNotifyV3(String body, Map<String, String> headers) throws WxPayException {
372 // 1. 解析回调 372 // 1. 解析回调
  373 + SignatureHeader signatureHeader = getRequestHeader(headers);
373 // TODO @luchi:这个可以复用 wxjava 里的类么? 374 // TODO @luchi:这个可以复用 wxjava 里的类么?
374 - WxPayTransferPartnerNotifyV3Result response = client.baseParseOrderNotifyV3Result(body, null, WxPayTransferPartnerNotifyV3Result.class, WxPayTransferPartnerNotifyV3Result.TransferNotifyResult.class); 375 + WxPayTransferPartnerNotifyV3Result response = client.baseParseOrderNotifyV3Result(body, signatureHeader, WxPayTransferPartnerNotifyV3Result.class, WxPayTransferPartnerNotifyV3Result.TransferNotifyResult.class);
375 WxPayTransferPartnerNotifyV3Result.TransferNotifyResult result = response.getResult(); 376 WxPayTransferPartnerNotifyV3Result.TransferNotifyResult result = response.getResult();
376 // 2. 构建结果 377 // 2. 构建结果
377 if (Objects.equals("FINISHED", result.getBatchStatus())) { 378 if (Objects.equals("FINISHED", result.getBatchStatus())) {
@@ -513,6 +514,20 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -513,6 +514,20 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
513 514
514 // ========== 各种工具方法 ========== 515 // ========== 各种工具方法 ==========
515 516
  517 + /**
  518 + * 组装请求头重的签名信息
  519 + *
  520 + * @see <a href="https://github.com/binarywang/weixin-java-pay-demo/blob/master/src/main/java/com/github/binarywang/demo/wx/pay/controller/WxPayV3Controller.java#L202-L221">官方示例</a>
  521 + */
  522 + private SignatureHeader getRequestHeader(Map<String, String> headers) {
  523 + return SignatureHeader.builder()
  524 + .signature(headers.get("wechatpay-signature"))
  525 + .nonce(headers.get("wechatpay-nonce"))
  526 + .serial(headers.get("wechatpay-serial"))
  527 + .timeStamp(headers.get("wechatpay-timestamp"))
  528 + .build();
  529 + }
  530 +
516 static String formatDateV2(LocalDateTime time) { 531 static String formatDateV2(LocalDateTime time) {
517 return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN); 532 return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN);
518 } 533 }
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java
@@ -73,13 +73,18 @@ public class WxPayClientConfig implements PayClientConfig { @@ -73,13 +73,18 @@ public class WxPayClientConfig implements PayClientConfig {
73 @NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class) 73 @NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class)
74 private String apiV3Key; 74 private String apiV3Key;
75 /** 75 /**
76 - * 证书序列号 76 + * 证书序列号(merchantSerialNumber)
77 */ 77 */
78 @NotBlank(message = "证书序列号不能为空", groups = V3.class) 78 @NotBlank(message = "证书序列号不能为空", groups = V3.class)
79 private String certSerialNo; 79 private String certSerialNo;
80 80
81 - @Deprecated // TODO 芋艿:V2.3.0 进行移除  
82 - private String privateCertContent; 81 + /**
  82 + * pub_key.pem 证书文件的对应字符串
  83 + */
  84 + @NotBlank(message = "pub_key.pem 不能为空", groups = V3.class)
  85 + private String publicKeyContent;
  86 + @NotBlank(message = "publicKeyId 不能为空", groups = V3.class)
  87 + private String publicKeyId;
83 88
84 /** 89 /**
85 * 分组校验 v2版本 90 * 分组校验 v2版本