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. 优势分析
-
开闭原则:新增支付方式无需修改现有代码
-
单一职责:每个支付策略只负责自己的支付逻辑
-
易于测试:可以单独测试每个支付策略
-
配置灵活:支持动态配置和热更新
-
扩展性强:支持自定义支付策略
9. 扩展建议
-
支付路由:根据业务规则自动选择最优支付方式
-
支付降级:主支付方式失败时自动切换到备用支付方式
-
监控告警:集成监控系统,实时监控支付成功率
-
数据统计:支付数据分析和报表生成
-
风控系统:集成风控规则,防范支付风险