Java 开发统一支付入口:集成支付宝、微信、自研支付的实战设计与实现
作者简介:三年 Java 开发经验,近期主导公司自研平台支付系统的统一接入工作。本文总结实战经验,分享架构设计思路,并欢迎同行指正交流。
📌 声明:文中涉及的第三方支付 API 均基于其 v3 版本文档。
一、需求背景
我们正在为公司自研平台(以下简称"平台")构建统一支付能力。平台覆盖多端场景,具体需求如下:
- PC 端:支持扫码支付(展示二维码,用户扫码完成付款)
- H5 端:支持调起支付宝/微信支付,并支持会员卡支付
- 微信小程序端:支持一键唤起微信支付,同时支持会员卡支付
💡 会员卡支付为平台自研支付方式,基于用户储值账户体系实现。本文重点聚焦于第三方支付的统一接入设计,故该部分仅作简要提及。
二、可行性分析:支持的支付方式
根据业务需求,需集成以下主流支付方式:
支付渠道 | 支付类型 | 官方文档 |
---|---|---|
支付宝 | H5 支付 | 支付宝 H5 支付文档 |
支付宝 | 订单码支付(扫码) | 支付宝订单码支付文档 |
微信支付 | H5 支付 | 微信 H5 支付文档 |
微信支付 | 二维码支付(扫码) | 微信扫码支付文档 |
微信支付 | 小程序支付 | 微信小程序支付文档 |
自研 | 会员卡支付 | ------ |
三、架构设计与实现
为避免大量
if-else
或switch-case
判断带来的代码膨胀与维护困难,我们采用 工厂模式 + Spring 容器管理 的策略,实现支付方式的动态分发与解耦。
1. 统一支付入口:Controller 层
定义统一的 /pay
接口作为所有支付请求的入口,屏蔽客户端差异。
java
@RestController
@RequestMapping("/api/pay")
@Tag(name = "支付中心", description = "统一支付接口")
public class PayController {
private final PayService payService;
private final RedissonPropertiesConfig redissonPropertiesConfig;
private final Redisson redisson;
@Autowired
public PayController(RedissonPropertiesConfig redissonPropertiesConfig,
Redisson redisson,
PayService payService) {
this.redissonPropertiesConfig = redissonPropertiesConfig;
this.redisson = redisson;
this.payService = payService;
}
@PostMapping("/pay")
@Operation(summary = "统一支付入口")
@PermitAll
public CommonResult<PaymentVO> corePay(@RequestBody @Valid PayVO payParam) throws Exception {
log.info("【订单 {}】发起支付请求,参数:{}", payParam.getOrderId(), JSON.toJSONString(payParam));
String lockKey = RedisConstant.PAYMENT_LOCK.concat(payParam.getOrderId().toString());
RLock lock = redisson.getLock(lockKey);
PaymentVO r = null;
try {
lock.lock(redissonPropertiesConfig.getAutomaticReleaseTimeValue(), TimeUnit.SECONDS);
// 执行支付
r = payService.corePay(payParam);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
return CommonResult.success(result);
}
}
🔐 说明 :使用
Redisson
分布式锁防止订单重复支付,锁的持有时间与等待时间可配置,提升系统健壮性。
2. 支付服务层:PayService
PayService
是支付流程的调度中心,负责执行公共逻辑,如:
- 查询支付方式配置
- 支付金额校验
- 订单状态检查(是否已支付、是否可支付)
- 调用对应支付工厂执行支付
java
@Service
public class PayServiceImpl implements PayService {
@Resource
private ApplicationContext applicationContext;
@Override
@Transactional(rollbackFor = Exception.class)
public PaymentVO corePay(PayVO payParam) throws Exception {
// todo 1. 查询支付方式配置
PayTypeDO payType = ...
// todo 2. 金额预检
validateAmount(payParam.getAmount());
// todo 3. 检查订单状态(是否已支付、是否存在)
// 4. 动态获取支付实现类
CorePayService corePayService = applicationContext.getBean(payType.getServiceName(), CorePayService.class);
// 5. 执行支付
return corePayService.pay(payParam);
}
}
🧩 关键设计 :通过
PayTypeDO
表中的serviceName
字段动态映射到 Spring 容器中的 Bean,实现运行时动态调用。
3. 支付方式配置表:PayTypeDO
字段 | 描述 |
---|---|
id |
主键 |
pay_code |
支付方式编码(如:ALI_H5、WX_NATIVE、MEMBER_CARD) |
service_name |
对应 Spring Bean 名称(如:aliH5PayService、wxNativePayService) |
config_json |
支付参数(JSON,如 appId、商户号、密钥等) |
✅ 这种设计使得新增支付方式只需:
- 新增配置记录
- 实现
CorePayService
接口- 注册为 Spring Bean
无需修改任何已有代码,完美符合 开闭原则。
4. 支付工厂:CorePayService 接口与实现
接口定义
java
public interface CorePayService {
/**
* 执行支付
* @param payParam 支付参数
* @return 支付结果(如:二维码链接、跳转 URL 等)
*/
PaymentVO pay(PayVO payParam) throws Exception;
}
实现示例:支付宝扫码支付(订单码)
java
@Service("AliPayQRCodeServiceImpl")
@Slf4j
public class AliPayQRCodeServiceImpl implements CorePayService {
@Resource
private AlipayConfig alipayConfig;
@Resource
private AliPayPropertiesConfig aliPayPropertiesConfig;
@Resource
private PayLogMapper logMapper;
@Resource
private OrderRefundApi orderRefundApi;
@Resource
private PayLogMapper payLogMapper;
@Resource
private OrderPayLogApi orderPayLogApi;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public PaymentVO pay(PayVO payParam) throws Exception {
// 支付日志
log.info("【{}】订单支付场景信息 => {}", payLog.getOrderId(), JSONUtil.toJsonStr(build));
// 支付场景信息保存到redis中,避免传入的数据字节数太大导致接口调用失败
stringRedisTemplate.opsForValue().set(PAYMENT_INFO.concat(payLog.getPayPaylog()), JSONUtil.toJsonStr(build), 12, TimeUnit.HOURS);
// 初始化SDK
AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
// 构造请求参数以调用接口
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
// 设置商户订单号
model.setOutTradeNo(...);
// 设置订单总金额(小数点后两位)
model.setTotalAmount(...);
// 设置订单标题
model.setSubject(...);
// 设置产品码
model.setProductCode("QR_CODE_OFFLINE");
// 设置订单附加信息
model.setBody(JSON.toJSONString(payParam.getScenarios()));
log.info("订单【{}】申请支付宝QR付款(v3)参数 => {}", payParam.getOrderId(), JSONUtil.toJsonStr(model));
request.setBizModel(model);
request.setNotifyUrl(...);
AlipayTradePrecreateResponse response = alipayClient.execute(request);
JSONObject entries = JSONUtil.parseObj(response.getBody());
if (!response.isSuccess()) {
log.error("订单【{}】申请支付宝QR付款(v3)失败响应 => {}", payParam.getOrderId(), entries);
throw exception(PayErrorCode.ZFB_QR_PAY_ERR);
}
log.info("订单【{}】申请支付宝QR付款(v3)成功响应 => {}", payParam.getOrderId(), entries);
JSONObject resp = entries.getJSONObject("alipay_trade_precreate_response");
String qrCode = resp.getStr("qr_code");
return PaymentVO.builder()
.payType(Integer.valueOf(payParam.getPayTypeNo()))
.inTradeNo(payParam.getPayLog())
.param(qrCode)
.build();
}
🌟 同理可实现
AliH5PayService
、WxAppletPayService
等,各自独立,互不影响。
5. 组件图:统一支付系统架构

6. 序列图:用户发起支付流程

四、总结与思考
通过本次统一支付系统的构建,我们实现了以下目标:
✅ 成果亮点
- 高内聚低耦合:各支付方式独立实现,职责清晰。
- 易扩展:新增支付渠道只需新增实现类 + 配置,核心逻辑无侵入。
- 可维护性强 :避免
if-else
地狱,代码结构清晰。 - 安全可靠:通过分布式锁防止重复支付,金额校验防篡改。
- 符合开闭原则:对扩展开放,对修改关闭。
🚀 未来优化方向
- 支付配置动态化 :将
PayTypeDO
配置接入 Nacos 或 Apollo,支持热更新。 - 异步通知统一处理 :设计统一的
NotifyHandler
工厂,处理微信/支付宝异步回调。 - 支付结果轮询机制:对于扫码支付,前端可轮询支付状态。
- 日志与监控:接入链路追踪(如 SkyWalking),便于排查问题。
- 幂等性保障 :在
PaymentVO
中引入requestId
,防止重复下单。
五、结语
支付系统是业务的核心环节,安全、稳定、可扩展 是基本要求。本文通过 工厂模式 + Spring IOC 的组合拳,实现了多支付方式的优雅接入。这不仅是一次技术实践,更是对设计模式、系统架构的深入理解。
支付无小事,细节定成败。愿我们都能在构建高质量系统的过程中不断精进,写出更优雅、更可靠的代码。
📌 欢迎留言交流:如果你也在做支付系统,欢迎分享你的架构设计与踩坑经验!