feat:weixin-java from 4.7.2.B => 4.7.4.B
feat:微信支付 v3 从平台证书切换成微信支付公钥 feat:微信支付 v3 增加 header 解析
This commit is contained in:
parent
59234e1eea
commit
a2bfa7a95a
|
@ -75,7 +75,7 @@
|
||||||
<justauth.version>1.16.7</justauth.version>
|
<justauth.version>1.16.7</justauth.version>
|
||||||
<justauth-starter.version>1.4.0</justauth-starter.version>
|
<justauth-starter.version>1.4.0</justauth-starter.version>
|
||||||
<jimureport.version>1.9.4</jimureport.version>
|
<jimureport.version>1.9.4</jimureport.version>
|
||||||
<weixin-java.version>4.7.2.B</weixin-java.version>
|
<weixin-java.version>4.7.4.B</weixin-java.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
|
|
@ -66,7 +66,8 @@ public class PayNotifyController {
|
||||||
@TenantIgnore
|
@TenantIgnore
|
||||||
public String notifyOrder(@PathVariable("channelId") Long channelId,
|
public String notifyOrder(@PathVariable("channelId") Long channelId,
|
||||||
@RequestParam(required = false) Map<String, String> params,
|
@RequestParam(required = false) Map<String, String> params,
|
||||||
@RequestBody(required = false) String body) {
|
@RequestBody(required = false) String body,
|
||||||
|
@RequestHeader Map<String, String> headers) {
|
||||||
log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body);
|
log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body);
|
||||||
// 1. 校验支付渠道是否存在
|
// 1. 校验支付渠道是否存在
|
||||||
PayClient payClient = channelService.getPayClient(channelId);
|
PayClient payClient = channelService.getPayClient(channelId);
|
||||||
|
@ -76,7 +77,7 @@ public class PayNotifyController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 解析通知数据
|
// 2. 解析通知数据
|
||||||
PayOrderRespDTO notify = payClient.parseOrderNotify(params, body);
|
PayOrderRespDTO notify = payClient.parseOrderNotify(params, body, headers);
|
||||||
orderService.notifyOrder(channelId, notify);
|
orderService.notifyOrder(channelId, notify);
|
||||||
return "success";
|
return "success";
|
||||||
}
|
}
|
||||||
|
@ -87,7 +88,8 @@ public class PayNotifyController {
|
||||||
@TenantIgnore
|
@TenantIgnore
|
||||||
public String notifyRefund(@PathVariable("channelId") Long channelId,
|
public String notifyRefund(@PathVariable("channelId") Long channelId,
|
||||||
@RequestParam(required = false) Map<String, String> params,
|
@RequestParam(required = false) Map<String, String> params,
|
||||||
@RequestBody(required = false) String body) {
|
@RequestBody(required = false) String body,
|
||||||
|
@RequestHeader Map<String, String> headers) {
|
||||||
log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body);
|
log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body);
|
||||||
// 1. 校验支付渠道是否存在
|
// 1. 校验支付渠道是否存在
|
||||||
PayClient payClient = channelService.getPayClient(channelId);
|
PayClient payClient = channelService.getPayClient(channelId);
|
||||||
|
@ -97,7 +99,7 @@ public class PayNotifyController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 解析通知数据
|
// 2. 解析通知数据
|
||||||
PayRefundRespDTO notify = payClient.parseRefundNotify(params, body);
|
PayRefundRespDTO notify = payClient.parseRefundNotify(params, body, headers);
|
||||||
refundService.notifyRefund(channelId, notify);
|
refundService.notifyRefund(channelId, notify);
|
||||||
return "success";
|
return "success";
|
||||||
}
|
}
|
||||||
|
@ -108,7 +110,8 @@ public class PayNotifyController {
|
||||||
@TenantIgnore
|
@TenantIgnore
|
||||||
public String notifyTransfer(@PathVariable("channelId") Long channelId,
|
public String notifyTransfer(@PathVariable("channelId") Long channelId,
|
||||||
@RequestParam(required = false) Map<String, String> params,
|
@RequestParam(required = false) Map<String, String> params,
|
||||||
@RequestBody(required = false) String body) {
|
@RequestBody(required = false) String body,
|
||||||
|
@RequestHeader Map<String, String> headers) {
|
||||||
log.info("[notifyTransfer][channelId({}) 回调数据({}/{})]", channelId, params, body);
|
log.info("[notifyTransfer][channelId({}) 回调数据({}/{})]", channelId, params, body);
|
||||||
// 1. 校验支付渠道是否存在
|
// 1. 校验支付渠道是否存在
|
||||||
PayClient payClient = channelService.getPayClient(channelId);
|
PayClient payClient = channelService.getPayClient(channelId);
|
||||||
|
@ -118,7 +121,7 @@ public class PayNotifyController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 解析通知数据
|
// 2. 解析通知数据
|
||||||
PayTransferRespDTO notify = payClient.parseTransferNotify(params, body);
|
PayTransferRespDTO notify = payClient.parseTransferNotify(params, body, headers);
|
||||||
payTransferService.notifyTransfer(channelId, notify);
|
payTransferService.notifyTransfer(channelId, notify);
|
||||||
return "success";
|
return "success";
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) {
|
protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
throw new UnsupportedOperationException("钱包支付无支付回调");
|
throw new UnsupportedOperationException("钱包支付无支付回调");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) {
|
protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
throw new UnsupportedOperationException("钱包支付无退款回调");
|
throw new UnsupportedOperationException("钱包支付无退款回调");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
|
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
throw new UnsupportedOperationException("未实现");
|
throw new UnsupportedOperationException("未实现");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,10 @@ public interface PayClient {
|
||||||
*
|
*
|
||||||
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
|
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
|
||||||
* @param body HTTP 回调接口的 request body
|
* @param body HTTP 回调接口的 request body
|
||||||
|
* @param headers HTTP 回调接口的 request headers
|
||||||
* @return 支付订单信息
|
* @return 支付订单信息
|
||||||
*/
|
*/
|
||||||
PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body);
|
PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body, Map<String, String> headers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得支付订单信息
|
* 获得支付订单信息
|
||||||
|
@ -66,9 +67,10 @@ public interface PayClient {
|
||||||
*
|
*
|
||||||
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
|
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
|
||||||
* @param body HTTP 回调接口的 request body
|
* @param body HTTP 回调接口的 request body
|
||||||
|
* @param headers HTTP 回调接口的 request headers
|
||||||
* @return 支付订单信息
|
* @return 支付订单信息
|
||||||
*/
|
*/
|
||||||
PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body);
|
PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body, Map<String, String> headers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得退款订单信息
|
* 获得退款订单信息
|
||||||
|
@ -103,8 +105,9 @@ public interface PayClient {
|
||||||
*
|
*
|
||||||
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
|
* @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
|
||||||
* @param body HTTP 回调接口的 request body
|
* @param body HTTP 回调接口的 request body
|
||||||
|
* @param headers HTTP 回调接口的 request headers
|
||||||
* @return 转账信息
|
* @return 转账信息
|
||||||
*/
|
*/
|
||||||
PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body);
|
PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body, Map<String, String> headers);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.pay.core.client;
|
package cn.iocoder.yudao.framework.pay.core.client;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
|
||||||
import jakarta.validation.Validator;
|
import jakarta.validation.Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,6 +14,7 @@ import jakarta.validation.Validator;
|
||||||
// @JsonTypeInfo 注解的作用,Jackson 多态
|
// @JsonTypeInfo 注解的作用,Jackson 多态
|
||||||
// 1. 序列化到时数据库时,增加 @class 属性。
|
// 1. 序列化到时数据库时,增加 @class 属性。
|
||||||
// 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型
|
// 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true) // 目的:忽略未知的属性,避免反序列化失败
|
||||||
public interface PayClientConfig {
|
public interface PayClientConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -101,19 +101,19 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
||||||
throws Throwable;
|
throws Throwable;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) {
|
public final PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
try {
|
try {
|
||||||
return doParseOrderNotify(params, body);
|
return doParseOrderNotify(params, body, headers);
|
||||||
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
||||||
throw ex;
|
throw ex;
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
log.error("[parseOrderNotify][客户端({}) params({}) body({}) 解析失败]",
|
log.error("[parseOrderNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
|
||||||
getId(), params, body, ex);
|
getId(), params, body, headers, ex);
|
||||||
throw buildPayException(ex);
|
throw buildPayException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body)
|
protected abstract PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers)
|
||||||
throws Throwable;
|
throws Throwable;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -155,19 +155,19 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
||||||
protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
|
protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) {
|
public final PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
try {
|
try {
|
||||||
return doParseRefundNotify(params, body);
|
return doParseRefundNotify(params, body, headers);
|
||||||
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
||||||
throw ex;
|
throw ex;
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
log.error("[parseRefundNotify][客户端({}) params({}) body({}) 解析失败]",
|
log.error("[parseRefundNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
|
||||||
getId(), params, body, ex);
|
getId(), params, body, headers, ex);
|
||||||
throw buildPayException(ex);
|
throw buildPayException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body)
|
protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers)
|
||||||
throws Throwable;
|
throws Throwable;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -220,19 +220,19 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body) {
|
public final PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
try {
|
try {
|
||||||
return doParseTransferNotify(params, body);
|
return doParseTransferNotify(params, body, headers);
|
||||||
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
||||||
throw ex;
|
throw ex;
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
log.error("[doParseTransferNotify][客户端({}) params({}) body({}) 解析失败]",
|
log.error("[doParseTransferNotify][客户端({}) params({}) body({}) headers({}) 解析失败]",
|
||||||
getId(), params, body, ex);
|
getId(), params, body, headers, ex);
|
||||||
throw buildPayException(ex);
|
throw buildPayException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body)
|
protected abstract PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers)
|
||||||
throws Throwable;
|
throws Throwable;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -79,7 +79,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) throws Throwable {
|
public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) throws Throwable {
|
||||||
// 1. 校验回调数据
|
// 1. 校验回调数据
|
||||||
Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
|
Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
|
||||||
AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(),
|
AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(),
|
||||||
|
@ -175,7 +175,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) {
|
public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
// 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。
|
// 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。
|
||||||
// ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调
|
// ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调
|
||||||
// ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有
|
// ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有
|
||||||
|
@ -327,7 +327,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
||||||
|
|
||||||
// TODO @chihuo:这里是不是也要实现,支付宝的。
|
// TODO @chihuo:这里是不是也要实现,支付宝的。
|
||||||
@Override
|
@Override
|
||||||
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
|
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
throw new UnsupportedOperationException("未实现");
|
throw new UnsupportedOperationException("未实现");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,17 +58,17 @@ public class MockPayClient extends AbstractPayClient<NonePayClientConfig> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
|
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
throw new UnsupportedOperationException("未实现");
|
throw new UnsupportedOperationException("未实现");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) {
|
protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
throw new UnsupportedOperationException("模拟支付无退款回调");
|
throw new UnsupportedOperationException("模拟支付无退款回调");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) {
|
protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) {
|
||||||
throw new UnsupportedOperationException("模拟支付无支付回调");
|
throw new UnsupportedOperationException("模拟支付无支付回调");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.client.impl.AbstractPayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
|
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.*;
|
||||||
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.request.*;
|
import com.github.binarywang.wxpay.bean.request.*;
|
||||||
import com.github.binarywang.wxpay.bean.result.*;
|
import com.github.binarywang.wxpay.bean.result.*;
|
||||||
import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest;
|
import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest;
|
||||||
|
@ -67,13 +64,14 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
protected void doInit(String tradeType) {
|
protected void doInit(String tradeType) {
|
||||||
// 创建 config 配置
|
// 创建 config 配置
|
||||||
WxPayConfig payConfig = new WxPayConfig();
|
WxPayConfig payConfig = new WxPayConfig();
|
||||||
BeanUtil.copyProperties(config, payConfig, "keyContent", "privateKeyContent");
|
BeanUtil.copyProperties(config, payConfig, "keyContent", "privateKeyContent", "publicKeyContent");
|
||||||
payConfig.setTradeType(tradeType);
|
payConfig.setTradeType(tradeType);
|
||||||
// weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决
|
// weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决
|
||||||
if (Objects.equals(config.getApiVersion(), API_VERSION_V2)) {
|
if (Objects.equals(config.getApiVersion(), API_VERSION_V2)) {
|
||||||
payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath());
|
payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath());
|
||||||
} else if (Objects.equals(config.getApiVersion(), API_VERSION_V3)) {
|
} else if (Objects.equals(config.getApiVersion(), API_VERSION_V3)) {
|
||||||
payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath());
|
payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath());
|
||||||
|
payConfig.setPublicKeyPath(FileUtils.createTempFile(config.getPublicKeyContent()).getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 client 客户端
|
// 创建 client 客户端
|
||||||
|
@ -157,12 +155,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) throws WxPayException {
|
public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) throws WxPayException {
|
||||||
switch (config.getApiVersion()) {
|
switch (config.getApiVersion()) {
|
||||||
case API_VERSION_V2:
|
case API_VERSION_V2:
|
||||||
return doParseOrderNotifyV2(body);
|
return doParseOrderNotifyV2(body);
|
||||||
case API_VERSION_V3:
|
case API_VERSION_V3:
|
||||||
return doParseOrderNotifyV3(body);
|
return doParseOrderNotifyV3(body, headers);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
|
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
|
||||||
}
|
}
|
||||||
|
@ -179,9 +177,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
response.getOutTradeNo(), body);
|
response.getOutTradeNo(), body);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PayOrderRespDTO doParseOrderNotifyV3(String body) throws WxPayException {
|
private PayOrderRespDTO doParseOrderNotifyV3(String body, Map<String, String> headers) throws WxPayException {
|
||||||
// 1. 解析回调
|
// 1. 解析回调
|
||||||
WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, null);
|
SignatureHeader signatureHeader = getRequestHeader(headers);
|
||||||
|
WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, signatureHeader);
|
||||||
WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult();
|
WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult();
|
||||||
// 2. 构建结果
|
// 2. 构建结果
|
||||||
Integer status = parseStatus(result.getTradeState());
|
Integer status = parseStatus(result.getTradeState());
|
||||||
|
@ -321,12 +320,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) throws WxPayException {
|
public PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) throws WxPayException {
|
||||||
switch (config.getApiVersion()) {
|
switch (config.getApiVersion()) {
|
||||||
case API_VERSION_V2:
|
case API_VERSION_V2:
|
||||||
return doParseRefundNotifyV2(body);
|
return doParseRefundNotifyV2(body);
|
||||||
case API_VERSION_V3:
|
case API_VERSION_V3:
|
||||||
return parseRefundNotifyV3(body);
|
return parseRefundNotifyV3(body, headers);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
|
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
|
||||||
}
|
}
|
||||||
|
@ -344,9 +343,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
|
return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException {
|
private PayRefundRespDTO parseRefundNotifyV3(String body, Map<String, String> headers) throws WxPayException {
|
||||||
// 1. 解析回调
|
// 1. 解析回调
|
||||||
WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null);
|
SignatureHeader signatureHeader = getRequestHeader(headers);
|
||||||
|
WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, signatureHeader);
|
||||||
WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult();
|
WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult();
|
||||||
// 2. 构建结果
|
// 2. 构建结果
|
||||||
if (Objects.equals("SUCCESS", result.getRefundStatus())) {
|
if (Objects.equals("SUCCESS", result.getRefundStatus())) {
|
||||||
|
@ -357,10 +357,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws WxPayException {
|
public PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) throws WxPayException {
|
||||||
switch (config.getApiVersion()) {
|
switch (config.getApiVersion()) {
|
||||||
case API_VERSION_V3:
|
case API_VERSION_V3:
|
||||||
return parseTransferNotifyV3(body);
|
return parseTransferNotifyV3(body, headers);
|
||||||
case API_VERSION_V2:
|
case API_VERSION_V2:
|
||||||
throw new UnsupportedOperationException("V2 版本暂不支持,建议使用 V3 版本");
|
throw new UnsupportedOperationException("V2 版本暂不支持,建议使用 V3 版本");
|
||||||
default:
|
default:
|
||||||
|
@ -368,10 +368,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PayTransferRespDTO parseTransferNotifyV3(String body) throws WxPayException {
|
private PayTransferRespDTO parseTransferNotifyV3(String body, Map<String, String> headers) throws WxPayException {
|
||||||
// 1. 解析回调
|
// 1. 解析回调
|
||||||
|
SignatureHeader signatureHeader = getRequestHeader(headers);
|
||||||
// TODO @luchi:这个可以复用 wxjava 里的类么?
|
// 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();
|
WxPayTransferPartnerNotifyV3Result.TransferNotifyResult result = response.getResult();
|
||||||
// 2. 构建结果
|
// 2. 构建结果
|
||||||
if (Objects.equals("FINISHED", result.getBatchStatus())) {
|
if (Objects.equals("FINISHED", result.getBatchStatus())) {
|
||||||
|
@ -513,6 +514,20 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
|
|
||||||
// ========== 各种工具方法 ==========
|
// ========== 各种工具方法 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装请求头重的签名信息
|
||||||
|
*
|
||||||
|
* @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>
|
||||||
|
*/
|
||||||
|
private SignatureHeader getRequestHeader(Map<String, String> 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) {
|
static String formatDateV2(LocalDateTime time) {
|
||||||
return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN);
|
return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,13 +73,18 @@ public class WxPayClientConfig implements PayClientConfig {
|
||||||
@NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class)
|
@NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class)
|
||||||
private String apiV3Key;
|
private String apiV3Key;
|
||||||
/**
|
/**
|
||||||
* 证书序列号
|
* 证书序列号(merchantSerialNumber)
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "证书序列号不能为空", groups = V3.class)
|
@NotBlank(message = "证书序列号不能为空", groups = V3.class)
|
||||||
private String certSerialNo;
|
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版本
|
* 分组校验 v2版本
|
||||||
|
|
Loading…
Reference in New Issue