Java支付对接策略模式详细设计

1. 系统架构概览

text

复制代码
支付系统
├── 支付策略接口
├── 具体支付策略实现
├── 支付上下文
├── 支付请求/响应对象
├── 支付配置管理
└── 支付结果处理

2. 核心类设计

2.1 支付策略接口

java 复制代码
/**
 * 支付策略接口
 */
public interface PaymentStrategy {
    
    /**
     * 执行支付
     */
    PaymentResponse pay(PaymentRequest request);
    
    /**
     * 查询支付结果
     */
    PaymentQueryResponse query(PaymentQueryRequest request);
    
    /**
     * 退款
     */
    RefundResponse refund(RefundRequest request);
    
    /**
     * 关闭订单
     */
    CloseResponse close(CloseRequest request);
    
    /**
     * 获取支付方式类型
     */
    PaymentType getPaymentType();
    
    /**
     * 验证签名
     */
    boolean verifySign(String data, String sign);
}

2.2 支付类型枚举

java 复制代码
/**
 * 支付类型枚举
 */
public enum PaymentType {
    WECHAT_H5("微信H5支付"),
    WECHAT_MOBILE("微信移动支付"),
    WECHAT_PC("微信PC支付"),
    WECHAT_SCAN("微信扫码支付"),
    ALIPAY_H5("支付宝H5支付"),
    ALIPAY_MOBILE("支付宝移动支付"),
    ALIPAY_PC("支付宝PC支付"),
    ALIPAY_SCAN("支付宝扫码支付"),
    UNIONPAY("云闪付"),
    BANK_CARD("银行卡支付"),
    ;
    
    private final String description;
    
    PaymentType(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

2.3 支付上下文

java 复制代码
/**
 * 支付上下文
 */
public class PaymentContext {
    
    private PaymentStrategy paymentStrategy;
    private PaymentConfig paymentConfig;
    
    public PaymentContext(PaymentStrategy paymentStrategy, PaymentConfig paymentConfig) {
        this.paymentStrategy = paymentStrategy;
        this.paymentConfig = paymentConfig;
    }
    
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }
    
    /**
     * 执行支付
     */
    public PaymentResponse executePay(PaymentRequest request) {
        // 参数校验
        validateRequest(request);
        
        // 设置商户配置
        request.setMerchantConfig(paymentConfig);
        
        // 执行支付
        return paymentStrategy.pay(request);
    }
    
    /**
     * 查询支付结果
     */
    public PaymentQueryResponse executeQuery(PaymentQueryRequest request) {
        request.setMerchantConfig(paymentConfig);
        return paymentStrategy.query(request);
    }
    
    /**
     * 执行退款
     */
    public RefundResponse executeRefund(RefundRequest request) {
        request.setMerchantConfig(paymentConfig);
        return paymentStrategy.refund(request);
    }
    
    /**
     * 关闭订单
     */
    public CloseResponse executeClose(CloseRequest request) {
        request.setMerchantConfig(paymentConfig);
        return paymentStrategy.close(request);
    }
    
    private void validateRequest(PaymentRequest request) {
        // 参数校验逻辑
        if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new PaymentException("支付金额必须大于0");
        }
        if (StringUtils.isBlank(request.getOrderNo())) {
            throw new PaymentException("订单号不能为空");
        }
    }
}

3. 具体支付策略实现

3.1 微信支付抽象基类

java 复制代码
/**
 * 微信支付抽象基类
 */
public abstract class AbstractWechatPayment implements PaymentStrategy {
    
    protected WechatPayConfig wechatConfig;
    protected WechatPayClient wechatPayClient;
    
    public AbstractWechatPayment(WechatPayConfig config) {
        this.wechatConfig = config;
        this.wechatPayClient = createWechatPayClient(config);
    }
    
    protected WechatPayClient createWechatPayClient(WechatPayConfig config) {
        // 创建微信支付客户端
        return WechatPayClientBuilder.create()
                .withMerchant(config.getMerchantId(), config.getMerchantSerialNumber(), config.getPrivateKey())
                .withValidator(new WechatPay2Validator(config.getApiKey()))
                .build();
    }
    
