application.yml 管理包路径: com.ruoyi.payment.interfaces.controller
职责:
- 对外 REST API(发起支付、查询订单)
- 渠道异步回调 Webhook(微信/支付宝)
- 管理端操作接口(关闭、重发回调、对账查询)
包路径: com.ruoyi.payment.application.service
职责:
- 用例编排(发起支付、处理渠道回调、触发业务回调)
- 事务控制与跨聚合协调
- 定时任务(每日对账、订单过期处理)
包路径:
- com.ruoyi.payment.domain.model - 聚合根、实体、值对象
- com.ruoyi.payment.domain.service - 领域服务
- com.ruoyi.payment.domain.repository - 仓储接口
职责:
- 核心业务规则与状态机
- 聚合根封装与不变性约束
- 领域事件定义
包路径:
- com.ruoyi.payment.infrastructure.persistence - Mapper 实现
- com.ruoyi.payment.infrastructure.channel.wechat - 微信客户端
- com.ruoyi.payment.infrastructure.channel.alipay - 支付宝客户端
- com.ruoyi.payment.infrastructure.config - 配置加载
- com.ruoyi.payment.infrastructure.schedule - 定时调度
- com.ruoyi.payment.infrastructure.audit - 操作审计
职责:
- 仓储接口实现(数据库访问)
- 渠道客户端封装与适配
- 证书与密钥管理
- 定时任务与消息发布
字段:
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 内部订单ID(主键,雪花ID) |
| bizOrderId | String | 外部业务订单号 |
| amount | Integer | 金额(单位:分) |
| currency | String | 币种(固定 CNY) |
| channel | Enum | 支付渠道(WECHAT/ALIPAY) |
| status | Enum | 订单状态 |
| subject | String | 订单标题 |
| description | String | 订单描述 |
| callbackUrl | String | 业务回调地址 |
| expireAt | DateTime | 过期时间(创建后+2小时) |
| latestTransactionId | Long | 最新交易ID |
| channelTradeNo | String | 渠道交易号(支付成功后) |
| paidAt | DateTime | 支付成功时间 |
| version | Integer | 乐观锁版本号 |
| createdAt | DateTime | 创建时间 |
| updatedAt | DateTime | 更新时间 |
订单状态枚举 (status):
- INIT: 初始化
- PENDING: 待支付
- SUCCEEDED: 支付成功
- FAILED: 支付失败
- CANCELED: 已关闭
- EXPIRED: 已过期
业务规则:
1. 金额必须 > 0
2. 币种固定为 CNY
3. 同一订单同时只允许存在**一笔进行中的交易**(PENDING)
4. 订单超过2小时未支付自动标记为 EXPIRED
5. 订单成功后触发外部业务回调
字段:
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 交易ID(主键) |
| orderId | Long | 所属订单ID |
| channel | Enum | 支付渠道 |
| clientType | Enum | 客户端类型(NATIVE/ALIPAY_PRECREATE) |
| status | Enum | 交易状态 |
| codeOrQr | String | 渠道返回的二维码内容(code_url/qr_code) |
| qrBase64 | Text | 服务端生成的Base64二维码图片 |
| requestParams | Text | 渠道请求参数快照 |
| responseSnapshot | Text | 渠道响应快照 |
| channelTradeNo | String | 渠道交易号 |
| createdAt | DateTime | 创建时间 |
| paidAt | DateTime | 支付完成时间 |
交易状态枚举 (status):
- PENDING: 待支付
- SUCCEEDED: 支付成功
- FAILED: 支付失败
- CANCELED: 已取消
业务规则:
1. 每次发起支付时,若订单已有 PENDING 交易,则复用该交易并返回其二维码
2. 若无 PENDING 交易,则创建新交易
3. 一旦交易成功,订单状态同步为 SUCCEEDED
字段:
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 日志ID |
| channel | Enum | 支付渠道 |
| notifyIdOrSerial | String | 渠道通知唯一标识 |
| orderId | Long | 订单ID |
| transactionId | Long | 交易ID |
| payload | Text | 回调原始报文 |
| verified | Boolean | 签名验证是否通过 |
| processed | Boolean | 是否已处理 |
| result | String | 处理结果 |
| createdAt | DateTime | 接收时间 |
幂等控制:
- 唯一索引:channel + notifyIdOrSerial
- 重复通知直接返回成功应答
字段:
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 日志ID |
| orderId | Long | 订单ID |
| transactionId | Long | 交易ID |
| callbackUrl | String | 回调地址 |
| payload | Text | 回调请求体 |
| httpStatus | Integer | HTTP 状态码 |
| response | Text | 响应内容 |
| success | Boolean | 是否成功 |
| retryCount | Integer | 重试次数 |
| lastRetryAt | DateTime | 最后重试时间 |
| createdAt | DateTime | 创建时间 |
重试策略:
- 间隔:0/1/5/15/60 分钟
- 最多重试:10次
- 支持管理端手工重发
字段:
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Long | 审计ID |
| operator | String | 操作人 |
| operationType | Enum | 操作类型 |
| orderId | Long | 订单ID(可选) |
| transactionId | Long | 交易ID(可选) |
| params | Text | 操作参数 |
| approved | Boolean | 是否通过(记录,不走审批流程) |
| createdAt | DateTime | 操作时间 |
操作类型:
- CLOSE_ORDER: 关闭订单
- RESEND_CALLBACK: 重发业务回调
- MANUAL_FIX: 手工修正对账差异
- UPDATE_CHANNEL_ACCOUNT: 更新渠道账号
{ amountInCents, currency }入参:
- bizOrderId: 外部业务订单号
- amount: 金额(分)
- subject: 订单标题
- description: 订单描述
- channel: 支付渠道(WECHAT/ALIPAY)
- callbackUrl: 业务回调地址
流程:
```
1. 查询订单是否存在
- 不存在 → 创建订单(状态 PENDING,expireAt = now + 2小时)
- 存在 → 加载订单
【支付宝】
- 接口:alipay.trade.precreate
- notify_url: https://api.966120.com/api/pay/notify/alipay
- 返回:qr_code
幂等控制:
- 同一订单仅允许一笔 PENDING 交易存在
- 重复请求直接返回已有交易数据
微信v2回调: 1. 接收 XML 报文 2. 验证签名(MD5) 3. 解析报文,提取交易号与支付结果 4. 查询订单与交易 5. 状态转换 - 成功 → 交易状态 SUCCEEDED,订单状态 SUCCEEDED - 失败 → 交易状态 FAILED 6. 持久化更新(乐观锁) 7. 记录 NotifyLog(幂等控制) 8. 触发外部业务回调 9. 返回微信要求的 XML 应答
支付宝回调: 1. 接收表单参数 2. 验证签名(RSA2) 3. 解析交易状态 4. 同步订单与交易状态 5. 记录 NotifyLog 6. 触发外部业务回调 7. 返回 "success"
幂等保障:
- 基于 channel + notifyIdOrSerial 唯一索引
- 重复通知直接返回成功应答,不重复处理
触发时机: 订单状态变更为 SUCCEEDED 后
协议: HTTP POST JSON
请求头:
- Content-Type: application/json
- X-Signature: HMAC-SHA256(payload + nonce + timestamp, callbackSignSecret)
- X-Nonce: 随机字符串
- X-Timestamp: 毫秒时间戳
请求体:json { "tradeId": 1234567890, "orderId": 9876543210, "bizOrderId": "BIZ20251123001", "channel": "WECHAT", "amount": 10000, "currency": "CNY", "status": "SUCCEEDED", "channelTradeNo": "4200001234567890", "paidAt": "2025-11-23T10:30:00", "subject": "商品订单支付", "description": "订单详情" }
鉴权方式:
- 使用 HMAC-SHA256 签名
- 密钥:配置文件中的 callbackSignSecret
- 签名内容:payload + nonce + timestamp
- 外部系统使用相同密钥验证签名
重试策略:
- 失败重试间隔:0/1/5/15/60 分钟
- 最多重试:10次
- 支持管理端手工重发
触发方式: 定时任务(建议每10分钟)
逻辑: 1. 查询状态为 PENDING 且 expireAt < now 的订单 2. 将订单状态更新为 EXPIRED 3. 记录操作日志
过期时间:
- 从订单首次创建时间起算 +2小时
- 发起新交易不刷新过期时间
调度时间: 每天 02:00
流程: 1. 确定对账日期(T-1) 2. 查询本地该日所有订单与交易 3. 调用渠道查询接口(批量/单笔) - 微信:orderquery - 支付宝:alipay.trade.query 4. 对比本地状态与渠道状态 5. 自动修复 - 本地 PENDING,渠道已成功 → 修正为 SUCCEEDED - 本地 PENDING,渠道已关闭 → 修正为 FAILED 6. 差异记录 - 金额不一致 - 渠道无记录但本地存在 - 其他异常情况 7. 生成对账报告 - 总订单数 - 成功数 - 失败数 - 差异数 - 自动修复数 8. 保存对账任务与结果明细
差异处理:
- 状态差异:自动修复并记录
- 金额差异:仅记录,不自动修复,需人工介入
- 严重差异:告警通知
配置项 (application.yml):yaml payment: wechat: appId: wx70f6a7346ee842xx mchId: 1573728xxx mchKey: Xz0ClPK3f5sCeT6SGa1vpVmyUFcbpxxx notifyUrl: https://api.966120.com/api/pay/notify/wechat signType: MD5
接口封装 (WxPayV2Client):
- createNativeOrder(): 统一下单,返回 code_url
- queryOrder(): 查询订单状态
- closeOrder(): 关闭订单
- verifyNotify(): 验证回调签名
- buildNotifyResponse(): 构造应答报文
签名方式: MD5
关键流程:
1. 参数按 ASCII 排序拼接
2. 追加 &key=mchKey
3. MD5 加密并转大写
配置项 (application.yml):yaml payment: alipay: appId: 2021xxxxxxxxxxxxx privateKey: MIIEvQIBADANBgkqhki...(商户RSA2私钥) alipayPublicKey: MIIBIjANBgkqhki...(支付宝RSA2公钥) serverUrl: https://openapi.alipay.com/gateway.do notifyUrl: https://api.966120.com/api/pay/notify/alipay signType: RSA2
接口封装 (AlipayF2FClient):
- precreate(): 当面付下单,返回 qr_code
- query(): 查询订单状态
- close(): 关闭订单
- verifyNotify(): 验证回调签名
签名方式: RSA2
SDK: 使用官方 alipay-sdk-java
public interface ChannelClient {
/**
* 创建二维码订单
*/
QrOrderResponse createQrOrder(QrOrderRequest request);
/**
* 查询订单状态
*/
OrderQueryResponse queryOrder(String channelTradeNo);
/**
* 关闭订单
*/
void closeOrder(String channelTradeNo);
/**
* 验证回调签名
*/
boolean verifyNotify(Map<String, String> params);
}
工厂模式选择实现:
- WxPayV2Client implements ChannelClient
- AlipayF2FClient implements ChannelClient
技术方案: 使用 ZXing 库
参数:
- 尺寸:300 × 300
- 格式:PNG
- 纠错等级:M(默认)
- 编码:UTF-8
输出格式: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
实现:java // 伪代码 BufferedImage qrImage = QRCodeGenerator.generate(codeUrl, 300, 300); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(qrImage, "PNG", baos); String base64 = "data:image/png;base64," + Base64.getEncoder().encodeToString(baos.toByteArray());
CREATE TABLE `pay_order` (
`id` BIGINT NOT NULL PRIMARY KEY COMMENT '订单ID',
`biz_order_id` VARCHAR(64) NOT NULL COMMENT '业务订单号',
`amount` INT NOT NULL COMMENT '金额(分)',
`currency` VARCHAR(8) NOT NULL DEFAULT 'CNY' COMMENT '币种',
`channel` VARCHAR(16) NOT NULL COMMENT '支付渠道',
`status` VARCHAR(16) NOT NULL COMMENT '订单状态',
`subject` VARCHAR(128) NOT NULL COMMENT '订单标题',
`description` VARCHAR(512) COMMENT '订单描述',
`callback_url` VARCHAR(512) NOT NULL COMMENT '业务回调地址',
`expire_at` DATETIME NOT NULL COMMENT '过期时间',
`latest_transaction_id` BIGINT COMMENT '最新交易ID',
`channel_trade_no` VARCHAR(64) COMMENT '渠道交易号',
`paid_at` DATETIME COMMENT '支付成功时间',
`version` INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX `idx_biz_order_id` (`biz_order_id`),
INDEX `idx_channel_trade_no` (`channel_trade_no`),
INDEX `idx_status` (`status`),
INDEX `idx_expire_at` (`expire_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付订单表';
CREATE TABLE `pay_transaction` (
`id` BIGINT NOT NULL PRIMARY KEY COMMENT '交易ID',
`order_id` BIGINT NOT NULL COMMENT '订单ID',
`channel` VARCHAR(16) NOT NULL COMMENT '支付渠道',
`client_type` VARCHAR(32) NOT NULL COMMENT '客户端类型',
`status` VARCHAR(16) NOT NULL COMMENT '交易状态',
`code_or_qr` VARCHAR(512) COMMENT '二维码内容',
`qr_base64` TEXT COMMENT 'Base64二维码图片',
`request_params` TEXT COMMENT '请求参数快照',
`response_snapshot` TEXT COMMENT '响应快照',
`channel_trade_no` VARCHAR(64) COMMENT '渠道交易号',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`paid_at` DATETIME COMMENT '支付完成时间',
INDEX `idx_order_id` (`order_id`),
INDEX `idx_channel_trade_no` (`channel_trade_no`),
INDEX `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付交易流水表';
CREATE TABLE `notify_log` (
`id` BIGINT NOT NULL PRIMARY KEY COMMENT '日志ID',
`channel` VARCHAR(16) NOT NULL COMMENT '支付渠道',
`notify_id_or_serial` VARCHAR(64) NOT NULL COMMENT '渠道通知唯一标识',
`order_id` BIGINT COMMENT '订单ID',
`transaction_id` BIGINT COMMENT '交易ID',
`payload` TEXT NOT NULL COMMENT '回调原始报文',
`verified` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '签名验证是否通过',
`processed` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否已处理',
`result` VARCHAR(128) COMMENT '处理结果',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '接收时间',
UNIQUE KEY `uk_channel_notify` (`channel`, `notify_id_or_serial`),
INDEX `idx_order_id` (`order_id`),
INDEX `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='渠道回调日志表';
CREATE TABLE `biz_callback_log` (
`id` BIGINT NOT NULL PRIMARY KEY COMMENT '日志ID',
`order_id` BIGINT NOT NULL COMMENT '订单ID',
`transaction_id` BIGINT NOT NULL COMMENT '交易ID',
`callback_url` VARCHAR(512) NOT NULL COMMENT '回调地址',
`payload` TEXT NOT NULL COMMENT '回调请求体',
`http_status` INT COMMENT 'HTTP状态码',
`response` TEXT COMMENT '响应内容',
`success` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否成功',
`retry_count` INT NOT NULL DEFAULT 0 COMMENT '重试次数',
`last_retry_at` DATETIME COMMENT '最后重试时间',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
INDEX `idx_order_id` (`order_id`),
INDEX `idx_success` (`success`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='业务回调日志表';
CREATE TABLE `operation_audit` (
`id` BIGINT NOT NULL PRIMARY KEY COMMENT '审计ID',
`operator` VARCHAR(64) NOT NULL COMMENT '操作人',
`operation_type` VARCHAR(32) NOT NULL COMMENT '操作类型',
`order_id` BIGINT COMMENT '订单ID',
`transaction_id` BIGINT COMMENT '交易ID',
`params` TEXT COMMENT '操作参数',
`approved` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否通过',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
INDEX `idx_operator` (`operator`),
INDEX `idx_operation_type` (`operation_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作审计表';
CREATE TABLE `reconciliation_task` (
`id` BIGINT NOT NULL PRIMARY KEY COMMENT '任务ID',
`task_date` DATE NOT NULL COMMENT '对账日期',
`status` VARCHAR(16) NOT NULL COMMENT '任务状态',
`total_count` INT NOT NULL DEFAULT 0 COMMENT '总订单数',
`success_count` INT NOT NULL DEFAULT 0 COMMENT '成功数',
`failed_count` INT NOT NULL DEFAULT 0 COMMENT '失败数',
`diff_count` INT NOT NULL DEFAULT 0 COMMENT '差异数',
`fixed_count` INT NOT NULL DEFAULT 0 COMMENT '自动修复数',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`finished_at` DATETIME COMMENT '完成时间',
UNIQUE KEY `uk_task_date` (`task_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='对账任务表';
CREATE TABLE `reconciliation_result` (
`id` BIGINT NOT NULL PRIMARY KEY COMMENT '明细ID',
`task_id` BIGINT NOT NULL COMMENT '任务ID',
`order_id` BIGINT NOT NULL COMMENT '订单ID',
`transaction_id` BIGINT COMMENT '交易ID',
`local_status` VARCHAR(16) COMMENT '本地状态',
`channel_status` VARCHAR(16) COMMENT '渠道状态',
`diff_type` VARCHAR(32) NOT NULL COMMENT '差异类型',
`fixed` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否已修复',
`note` VARCHAR(512) COMMENT '备注',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
INDEX `idx_task_id` (`task_id`),
INDEX `idx_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='对账差异明细表';
POST /api/pay/wechat/native
请求体:json { "bizOrderId": "BIZ20251123001", "amount": 10000, "subject": "商品订单支付", "description": "购买商品A", "callbackUrl": "https://your-business.com/notify" }
响应:json { "code": 200, "msg": "success", "data": { "orderId": 1234567890, "transactionId": 9876543210, "status": "PENDING", "qrBase64": "data:image/png;base64,iVBORw0KG...", "expireAt": "2025-11-23T12:00:00" } }
POST /api/pay/alipay/precreate
请求体/响应: 同上
POST /api/pay/notify/wechat
说明: 接收微信 XML 报文,验签后处理,返回 XML 应答
POST /api/pay/notify/alipay
说明: 接收表单参数,验签后处理,返回 "success"
GET /api/pay/orders/{orderId}
响应:json { "code": 200, "msg": "success", "data": { "orderId": 1234567890, "bizOrderId": "BIZ20251123001", "amount": 10000, "currency": "CNY", "channel": "WECHAT", "status": "SUCCEEDED", "subject": "商品订单支付", "channelTradeNo": "4200001234567890", "paidAt": "2025-11-23T10:30:00", "expireAt": "2025-11-23T12:00:00", "createdAt": "2025-11-23T10:00:00" } }
GET /api/pay/orders/{orderId}/transactions/latest
响应:json { "code": 200, "msg": "success", "data": { "transactionId": 9876543210, "orderId": 1234567890, "status": "PENDING", "qrBase64": "data:image/png;base64,iVBORw0KG...", "createdAt": "2025-11-23T10:00:00" } }
POST /api/pay/orders/{orderId}/close
响应:json { "code": 200, "msg": "订单已关闭" }
POST /api/pay/orders/{orderId}/callback/resend
响应:json { "code": 200, "msg": "回调已重新发送" }
GET /api/pay/reconciliation/tasks?date=2025-11-22
响应:json { "code": 200, "msg": "success", "data": { "taskId": 12345, "taskDate": "2025-11-22", "status": "FINISHED", "totalCount": 1000, "successCount": 980, "failedCount": 15, "diffCount": 5, "fixedCount": 3, "createdAt": "2025-11-23T02:00:00", "finishedAt": "2025-11-23T02:15:00" } }
GET /api/pay/reconciliation/results?taskId=12345
响应:json { "code": 200, "msg": "success", "data": [ { "orderId": 1234567890, "transactionId": 9876543210, "localStatus": "PENDING", "channelStatus": "SUCCEEDED", "diffType": "STATUS_DIFF", "fixed": true, "note": "已自动修复" } ] }
application.yml:
```yaml
spring:
application:
name: dryad-payment
payment:
# 微信支付配置
wechat:
appId: wx70f6a7346ee842xx
mchId: 1573728xxx
mchKey: Xz0ClPK3f5sCeT6SGa1vpVmyUFcbpxxx
notifyUrl: https://api.966120.com/api/pay/notify/wechat
signType: MD5
# 支付宝配置
alipay:
appId: 2021xxxxxxxxxxxxx
privateKey: MIIEvQIBADANBgkqhki...
alipayPublicKey: MIIBIjANBgkqhki...
serverUrl: https://openapi.alipay.com/gateway.do
notifyUrl: https://api.966120.com/api/pay/notify/alipay
signType: RSA2
# 业务回调配置
business:
callbackSignSecret: your-hmac-secret-key-here
callbackRetryMaxCount: 10
callbackRetryIntervals: 0,1,5,15,60 # 分钟
# 二维码配置
qrcode:
size: 300
format: PNG
# 对账配置
reconciliation:
enabled: true
cron: "0 0 2 * * ?" # 每天凌晨2点
```
路径: /payment/orders
功能:
- 列表展示(支持分页)
- 条件检索:业务订单号、渠道、状态、时间范围
- 详情查看:订单信息、交易记录、回调日志
- 操作:手工关闭订单
路径: /payment/transactions
功能:
- 列表展示(支持分页)
- 查看二维码(Base64图片)
- 查看渠道请求/响应快照
- 按订单过滤
路径: /payment/notify-logs
功能:
- 列表展示(支持分页)
- 查看原始报文
- 验签结果展示
- 处理状态与结果
路径: /payment/callback-logs
功能:
- 列表展示(支持分页)
- 查看回调请求/响应
- 重试次数与状态
- 手工重发回调
路径: /payment/reconciliation
功能:
- 对账任务列表(按日期)
- 查看对账统计
- 差异明细列表
- 自动修复记录查看
路径: /payment/audit
功能:
- 审计日志列表(支持分页)
- 按操作人、操作类型过滤
- 查看操作参数与时间
说明: 不提供导出功能,所有数据仅在线查看
风险: 同一订单并发创建多笔交易
应对: 订单级别乐观锁 + 数据库唯一约束
风险: 渠道回调未成功送达
应对: 每日对账补偿 + 主动查询机制
风险: 外部系统不可用导致回调失败
应对: 重试机制 + 手工重发
风险: 本地与渠道状态不一致
应对: 自动修复 + 差异告警 + 人工介入
风险: 配置文件泄露导致密钥暴露
应对: 文件权限控制 + 日志脱敏 + 定期更换
本设计方案基于 DDD 架构,充分考虑了支付业务的复杂性与稳健性需求:
该方案已对齐:
- ✅ Java 1.8 + Spring Boot 2.5.15 + ruoyi-framework
- ✅ 微信支付 v2 统一下单(MD5签名)
- ✅ 支付宝当面付(RSA2签名)
- ✅ 服务端返回 300×300 Base64 二维码
- ✅ 外部业务回调 HMAC 鉴权
- ✅ 同一订单仅一笔进行中交易
- ✅ 订单 2 小时自动过期
- ✅ 每日 2 点自动对账修复
- ✅ 单商户配置文件加载
- ✅ 管理端页面(不导出)
方案已确认,可进入代码实现阶段。