mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-11 23:25:33 +08:00
refactor(strategy): 策略无状态化, 显式PayContext传递替代实例字段
AbsPayStrategy/AbsPayCloseStrategy/AbsSyncPayOrderStrategy 去掉可变状态字段(trade/payParam/useCancel), 改为方法参数或PayContext显式传递; 新建PayContext承载payParam/trade/channelConfig, 配置由doBeforePay写入doPay读取; 策略全单例无状态, 消除并发线程安全隐患; 适配3个策略子类(AlipayDirect/AlipayIsv/Douyin)+新版调用方(NormalPayService/PayCloseService/PaySyncService)+old包调用方(PayService/PaySyncService/PayCloseService)。
This commit is contained in:
@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.alipay.strategy.direct;
|
||||
|
||||
import cn.daxpay.open.channel.alipay.service.direct.AlipayDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.alipay.service.pay.AlipayPayService;
|
||||
import cn.daxpay.open.payment.common.context.PayContext;
|
||||
import cn.daxpay.open.payment.pay.bo.PayTradeResultBo;
|
||||
import cn.daxpay.open.payment.strategy.pay.AbsPayStrategy;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
@@ -28,8 +29,8 @@ public class AlipayDirectPayStrategy extends AbsPayStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayTradeResultBo doPayHandler() {
|
||||
return alipayPayService.pay(getTrade(), getPayParam(),
|
||||
alipayDirectConfigAssembler.buildConfig(getTrade().getMchNo()));
|
||||
public PayTradeResultBo doPay(PayContext context) {
|
||||
return alipayPayService.pay(context.getTrade(), context.getPayParam(),
|
||||
alipayDirectConfigAssembler.buildConfig(context.getTrade().getMchNo()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import cn.daxpay.open.channel.alipay.entity.isv.AlipayIsvAppKeyConfig;
|
||||
import cn.daxpay.open.channel.alipay.entity.isv.AlipayIsvChannelMerchant;
|
||||
import cn.daxpay.open.channel.alipay.service.isv.AlipayIsvAppKeyConfigService;
|
||||
import cn.daxpay.open.channel.alipay.service.pay.AlipayPayService;
|
||||
import cn.daxpay.open.payment.common.context.PayContext;
|
||||
import cn.daxpay.open.payment.pay.bo.PayTradeResultBo;
|
||||
import cn.daxpay.open.payment.strategy.pay.AbsPayStrategy;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
|
||||
@@ -40,17 +41,18 @@ public class AlipayIsvPayStrategy extends AbsPayStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doBeforePayHandler() {
|
||||
mapMethod(getPayParam().getMethod());
|
||||
public void doBeforePay(PayContext context) {
|
||||
mapMethod(context.getPayParam().getMethod());
|
||||
// 前置阶段构建配置,存入上下文供 doPay 使用
|
||||
context.setChannelConfig(buildConfig(context.getTrade().getMchNo()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayTradeResultBo doPayHandler() {
|
||||
return alipayPayService.pay(getTrade(), getPayParam(), buildConfig());
|
||||
public PayTradeResultBo doPay(PayContext context) {
|
||||
return alipayPayService.pay(context.getTrade(), context.getPayParam(), context.getChannelConfig());
|
||||
}
|
||||
|
||||
private Map<String, Object> buildConfig() {
|
||||
String mchNo = getTrade().getMchNo();
|
||||
private Map<String, Object> buildConfig(String mchNo) {
|
||||
AlipayIsvChannelMerchant isvMerchant = alipayIsvChannelMerchantManager.findByMchNo(mchNo)
|
||||
.orElseThrow(() -> new DataNotExistException("error.channel.alipay.mchAppNotFound"));
|
||||
AlipayIsvApp isvApp = alipayIsvAppManager.findById(isvMerchant.getIsvAppId())
|
||||
|
||||
@@ -3,6 +3,7 @@ package cn.daxpay.open.channel.douyin.strategy;
|
||||
import cn.daxpay.open.channel.douyin.client.DouyinChannelClient;
|
||||
import cn.daxpay.open.channel.douyin.dto.DouyinPayReq;
|
||||
import cn.daxpay.open.channel.douyin.dto.DouyinPayResp;
|
||||
import cn.daxpay.open.payment.common.context.PayContext;
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import cn.daxpay.open.payment.pay.bo.PayTradeResultBo;
|
||||
import cn.daxpay.open.payment.strategy.pay.AbsPayStrategy;
|
||||
@@ -33,14 +34,14 @@ public class DouyinDirectPayStrategy extends AbsPayStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayTradeResultBo doPayHandler() {
|
||||
public PayTradeResultBo doPay(PayContext context) {
|
||||
// 构建请求
|
||||
DouyinPayReq req = new DouyinPayReq();
|
||||
req.setChannel(ProductEnum.DOUYIN_PAY.getChannel());
|
||||
req.setBizOrderNo(getPayParam().getBizOrderNo());
|
||||
req.setAmount(getPayParam().getAmount().multiply(HUNDRED).longValue());
|
||||
req.setSubject(getPayParam().getTitle());
|
||||
req.setMethod(getPayParam().getMethod());
|
||||
req.setBizOrderNo(context.getPayParam().getBizOrderNo());
|
||||
req.setAmount(context.getPayParam().getAmount().multiply(HUNDRED).longValue());
|
||||
req.setSubject(context.getPayParam().getTitle());
|
||||
req.setMethod(context.getPayParam().getMethod());
|
||||
// TODO 从数据库获取抖音通道配置
|
||||
req.setConfig(Map.of());
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.daxpay.open.payment.common.context;
|
||||
|
||||
import cn.daxpay.open.payment.pay.order.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.PayParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/// # 支付策略执行上下文(请求级,每次支付创建新实例)
|
||||
///
|
||||
/// 显式传递,替代原 AbsPayStrategy 实例字段。通道配置由 doBeforePay 写入、doPay 读取。
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
public class PayContext {
|
||||
|
||||
/// 支付参数
|
||||
private PayParam payParam;
|
||||
|
||||
/// 资金交易凭证
|
||||
private PayTrade trade;
|
||||
|
||||
/// 通道配置(doBeforePay 写入,doPay 读取;类型各通道不同)
|
||||
private Object channelConfig;
|
||||
|
||||
public PayContext() {
|
||||
}
|
||||
|
||||
public PayContext(PayParam payParam) {
|
||||
this.payParam = payParam;
|
||||
}
|
||||
|
||||
/// 读取通道配置(各通道策略 cast 自己的配置类型)
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getChannelConfig() {
|
||||
return (T) channelConfig;
|
||||
}
|
||||
}
|
||||
@@ -94,11 +94,10 @@ public class PayCloseService {
|
||||
trade.setProduct(payOrder.getProduct());
|
||||
trade.setChannel(payOrder.getChannel());
|
||||
trade.setMethod(payOrder.getMethod());
|
||||
strategy.init(trade, useCancel);
|
||||
// 关闭前准备
|
||||
strategy.doBeforeCloseHandler();
|
||||
strategy.doBeforeClose(trade);
|
||||
// 执行关闭策略, 返回关闭的方式
|
||||
closeType = strategy.doCloseHandler();
|
||||
closeType = strategy.doClose(trade, useCancel);
|
||||
// 成功处理 关闭或撤销订单
|
||||
payStatusEnum = useCancel ? PayStatusEnum.CANCEL : PayStatusEnum.CLOSE;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.daxpay.open.platform.core.exception.system.DataErrorException;
|
||||
import cn.daxpay.open.platform.core.exception.PayFailureException;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.payment.common.context.PayContext;
|
||||
import cn.daxpay.open.payment.common.util.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.old.pay.bo.trade.PayResultBo;
|
||||
import cn.daxpay.open.payment.old.pay.dao.order.pay.PayOrderExpandManager;
|
||||
@@ -78,8 +79,7 @@ public class PayService {
|
||||
public PayResult payHandle(PayParam payParam, PayOrder payOrder) {
|
||||
// 获取支付策略类
|
||||
var payStrategy = PaymentStrategyFactory.createByProduct(payParam.getProduct(), AbsPayStrategy.class);
|
||||
// 初始化支付的参数
|
||||
payStrategy.setPayParam(payParam);
|
||||
PayContext context = new PayContext(payParam);
|
||||
// 检测支付能力是否支持(产品已挂载能力覆盖该支付方式)
|
||||
var methodEnum = PayMethodEnum.findByCode(payParam.getMethod());
|
||||
if (!SpringUtil.getBean(PayProductCapabilityService.class).productSupportsMethod(
|
||||
@@ -88,7 +88,7 @@ public class PayService {
|
||||
I18nUtil.getEnumName(methodEnum) + "(" + methodEnum.getCode() + ")");
|
||||
}
|
||||
// 执行支付前处理动作, 进行各种校验, 校验通过才会进行下面的操作
|
||||
payStrategy.doBeforePayHandler();
|
||||
payStrategy.doBeforePay(context);
|
||||
// 订单不存在执行支付前的保存动作, 保存支付订单默认状态为支付中
|
||||
if (Objects.isNull(payOrder)){
|
||||
payOrder = payAssistService.createPayOrder(payParam);
|
||||
@@ -110,11 +110,11 @@ public class PayService {
|
||||
trade.setChannel(payOrder.getChannel());
|
||||
trade.setMethod(payOrder.getMethod());
|
||||
trade.setAmount(payOrder.getAmount().multiply(java.math.BigDecimal.valueOf(100)).longValue());
|
||||
payStrategy.setTrade(trade);
|
||||
context.setTrade(trade);
|
||||
PayResultBo result;
|
||||
try {
|
||||
// 支付操作
|
||||
var newResult = payStrategy.doPayHandler();
|
||||
var newResult = payStrategy.doPay(context);
|
||||
result = new PayResultBo();
|
||||
result.setOutOrderNo(newResult.getOutOrderNo());
|
||||
result.setComplete(newResult.isComplete());
|
||||
|
||||
@@ -103,10 +103,9 @@ public class PaySyncService {
|
||||
trade.setChannel(payOrder.getChannel());
|
||||
trade.setMethod(payOrder.getMethod());
|
||||
trade.setAmount(payOrder.getAmount().multiply(BigDecimal.valueOf(100)).longValue());
|
||||
syncPayStrategy.setTrade(trade);
|
||||
try {
|
||||
// 执行操作, 获取支付网关同步的结果
|
||||
var newResult = syncPayStrategy.doSync();
|
||||
var newResult = syncPayStrategy.doSync(trade);
|
||||
PaySyncResultBo syncResult = new PaySyncResultBo();
|
||||
syncResult.setSyncSuccess(newResult.isSyncSuccess());
|
||||
if (newResult.getPayStatus() != null) {
|
||||
@@ -253,10 +252,9 @@ public class PaySyncService {
|
||||
closeTrade.setProduct(order.getProduct());
|
||||
closeTrade.setChannel(order.getChannel());
|
||||
closeTrade.setMethod(order.getMethod());
|
||||
strategy.setTrade(closeTrade);
|
||||
strategy.doBeforeCloseHandler();
|
||||
strategy.doBeforeClose(closeTrade);
|
||||
// 执行策略的关闭方法
|
||||
strategy.doCloseHandler();
|
||||
strategy.doClose(closeTrade, false);
|
||||
// 关闭统一处理
|
||||
tradeUniHandleService.payClose(order, PayStatusEnum.CLOSE);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.exception.PayFailureException;
|
||||
import cn.daxpay.open.payment.common.enums.PayFundStatusEnum;
|
||||
import cn.daxpay.open.payment.common.context.PayContext;
|
||||
import cn.daxpay.open.payment.common.util.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.pay.bo.PayTradeResultBo;
|
||||
import cn.daxpay.open.payment.pay.order.dao.PayTradeManager;
|
||||
@@ -59,7 +60,6 @@ public class NormalPayService {
|
||||
// 路由解析:直定模式(已传 channelMchNo)直接解析,否则按 appId+method 策略匹配
|
||||
payRouteFacade.resolve(payParam);
|
||||
var payStrategy = PaymentStrategyFactory.createByProduct(payParam.getProduct(), AbsPayStrategy.class);
|
||||
payStrategy.setPayParam(payParam);
|
||||
// 订单不存在,新建支付订单
|
||||
if (Objects.isNull(trade)) {
|
||||
trade = payAssistService.createOrder(payParam);
|
||||
@@ -69,12 +69,12 @@ public class NormalPayService {
|
||||
return payAssistService.buildResult(trade);
|
||||
}
|
||||
}
|
||||
payStrategy.setTrade(trade);
|
||||
payStrategy.initPayParam(trade, payParam);
|
||||
payStrategy.doBeforePayHandler();
|
||||
// 显式传递上下文(替代原策略实例字段)
|
||||
PayContext context = new PayContext(payParam).setTrade(trade);
|
||||
payStrategy.doBeforePay(context);
|
||||
PayTradeResultBo result;
|
||||
try {
|
||||
result = payStrategy.doPayHandler();
|
||||
result = payStrategy.doPay(context);
|
||||
} catch (Exception e) {
|
||||
log.error("支付出现异常", e);
|
||||
trade.setStatus(PayFundStatusEnum.FAIL.getCode());
|
||||
|
||||
@@ -76,10 +76,8 @@ public class PayCloseService {
|
||||
} else {
|
||||
AbsPayCloseStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsPayCloseStrategy.class);
|
||||
strategy.setTrade(trade);
|
||||
strategy.init(trade, useCancel);
|
||||
strategy.doBeforeCloseHandler();
|
||||
strategy.doCloseHandler();
|
||||
strategy.doBeforeClose(trade);
|
||||
strategy.doClose(trade, useCancel);
|
||||
payUniHandleService.payClose(trade, normalOrder);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -87,8 +87,7 @@ public class PaySyncService {
|
||||
.orElse(null);
|
||||
var syncStrategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsSyncPayOrderStrategy.class);
|
||||
syncStrategy.setTrade(trade);
|
||||
PaySyncResultBo syncResult = syncStrategy.doSync();
|
||||
PaySyncResultBo syncResult = syncStrategy.doSync(trade);
|
||||
if (!Objects.equals(syncResult.getOutOrderNo(), trade.getOutOrderNo())) {
|
||||
trade.setOutOrderNo(syncResult.getOutOrderNo());
|
||||
payTradeManager.updateById(trade);
|
||||
|
||||
@@ -3,32 +3,20 @@ package cn.daxpay.open.payment.strategy.pay;
|
||||
import cn.daxpay.open.payment.common.strategy.PaymentStrategy;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
import cn.daxpay.open.payment.pay.order.entity.PayTrade;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/// # 支付关闭策略
|
||||
///
|
||||
@Getter
|
||||
@Setter
|
||||
/// 策略为单例无状态,运行时数据通过方法参数显式传递。
|
||||
public abstract class AbsPayCloseStrategy implements PaymentStrategy {
|
||||
|
||||
/// 资金交易凭证
|
||||
private PayTrade trade = null;
|
||||
|
||||
/// 是否使用撤销方式进行订单关闭
|
||||
private boolean useCancel = false;
|
||||
|
||||
public void init(PayTrade trade, boolean useCancel){
|
||||
this.trade = trade;
|
||||
this.useCancel = useCancel;
|
||||
/// 关闭前的处理方式
|
||||
public void doBeforeClose(PayTrade trade) {
|
||||
}
|
||||
|
||||
/// 关闭前的处理方式
|
||||
public void doBeforeCloseHandler() {}
|
||||
|
||||
/// 关闭操作
|
||||
/// @param trade 资金交易凭证
|
||||
/// @param useCancel 是否使用撤销方式进行订单关闭
|
||||
/// @return 如果执行成功, 返回使用何种方式关闭的支付订单
|
||||
public abstract CloseTypeEnum doCloseHandler();
|
||||
public abstract CloseTypeEnum doClose(PayTrade trade, boolean useCancel);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,21 @@
|
||||
package cn.daxpay.open.payment.strategy.pay;
|
||||
|
||||
import cn.daxpay.open.payment.common.context.PayContext;
|
||||
import cn.daxpay.open.payment.common.strategy.PaymentStrategy;
|
||||
import cn.daxpay.open.payment.pay.bo.PayTradeResultBo;
|
||||
import cn.daxpay.open.payment.pay.order.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.PayParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/// # 抽象支付策略基类
|
||||
///
|
||||
@Getter
|
||||
@Setter
|
||||
/// 策略为单例无状态,运行时数据通过 [PayContext] 显式传递。
|
||||
public abstract class AbsPayStrategy implements PaymentStrategy {
|
||||
|
||||
/// 资金交易凭证
|
||||
private PayTrade trade = null;
|
||||
|
||||
/// 支付参数
|
||||
private PayParam payParam = null;
|
||||
|
||||
/// 初始化支付的参数
|
||||
public void initPayParam(PayTrade trade, PayParam payParam) {
|
||||
this.trade = trade;
|
||||
this.payParam = payParam;
|
||||
}
|
||||
|
||||
/// 支付前处理 包含必要的校验以及对当前通道支付配置信息的初始化
|
||||
/// 出现错误不会保存相关信息
|
||||
public void doBeforePayHandler(){
|
||||
public void doBeforePay(PayContext context) {
|
||||
}
|
||||
|
||||
/// 支付操作
|
||||
/// 出现错误会保存相关信息
|
||||
public abstract PayTradeResultBo doPayHandler();
|
||||
public abstract PayTradeResultBo doPay(PayContext context);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,19 +3,13 @@ package cn.daxpay.open.payment.strategy.sync;
|
||||
import cn.daxpay.open.payment.common.strategy.PaymentStrategy;
|
||||
import cn.daxpay.open.payment.pay.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.pay.order.entity.PayTrade;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/// # 支付同步抽象类
|
||||
///
|
||||
@Getter
|
||||
@Setter
|
||||
/// 策略为单例无状态,运行时数据通过方法参数显式传递。
|
||||
public abstract class AbsSyncPayOrderStrategy implements PaymentStrategy {
|
||||
|
||||
/// 资金交易凭证
|
||||
private PayTrade trade = null;
|
||||
|
||||
/// 查询通道网关方的退款订单状态信息
|
||||
public abstract PaySyncResultBo doSync();
|
||||
public abstract PaySyncResultBo doSync(PayTrade trade);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user