    @Override
    public PaymentResponse pay(PaymentRequest request) {
        try {
            // 构建微信支付请求
            com.wechat.pay.java.service.payments.model.Request wechatRequest = buildWechatPayRequest(request);
            
            // 调用微信支付API
            com.wechat.pay.java.service.payments.model.Response wechatResponse = 
                wechatPayClient.execute(wechatRequest);
            
            // 转换为通用响应
            return convertToPaymentResponse(wechatResponse);
            
        } catch (Exception e) {
            throw new PaymentException("微信支付失败", e);
        }
    }
    
    /**
     * 构建微信支付请求 - 由子类实现
     */
    protected abstract com.wechat.pay.java.service.payments.model.Request buildWechatPayRequest(PaymentRequest request);
    
    /**
     * 转换为通用响应 - 由子类实现
     */
    protected abstract PaymentResponse convertToPaymentResponse(com.wechat.pay.java.service.payments.model.Response wechatResponse);
    
    @Override
    public boolean verifySign(String data, String sign) {
        // 微信支付签名验证
        try {
            return wechatPayClient.verifySign(data, sign);
        } catch (Exception e) {
            return false;
        }
    }
}

3.2 微信H5支付实现

java 复制代码
/**
 * 微信H5支付
 */
public class WechatH5Payment extends AbstractWechatPayment {
    
    public WechatH5Payment(WechatPayConfig config) {
        super(config);
    }
    
    @Override
    protected Request buildWechatPayRequest(PaymentRequest request) {
        H5Info h5Info = new H5Info();
        h5Info.setType("Wap");
        
        SceneInfo sceneInfo = new SceneInfo();
        sceneInfo.setPayerClientIp(request.getClientIp());
        sceneInfo.setH5Info(h5Info);
        
        Amount amount = new Amount();
        amount.setTotal(request.getAmount().multiply(new BigDecimal("100")).intValue());
        amount.setCurrency("CNY");
        
        PrepayRequest prepayRequest = new PrepayRequest();
        prepayRequest.setAppid(wechatConfig.getAppId());
        prepayRequest.setMchid(wechatConfig.getMerchantId());
        prepayRequest.setDescription(request.getSubject());
        prepayRequest.setOutTradeNo(request.getOrderNo());
        prepayRequest.setNotifyUrl(wechatConfig.getNotifyUrl());
        prepayRequest.setAmount(amount);
        prepayRequest.setSceneInfo(sceneInfo);
        
        return prepayRequest;
    }
    
    @Override
    protected PaymentResponse convertToPaymentResponse(Response wechatResponse) {
        PrepayResponse prepayResponse = (PrepayResponse) wechatResponse;
        
        PaymentResponse response = new PaymentResponse();
        response.setSuccess(true);
        response.setPaymentType(PaymentType.WECHAT_H5);
        response.setOrderNo(prepayResponse.getOutTradeNo());
        response.setPaymentData(prepayResponse.getH5Url());
        response.setPrepayId(prepayResponse.getPrepayId());
        
        return response;
    }
    
    @Override
    public PaymentType getPaymentType() {
        return PaymentType.WECHAT_H5;
    }
}

3.3 支付宝支付抽象基类

java 复制代码
/**
 * 支付宝支付抽象基类
 */
public abstract class AbstractAlipayPayment implements PaymentStrategy {
    
    protected AlipayConfig alipayConfig;
    protected AlipayClient alipayClient;
    
    public AbstractAlipayPayment(AlipayConfig config) {
        this.alipayConfig = config;
        this.alipayClient = createAlipayClient(config);
    }
    
    protected AlipayClient createAlipayClient(AlipayConfig config) {
        return new DefaultAlipayClient(
            config.getGateway(),
            config.getAppId(),
            config.getPrivateKey(),
            "json",
            "UTF-8",
            config.getAlipayPublicKey(),
            config.getSignType()
        );
    }
    
    @Override
    public PaymentResponse pay(PaymentRequest request) {
        try {
            AlipayTradePayResponse response = executeAlipayPay(request);
            return convertToPaymentResponse(response);
        } catch (AlipayApiException e) {
            throw new PaymentException("支付宝支付失败", e);
        }
    }
    
