scaffold-pay 支付模块
模块概述
scaffold-pay 是 Scaffold v2 的统一支付模块,采用策略模式支持多支付渠道(微信支付、支付宝)。提供统一下单、支付回调、退款、对账、统计等完整的支付生命周期管理。渠道配置存储在数据库中,敏感字段通过 AES 加密,支持运行时动态切换。
功能列表
- 统一下单:业务系统通过统一接口发起支付,自动路由到对应渠道
- 支付回调:接收第三方支付/退款结果通知,更新订单状态,异步通知业务系统
- 退款管理:发起退款申请,接收退款回调
- 渠道配置:管理支付渠道参数(AppId、商户号、密钥等),敏感字段加密存储
- 自动对账:每日定时下载渠道对账单与本地订单比对,支持手动触发
- 订单超时:定时扫描超时未支付订单自动关闭
- 支付统计:按时间范围统计支付/退款金额和笔数
- 业务回调:支付成功后异步通知业务系统,支持递增重试
核心组件
分层架构
| 层 |
类 |
职责 |
| Controller |
PayOrderController, PayConfigController, PayRefundController, PayReconcileController, PayStatisticsController, PayNotifyController |
REST 接口 |
| Service |
PayOrderService, PayConfigService, PayRefundService, PayReconcileService, PayStatisticsService, PayBizNotifyService |
业务逻辑 |
| Repository |
PayOrderRepository, PayRefundOrderRepository, PayChannelConfigRepository, PayReconcileResultRepository |
数据访问 |
| Mapper |
PayOrderMapper, PayRefundOrderMapper, PayChannelConfigMapper, PayReconcileResultMapper |
ORM 映射 |
策略模式
| 组件 |
说明 |
| PayChannelStrategy |
支付渠道策略接口,定义 createPayOrder / handlePayNotify / queryPayOrder / closePayOrder / createRefund / handleRefundNotify / downloadBill 7 个方法 |
| PayChannelFactory |
策略工厂,根据 PayChannel 枚举自动路由到对应策略实现 |
| WechatPayChannelStrategy |
微信支付策略实现 |
| AlipayPayChannelStrategy |
支付宝策略实现 |
核心组件
| 组件 |
说明 |
| PayChannelConfigManager |
渠道配置管理器,启动时从数据库加载配置到内存缓存,管理修改后自动刷新 |
| PayConfigEncryptor |
配置加解密服务,使用 AES 算法加密渠道配置中的敏感字段(key/secret/private/password) |
| PayOrderTimeoutJob |
定时任务,扫描超时未支付订单并调用第三方关闭 |
| PayReconcileJob |
定时任务,每日凌晨下载渠道对账单并执行自动对账 |
| PayBizNotifyService |
业务回调通知服务,支付成功后异步通知业务系统 |
数据实体
| 实体 |
表 |
说明 |
| PayOrder |
pay_order |
支付订单 |
| PayChannelConfig |
pay_channel_config |
渠道配置 |
| PayRefundOrder |
pay_refund_order |
退款订单 |
| PayReconcileResult |
pay_reconcile_result |
对账结果 |
订单状态流转
PENDING(待支付) -> PAYING(支付中) -> SUCCESS(已支付)
-> CLOSED(已关闭)
SUCCESS -> REFUNDING(退款中) -> REFUNDED(已退款)
注意:PayOrderStatus 和 PayRefundStatus 为多态状态机,不遵循布尔语义规范。
配置参数
配置前缀:scaffold.pay
| 参数 |
类型 |
默认值 |
说明 |
| enabled |
boolean |
true |
模块开关 |
| encrypt-key |
String |
scaffold-pay-default-key |
AES 加密密钥,建议通过环境变量注入 |
| default-expire-minutes |
Integer |
120 |
订单默认超时时间(分钟) |
| callback-retry-times |
Integer |
3 |
业务回调重试次数 |
| callback-retry-intervals |
List |
[5, 30, 120] |
业务回调重试间隔(秒),递增 |
| order-timeout-cron |
String |
0 */5 * * * ? |
订单超时检查 cron 表达式 |
| reconcile-cron |
String |
0 0 2 * * ? |
每日对账 cron 表达式 |
API 接口列表
PayOrderController -- 支付订单管理 (/v1/pay/order)
| 方法 |
路径 |
说明 |
| POST |
/create |
统一下单 |
| POST |
/page |
分页查询订单 |
| GET |
/detail/{id} |
订单详情 |
| GET |
/query/{orderNo}?configId= |
查询第三方订单状态 |
| POST |
/close/{orderNo} |
关闭订单 |
PayConfigController -- 支付渠道配置 (/v1/pay/config)
| 方法 |
路径 |
说明 |
| POST |
/add |
新增支付渠道配置 |
| POST |
/update?id= |
更新支付渠道配置 |
| POST |
/delete/{id} |
删除支付渠道配置 |
| POST |
/toggle-status/{id} |
切换支付渠道启用/禁用状态 |
| GET |
/detail/{id} |
支付渠道配置详情 |
| POST |
/page |
分页查询支付渠道配置 |
PayRefundController -- 退款管理 (/v1/pay/refund)
| 方法 |
路径 |
说明 |
| POST |
/create |
发起退款 |
| POST |
/page |
分页查询退款记录 |
PayStatisticsController -- 支付统计 (/v1/pay/statistics)
| 方法 |
路径 |
说明 |
| POST |
/ |
获取支付统计数据(支持时间范围筛选) |
PayReconcileController -- 支付对账 (/v1/pay/reconcile)
| 方法 |
路径 |
说明 |
| POST |
/page |
分页查询对账结果 |
| POST |
/execute?date=&channel= |
手动触发指定渠道对账 |
| POST |
/execute-all?date= |
手动触发全渠道对账 |
PayNotifyController -- 支付回调(匿名) (/v1/pay/notify)
| 方法 |
路径 |
说明 |
| POST |
/pay/{channel}/{configId} |
支付结果通知回调 |
| POST |
/refund/{channel}/{configId} |
退款结果通知回调 |
SPI 扩展点
新增支付渠道
实现 PayChannelStrategy 接口并注册为 Spring Bean:
- 在
PayChannel 枚举中新增渠道常量
- 实现
PayChannelStrategy 接口的 7 个方法
- 添加
@Component 注解,PayChannelFactory 自动发现并注册
@Component
public class NewPayChannelStrategy implements PayChannelStrategy {
@Override
public PayChannel getChannel() {
return PayChannel.NEW_CHANNEL;
}
// ... 实现其他方法
}
业务回调
实现 PayBizNotifyService 接口,支付成功后自动调用通知业务系统:
@Service
public class MyBizNotifyService implements PayBizNotifyService {
@Override
public void notifyBizSystem(PayOrder order) {
// 通知业务系统
}
}
使用示例
1. 配置支付渠道
POST /v1/pay/config/add
{
"channel": "WECHAT",
"name": "微信支付-生产",
"status": 1,
"channelConfig": "{\"appId\":\"wx...\", \"mchId\":\"14...\", \"apiV3Key\":\"...\"}"
}
说明:status 字段遵循布尔语义规范,1 = 启用,0 = 禁用
2. 发起支付
POST /v1/pay/order/create
{
"orderNo": "BIZ202604260001",
"channel": "WECHAT",
"configId": 1234567890,
"amount": 10000,
"subject": "商品订单支付",
"tradeType": "JSAPI",
"expireMinutes": 30,
"bizNotifyUrl": "https://your-domain.com/callback/pay"
}
3. 接收回调通知
回调接口路径为 /v1/pay/notify/pay/{channel}/{configId},需配置在微信/支付宝商户后台。模块自动验签、更新订单状态、通知业务系统。
4. 发起退款
POST /v1/pay/refund/create
{
"orderNo": "PAY202604260001",
"refundAmount": 5000,
"reason": "部分退款"
}
注意事项
- 密钥安全:
scaffold.pay.encrypt-key 应通过环境变量注入,不要在配置文件中使用默认值
- 回调路径:PayNotifyController 的回调路径需要在安全模块中配置为匿名访问路径
- 金额单位:所有金额字段统一使用分为单位(Long 类型),避免浮点精度问题
- 订单号唯一性:orderNo 需要业务系统保证全局唯一,建议包含日期+业务前缀+序号
- 超时关闭:订单超时后会尝试调用第三方关闭,如果第三方返回关闭失败(可能已支付),则标记为 PAYING 状态等待下次查询确认
- 对账时机:每日对账默认凌晨 2 点执行,对账日期为前一天;也可通过 API 手动触发
- 状态枚举:
status 字段(渠道配置)遵循布尔语义:1 = 启用,0 = 禁用
PayOrderStatus、PayRefundStatus 为多态状态机,不遵循布尔语义规范
待完善功能
- 支付创建流程的前端二维码/收银台页面集成
- 渠道证书管理(p12/pem 文件上传与存储)
- 支付渠道沙箱环境集成测试(AlipaySandboxIntegrationTest 已有基础)