diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index d05b01b3f9..bf16cd37d4 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -75,7 +75,7 @@
1.16.7
1.4.0
1.9.4
- 4.7.2.B
+ 4.7.4.B
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
index 9f1738ca26..3c1a86ec8f 100644
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
+++ b/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 {
@TenantIgnore
public String notifyOrder(@PathVariable("channelId") Long channelId,
@RequestParam(required = false) Map params,
- @RequestBody(required = false) String body) {
+ @RequestBody(required = false) String body,
+ @RequestHeader Map headers) {
log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body);
// 1. 校验支付渠道是否存在
PayClient payClient = channelService.getPayClient(channelId);
@@ -76,7 +77,7 @@ public class PayNotifyController {
}
// 2. 解析通知数据
- PayOrderRespDTO notify = payClient.parseOrderNotify(params, body);
+ PayOrderRespDTO notify = payClient.parseOrderNotify(params, body, headers);
orderService.notifyOrder(channelId, notify);
return "success";
}
@@ -87,7 +88,8 @@ public class PayNotifyController {
@TenantIgnore
public String notifyRefund(@PathVariable("channelId") Long channelId,
@RequestParam(required = false) Map params,
- @RequestBody(required = false) String body) {
+ @RequestBody(required = false) String body,
+ @RequestHeader Map headers) {
log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body);
// 1. 校验支付渠道是否存在
PayClient payClient = channelService.getPayClient(channelId);
@@ -97,7 +99,7 @@ public class PayNotifyController {
}
// 2. 解析通知数据
- PayRefundRespDTO notify = payClient.parseRefundNotify(params, body);
+ PayRefundRespDTO notify = payClient.parseRefundNotify(params, body, headers);
refundService.notifyRefund(channelId, notify);
return "success";
}
@@ -108,7 +110,8 @@ public class PayNotifyController {
@TenantIgnore
public String notifyTransfer(@PathVariable("channelId") Long channelId,
@RequestParam(required = false) Map params,
- @RequestBody(required = false) String body) {
+ @RequestBody(required = false) String body,
+ @RequestHeader Map headers) {
log.info("[notifyTransfer][channelId({}) 回调数据({}/{})]", channelId, params, body);
// 1. 校验支付渠道是否存在
PayClient payClient = channelService.getPayClient(channelId);
@@ -118,7 +121,7 @@ public class PayNotifyController {
}
// 2. 解析通知数据
- PayTransferRespDTO notify = payClient.parseTransferNotify(params, body);
+ PayTransferRespDTO notify = payClient.parseTransferNotify(params, body, headers);
payTransferService.notifyTransfer(channelId, notify);
return "success";
}
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
index 63fc92ba3c..2dd5893fd8 100644
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
+++ b/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 {
}
@Override
- protected PayOrderRespDTO doParseOrderNotify(Map params, String body) {
+ protected PayOrderRespDTO doParseOrderNotify(Map params, String body, Map headers) {
throw new UnsupportedOperationException("钱包支付无支付回调");
}
@@ -144,7 +144,7 @@ public class WalletPayClient extends AbstractPayClient {
}
@Override
- protected PayRefundRespDTO doParseRefundNotify(Map params, String body) {
+ protected PayRefundRespDTO doParseRefundNotify(Map params, String body, Map headers) {
throw new UnsupportedOperationException("钱包支付无退款回调");
}
@@ -178,7 +178,7 @@ public class WalletPayClient extends AbstractPayClient {
}
@Override
- protected PayTransferRespDTO doParseTransferNotify(Map params, String body) throws Throwable {
+ protected PayTransferRespDTO doParseTransferNotify(Map params, String body, Map headers) {
throw new UnsupportedOperationException("未实现");
}
diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
index 816b6fef72..64a56a5ca3 100644
--- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
+++ b/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 {
*
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
* @param body HTTP 回调接口的 request body
+ * @param headers HTTP 回调接口的 request headers
* @return 支付订单信息
*/
- PayOrderRespDTO parseOrderNotify(Map params, String body);
+ PayOrderRespDTO parseOrderNotify(Map params, String body, Map headers);
/**
* 获得支付订单信息
@@ -66,9 +67,10 @@ public interface PayClient {
*
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
* @param body HTTP 回调接口的 request body
+ * @param headers HTTP 回调接口的 request headers
* @return 支付订单信息
*/
- PayRefundRespDTO parseRefundNotify(Map params, String body);
+ PayRefundRespDTO parseRefundNotify(Map params, String body, Map headers);
/**
* 获得退款订单信息
@@ -103,8 +105,9 @@ public interface PayClient {
*
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
* @param body HTTP 回调接口的 request body
+ * @param headers HTTP 回调接口的 request headers
* @return 转账信息
*/
- PayTransferRespDTO parseTransferNotify(Map params, String body);
+ PayTransferRespDTO parseTransferNotify(Map params, String body, Map headers);
}
diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java
index beb3b41655..9df52cd61c 100644
--- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java
+++ b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java
@@ -1,7 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
import jakarta.validation.Validator;
/**
@@ -14,6 +14,7 @@ import jakarta.validation.Validator;
// @JsonTypeInfo 注解的作用,Jackson 多态
// 1. 序列化到时数据库时,增加 @class 属性。
// 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型
+@JsonIgnoreProperties(ignoreUnknown = true) // 目的:忽略未知的属性,避免反序列化失败
public interface PayClientConfig {
/**
diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
index 5c47504026..a478d4e629 100644
--- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
+++ b/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 implemen
throws Throwable;
@Override
- public final PayOrderRespDTO parseOrderNotify(Map params, String body) {
+ public final PayOrderRespDTO parseOrderNotify(Map params, String body, Map headers) {
try {
- return doParseOrderNotify(params, body);
+ return doParseOrderNotify(params, body, headers);
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
throw ex;
} catch (Throwable ex) {
- log.error("[parseOrderNotify][客户端({}) params({}) body({}) 解析失败]",
- getId(), params, body, ex);
+ log.error("[parseOrderNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
+ getId(), params, body, headers, ex);
throw buildPayException(ex);
}
}
- protected abstract PayOrderRespDTO doParseOrderNotify(Map params, String body)
+ protected abstract PayOrderRespDTO doParseOrderNotify(Map params, String body, Map headers)
throws Throwable;
@Override
@@ -155,19 +155,19 @@ public abstract class AbstractPayClient implemen
protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
@Override
- public final PayRefundRespDTO parseRefundNotify(Map params, String body) {
+ public final PayRefundRespDTO parseRefundNotify(Map params, String body, Map headers) {
try {
- return doParseRefundNotify(params, body);
+ return doParseRefundNotify(params, body, headers);
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
throw ex;
} catch (Throwable ex) {
- log.error("[parseRefundNotify][客户端({}) params({}) body({}) 解析失败]",
- getId(), params, body, ex);
+ log.error("[parseRefundNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
+ getId(), params, body, headers, ex);
throw buildPayException(ex);
}
}
- protected abstract PayRefundRespDTO doParseRefundNotify(Map params, String body)
+ protected abstract PayRefundRespDTO doParseRefundNotify(Map params, String body, Map headers)
throws Throwable;
@Override
@@ -220,19 +220,19 @@ public abstract class AbstractPayClient implemen
}
@Override
- public final PayTransferRespDTO parseTransferNotify(Map params, String body) {
+ public final PayTransferRespDTO parseTransferNotify(Map params, String body, Map headers) {
try {
- return doParseTransferNotify(params, body);
+ return doParseTransferNotify(params, body, headers);
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
throw ex;
} catch (Throwable ex) {
- log.error("[doParseTransferNotify][客户端({}) params({}) body({}) 解析失败]",
- getId(), params, body, ex);
+ log.error("[doParseTransferNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
+ getId(), params, body, headers, ex);
throw buildPayException(ex);
}
}
- protected abstract PayTransferRespDTO doParseTransferNotify(Map params, String body)
+ protected abstract PayTransferRespDTO doParseTransferNotify(Map params, String body, Map headers)
throws Throwable;
@Override
diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
index b3075eb03d..4b71c4bccc 100644
--- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
+++ b/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 params, String body) throws Throwable {
+ public PayOrderRespDTO doParseOrderNotify(Map params, String body, Map headers) throws Throwable {
// 1. 校验回调数据
Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(),
@@ -175,7 +175,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient params, String body) {
+ public PayRefundRespDTO doParseRefundNotify(Map params, String body, Map headers) {
// 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。
// ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调
// ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有
@@ -327,7 +327,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient params, String body) throws Throwable {
+ protected PayTransferRespDTO doParseTransferNotify(Map params, String body, Map headers) {
throw new UnsupportedOperationException("未实现");
}
diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
index 34b1d5db6f..d8f08bbf2f 100644
--- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
+++ b/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 {
}
@Override
- protected PayTransferRespDTO doParseTransferNotify(Map params, String body) throws Throwable {
+ protected PayTransferRespDTO doParseTransferNotify(Map params, String body, Map headers) {
throw new UnsupportedOperationException("未实现");
}
@Override
- protected PayRefundRespDTO doParseRefundNotify(Map params, String body) {
+ protected PayRefundRespDTO doParseRefundNotify(Map params, String body, Map headers) {
throw new UnsupportedOperationException("模拟支付无退款回调");
}
@Override
- protected PayOrderRespDTO doParseOrderNotify(Map params, String body) {
+ protected PayOrderRespDTO doParseOrderNotify(Map params, String body, Map headers) {
throw new UnsupportedOperationException("模拟支付无支付回调");
}
diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
index 374afccad6..ce01ddb794 100644
--- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
+++ b/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
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
-import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
-import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
-import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
-import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
+import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest;
@@ -67,13 +64,14 @@ public abstract class AbstractWxPayClient extends AbstractPayClient params, String body) throws WxPayException {
+ public PayOrderRespDTO doParseOrderNotify(Map params, String body, Map headers) throws WxPayException {
switch (config.getApiVersion()) {
case API_VERSION_V2:
return doParseOrderNotifyV2(body);
case API_VERSION_V3:
- return doParseOrderNotifyV3(body);
+ return doParseOrderNotifyV3(body, headers);
default:
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
}
@@ -179,9 +177,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient headers) throws WxPayException {
// 1. 解析回调
- WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, null);
+ SignatureHeader signatureHeader = getRequestHeader(headers);
+ WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, signatureHeader);
WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult();
// 2. 构建结果
Integer status = parseStatus(result.getTradeState());
@@ -321,12 +320,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient params, String body) throws WxPayException {
+ public PayRefundRespDTO doParseRefundNotify(Map params, String body, Map headers) throws WxPayException {
switch (config.getApiVersion()) {
case API_VERSION_V2:
return doParseRefundNotifyV2(body);
case API_VERSION_V3:
- return parseRefundNotifyV3(body);
+ return parseRefundNotifyV3(body, headers);
default:
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
}
@@ -344,9 +343,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient headers) throws WxPayException {
// 1. 解析回调
- WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null);
+ SignatureHeader signatureHeader = getRequestHeader(headers);
+ WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, signatureHeader);
WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult();
// 2. 构建结果
if (Objects.equals("SUCCESS", result.getRefundStatus())) {
@@ -357,10 +357,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient params, String body) throws WxPayException {
+ public PayTransferRespDTO doParseTransferNotify(Map params, String body, Map headers) throws WxPayException {
switch (config.getApiVersion()) {
case API_VERSION_V3:
- return parseTransferNotifyV3(body);
+ return parseTransferNotifyV3(body, headers);
case API_VERSION_V2:
throw new UnsupportedOperationException("V2 版本暂不支持,建议使用 V3 版本");
default:
@@ -368,10 +368,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient headers) throws WxPayException {
// 1. 解析回调
+ SignatureHeader signatureHeader = getRequestHeader(headers);
// TODO @luchi:这个可以复用 wxjava 里的类么?
- WxPayTransferPartnerNotifyV3Result response = client.baseParseOrderNotifyV3Result(body, null, WxPayTransferPartnerNotifyV3Result.class, WxPayTransferPartnerNotifyV3Result.TransferNotifyResult.class);
+ WxPayTransferPartnerNotifyV3Result response = client.baseParseOrderNotifyV3Result(body, signatureHeader, WxPayTransferPartnerNotifyV3Result.class, WxPayTransferPartnerNotifyV3Result.TransferNotifyResult.class);
WxPayTransferPartnerNotifyV3Result.TransferNotifyResult result = response.getResult();
// 2. 构建结果
if (Objects.equals("FINISHED", result.getBatchStatus())) {
@@ -513,6 +514,20 @@ public abstract class AbstractWxPayClient extends AbstractPayClient官方示例
+ */
+ private SignatureHeader getRequestHeader(Map headers) {
+ return SignatureHeader.builder()
+ .signature(headers.get("wechatpay-signature"))
+ .nonce(headers.get("wechatpay-nonce"))
+ .serial(headers.get("wechatpay-serial"))
+ .timeStamp(headers.get("wechatpay-timestamp"))
+ .build();
+ }
+
static String formatDateV2(LocalDateTime time) {
return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN);
}
diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java
index 9fe3eaaa17..273b982981 100644
--- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java
+++ b/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 {
@NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class)
private String apiV3Key;
/**
- * 证书序列号
+ * 证书序列号(merchantSerialNumber)
*/
@NotBlank(message = "证书序列号不能为空", groups = V3.class)
private String certSerialNo;
- @Deprecated // TODO 芋艿:V2.3.0 进行移除
- private String privateCertContent;
+ /**
+ * pub_key.pem 证书文件的对应字符串
+ */
+ @NotBlank(message = "pub_key.pem 不能为空", groups = V3.class)
+ private String publicKeyContent;
+ @NotBlank(message = "publicKeyId 不能为空", groups = V3.class)
+ private String publicKeyId;
/**
* 分组校验 v2版本