    /**
     * 执行支付宝支付 - 由子类实现
     */
    protected abstract AlipayTradePayResponse executeAlipayPay(PaymentRequest request) throws AlipayApiException;
    
    /**
     * 转换为通用响应
     */
    protected PaymentResponse convertToPaymentResponse(AlipayTradePayResponse alipayResponse) {
        PaymentResponse response = new PaymentResponse();
        response.setSuccess("10000".equals(alipayResponse.getCode()));
        response.setOrderNo(alipayResponse.getOutTradeNo());
        response.setTradeNo(alipayResponse.getTradeNo());
        response.setMessage(alipayResponse.getMsg());
        
        return response;
    }
    
    @Override
    public boolean verifySign(String data, String sign) {
        try {
            return AlipaySignature.rsaCheck(data, sign, alipayConfig.getAlipayPublicKey(), "UTF-8", alipayConfig.getSignType());
        } catch (AlipayApiException e) {
            return false;
        }
    }
}

3.4 云闪付实现

java 复制代码
/**
 * 云闪付支付
 */
public class UnionPayPayment implements PaymentStrategy {
    
    private UnionPayConfig unionPayConfig;
    private AcpService acpService;
    
    public UnionPayPayment(UnionPayConfig config) {
        this.unionPayConfig = config;
        this.acpService = AcpService.getAcpService(config.getBaseProperties());
    }
    
    @Override
    public PaymentResponse pay(PaymentRequest request) {
        try {
            Map<String, String> requestData = buildUnionPayRequest(request);
            
            // 签名
            Map<String, String> signedData = acpService.sign(requestData, "UTF-8");
            
            // 发送请求
            Map<String, String> responseData = acpService.post(signedData, unionPayConfig.getFrontTransUrl(), "UTF-8");
            
            return convertToPaymentResponse(responseData);
            
        } catch (Exception e) {
            throw new PaymentException("云闪付支付失败", e);
        }
    }
    
    private Map<String, String> buildUnionPayRequest(PaymentRequest request) {
        Map<String, String> data = new HashMap<>();
        
        // 银联参数
        data.put("version", "5.1.0");
        data.put("encoding", "UTF-8");
        data.put("signMethod", "01");
        data.put("txnType", "01");
        data.put("txnSubType", "01");
        data.put("bizType", "000201");
        data.put("channelType", "07");
        
        data.put("merId", unionPayConfig.getMerId());
        data.put("orderId", request.getOrderNo());
        data.put("txnAmt", request.getAmount().multiply(new BigDecimal("100")).toString());
        data.put("currencyCode", "156");
        data.put("txnTime", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        
        data.put("frontUrl", unionPayConfig.getFrontUrl());
        data.put("backUrl", unionPayConfig.getBackUrl());
        
        return data;
    }
    
    private PaymentResponse convertToPaymentResponse(Map<String, String> responseData) {
        PaymentResponse response = new PaymentResponse();
        
        if (!acpService.validate(responseData, "UTF-8")) {
            response.setSuccess(false);
            response.setMessage("签名验证失败");
            return response;
        }
        
        String respCode = responseData.get("respCode");
        response.setSuccess("00".equals(respCode));
        response.setOrderNo(responseData.get("orderId"));
        response.setTradeNo(responseData.get("queryId"));
        response.setMessage(responseData.get("respMsg"));
        response.setPaymentData(responseData.get("tn"));
        
        return response;
    }
    
    @Override
    public PaymentType getPaymentType() {
        return PaymentType.UNIONPAY;
    }
    
    // 其他方法实现...
}

4. 支付策略工厂

java 复制代码
/**
 * 支付策略工厂
 */
@Component
public class PaymentStrategyFactory {
    
    @Autowired
    private WechatPayConfig wechatPayConfig;
    
    @Autowired
    private AlipayConfig alipayConfig;
    
    @Autowired
    private UnionPayConfig unionPayConfig;
    
    private final Map<PaymentType, PaymentStrategy> strategyMap = new ConcurrentHashMap<>();
    
    @PostConstruct
    public void init() {
        // 初始化微信支付策略
        strategyMap.put(PaymentType.WECHAT_H5, new WechatH5Payment(wechatPayConfig));
        strategyMap.put(PaymentType.WECHAT_MOBILE, new WechatMobilePayment(wechatPayConfig));
        strategyMap.put(PaymentType.WECHAT_PC, new WechatPcPayment(wechatPayConfig));
        strategyMap.put(PaymentType.WECHAT_SCAN, new WechatScanPayment(wechatPayConfig));
        
        // 初始化支付宝支付策略
        strategyMap.put(PaymentType.ALIPAY_H5, new AlipayH5Payment(alipayConfig));
        strategyMap.put(PaymentType.ALIPAY_MOBILE, new AlipayMobilePayment(alipayConfig));
        strategyMap.put(PaymentType.ALIPAY_PC, new AlipayPcPayment(alipayConfig));
        strategyMap.put(PaymentType.ALIPAY_SCAN, new AlipayScanPayment(alipayConfig));
        
        // 初始化其他支付策略
        strategyMap.put(PaymentType.UNIONPAY, new UnionPayPayment(unionPayConfig));
        strategyMap.put(PaymentType.BANK_CARD, new BankCardPayment());
    }
    
    /**
     * 获取支付策略
     */
    public PaymentStrategy getStrategy(PaymentType paymentType) {
        PaymentStrategy strategy = strategyMap.get(paymentType);
        if (strategy == null) {
            throw new PaymentException("不支持的支付方式: " + paymentType);
        }
        return strategy;
    }
    
    /**
     * 注册新的支付策略
     */
    public void registerStrategy(PaymentType paymentType, PaymentStrategy strategy) {
        strategyMap.put(paymentType, strategy);
    }
}

5. 支付服务门面

java 复制代码
/**
 * 支付服务门面
 */
@Service
public class PaymentService {
    
    @Autowired
    private PaymentStrategyFactory strategyFactory;
    
    @Autowired
    private PaymentConfig paymentConfig;
    
    /**
     * 执行支付
     */
    public PaymentResponse pay(PaymentRequest request) {
        PaymentStrategy strategy = strategyFactory.getStrategy(request.getPaymentType());
        PaymentContext context = new PaymentContext(strategy, paymentConfig);
        return context.executePay(request);
    }
    
    /**
     * 查询支付结果
     */
    public PaymentQueryResponse queryPayment(PaymentQueryRequest request) {
        PaymentStrategy strategy = strategyFactory.getStrategy(request.getPaymentType());
        PaymentContext context = new PaymentContext(strategy, paymentConfig);
        return context.executeQuery(request);
    }
    
    /**
     * 执行退款
     */
    public RefundResponse refund(RefundRequest request) {
        PaymentStrategy strategy = strategyFactory.getStrategy(request.getPaymentType());
        PaymentContext context = new PaymentContext(strategy, paymentConfig);
        return context.executeRefund(request);
    }
    
    /**
     * 处理支付回调
     */
    public PaymentNotifyResult handleNotify(PaymentType paymentType, Map<String, String> notifyParams) {
        PaymentStrategy strategy = strategyFactory.getStrategy(paymentType);
        
        // 验证签名
        if (!strategy.verifySign(buildSignData(notifyParams), notifyParams.get("sign"))) {
            throw new PaymentException("签名验证失败");
        }
        
        // 处理回调逻辑
        return processNotifyResult(notifyParams);
    }
    
    private String buildSignData(Map<String, String> params) {
        // 构建待签名数据
        return params.entrySet().stream()
                .filter(entry -> !"sign".equals(entry.getKey()) && StringUtils.isNotBlank(entry.getValue()))
                .sorted(Map.Entry.comparingByKey())
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining("&"));
    }
    
    private PaymentNotifyResult processNotifyResult(Map<String, String> notifyParams) {
        // 处理回调结果
        PaymentNotifyResult result = new PaymentNotifyResult();
        result.setOrderNo(notifyParams.get("out_trade_no"));
        result.setTradeNo(notifyParams.get("trade_no"));
        result.setPaymentStatus(PaymentStatus.SUCCESS);
        result.setPaymentAmount(new BigDecimal(notifyParams.get("total_amount")));
        
        return result;
    }
}

6. 配置管理

6.1 支付配置基类

java 复制代码
/**
 * 支付配置基类
 */
@Data
public class PaymentConfig {
    private String merchantId;
    private String notifyUrl;
    private String returnUrl;
    private Boolean sandbox = false;
}

6.2 微信支付配置

java 复制代码
/**
 * 微信支付配置
 */
@Data
@ConfigurationProperties(prefix = "payment.wechat")
public class WechatPayConfig extends PaymentConfig {
    private String appId;
    private String merchantSerialNumber;
    private String privateKey;
    private String apiKey;
    private String apiV3Key;
}

7. 使用示例

java 复制代码
@RestController
@RequestMapping("/api/payment")
public class PaymentController {
    
    @Autowired
    private PaymentService paymentService;
    
    /**
     * 发起支付
     */
    @PostMapping("/pay")
    public ApiResult<PaymentResponse> pay(@RequestBody PaymentRequest request) {
        try {
            PaymentResponse response = paymentService.pay(request);
            return ApiResult.success(response);
        } catch (PaymentException e) {
            return ApiResult.fail(e.getMessage());
        }
    }
    
    /**
     * 微信支付回调
     */
    @PostMapping("/wechat/notify")
    public String wechatNotify(HttpServletRequest request) {
        try {
            Map<String, String> params = convertRequestToMap(request);
            PaymentNotifyResult result = paymentService.handleNotify(PaymentType.WECHAT_H5, params);
            
            // 更新订单状态
            updateOrderStatus(result);
            
            return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        } catch (Exception e) {
            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[处理失败]]></return_msg></xml>";
        }
    }
    
    /**
     * 支付宝支付回调
     */
    @PostMapping("/alipay/notify")
    public String alipayNotify(HttpServletRequest request) {
        try {
            Map<String, String> params = convertRequestToMap(request);
            PaymentNotifyResult result = paymentService.handleNotify(PaymentType.ALIPAY_H5, params);
            
            // 更新订单状态
            updateOrderStatus(result);
            
            return "success";
        } catch (Exception e) {
            return "fail";
        }
    }
    
    private Map<String, String> convertRequestToMap(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return params;
    }
    
    private void updateOrderStatus(PaymentNotifyResult result) {
        // 更新订单状态的业务逻辑
    }
}

8. 优势分析

  1. 开闭原则:新增支付方式无需修改现有代码

  2. 单一职责:每个支付策略只负责自己的支付逻辑

  3. 易于测试:可以单独测试每个支付策略

  4. 配置灵活:支持动态配置和热更新

  5. 扩展性强:支持自定义支付策略

9. 扩展建议

  1. 支付路由:根据业务规则自动选择最优支付方式

  2. 支付降级:主支付方式失败时自动切换到备用支付方式

  3. 监控告警:集成监控系统,实时监控支付成功率

  4. 数据统计:支付数据分析和报表生成

  5. 风控系统:集成风控规则,防范支付风险

相关推荐
来来走走1 天前
Android开发(Kotlin) 协程
android·java·kotlin
河铃旅鹿1 天前
Android开发-java版:Framgent
android·java·笔记·学习
y***61311 天前
【springboot】Spring 官方抛弃了 Java 8!新idea如何创建java8项目
java·spring boot·spring
tanxinji1 天前
RabbitMQ四种交换器类型详解及示例
java·rabbitmq
刘一说1 天前
一次生产环境 Tomcat 7 + JDK 7 应用启动失败的完整排查与修复实录
java·tomcat·firefox
七夜zippoe1 天前
JVM类加载机制(Class Loading)详解:双亲委派模型与破坏实践
java·开发语言·jvm·类加载·双亲委派
黄昏恋慕黎明1 天前
spring MVC了解
java·后端·spring·mvc
-Xie-1 天前
Redis(八)——多线程与单线程
java·数据库·redis
Kuo-Teng1 天前
LeetCode 279: Perfect Squares
java·数据结构·算法·leetcode·职场和发展
2501_941149501 天前
探索云原生架构:从容器到微服务的全面升级
微服务·云原生·架构