电商项目-支付模块交易链路梳理与时序图

支付模块交易链路梳理与时序图

本文基于某支付模块的代码实现(项目名已替换为 XXX),详细梳理交易链路,分析核心逻辑,并通过时序图直观展示支付流程。以下内容将帮助读者理解从用户发起支付到支付成功的完整过程,并适用于面试或技术分享场景。

一、核心组件概览

1. 核心实体 (PayInfo)

  • 作用 :记录支付信息,对应数据库表 pay_info
  • 关键字段
    • payId:支付流水号(分布式 ID)。
    • userId:用户 ID。
    • orderIds:关联订单 ID 列表(逗号分隔)。
    • bizPayNo:第三方支付交易号。
    • payStatus:支付状态(0-未支付,1-已支付)。
    • payAmount:支付金额(单位:分)。
    • version:乐观锁版本号。

2. 核心控制器

  • PayController:处理前端支付请求和状态查询。
  • PayNoticeController:处理第三方支付回调。

3. 核心服务 (PayInfoServiceImpl)

  • 功能:支付记录创建、状态更新、订单通知。

二、交易链路梳理

以下是基于代码的支付交易完整流程:

1. 用户发起支付请求

  • 触发点 :用户在前端点击"支付",调用 POST /pay/order
  • 输入PayInfoDTO(包含 orderIdsreturnUrl)。
  • 后端逻辑PayController.pay()):
    1. 获取用户 ID(通过 AuthUserContext)。
    2. 调用 PayInfoService.pay() 生成支付记录并返回 PayInfoBO
    3. 设置回调地址(apiNoticeUrl)和前端跳转地址(returnUrl)。
    4. 模拟回调(调用 PayNoticeController.submit(),仅用于测试)。
    5. 返回 payId 给前端。
  • 输出ServerResponseEntity 封装的 payId

注意 :代码中直接调用 payNoticeController.submit() 是测试逻辑,实际生产环境中应由第三方支付平台发起回调。

2. 支付记录创建 (PayInfoService.pay())

  • 输入userIdPayInfoDTO
  • 逻辑
    1. 生成支付 ID :通过 SegmentFeignClient 获取分布式 ID(payId)。
    2. 验证订单 :调用 OrderFeignClient.getOrdersAmountAndIfNoCancel(),获取订单金额并检查订单是否有效。
    3. 构建支付记录
      • 设置 payIduserIdpayAmountorderIds 等。
      • 初始状态为 PayStatus.UNPAY(未支付)。
    4. 保存记录 :插入 PayInfo 到数据库。
    5. 返回支付参数 :构造 PayInfoBO(包含 payIdpayAmountbody)。
  • 输出PayInfoBO

3. 前端唤起支付

  • 前端逻辑 (未在代码中体现,推测实现):
    • 接收后端返回的 payId
    • 使用 payId 和其他参数(如金额)调用第三方支付 SDK(如微信 wx.requestPayment() 或支付宝表单提交)。
  • 用户操作:输入密码完成支付。

4. 第三方支付平台回调

  • 触发点 :用户支付成功后,第三方支付平台(如微信、支付宝)向后端回调地址(/notice/pay/order)发送通知。
  • 输入payId(实际应包含第三方交易号和签名,代码中简化)。
  • 后端逻辑PayNoticeController.submit()):
    1. 根据 payId 查询 PayInfo
    2. 解析 orderIdsList<Long>
    3. 构造 PayInfoResultBO(包含 payIdbizPayNo 等)。
    4. 调用 PayInfoService.paySuccess() 处理支付成功逻辑。
    5. 返回空字符串(实际应返回第三方要求的响应,如 SUCCESS)。
  • 输出ResponseEntity<String>

5. 支付成功处理 (PayInfoService.paySuccess())

  • 输入PayInfoResultBOorderIds
  • 逻辑
    1. 更新支付状态
      • 设置 payStatusPayStatus.PAYED
      • 更新 bizPayNocallbackContentcallbackTime
      • 执行数据库更新。
    2. 通知订单服务
      • 通过 RocketMQTemplate 发送消息到 XXX_ORDER_NOTIFY_TOPIC,携带 PayNotifyBO(包含 orderIds)。
      • 若发送失败,抛出异常(依赖 RocketMQ 重试)。
  • 特性:事务性操作,确保状态更新和消息发送一致。

6. 前端查询支付状态(可选)

  • 触发点 :前端调用 GET /pay/isPay/{orderIds} 检查支付结果。
  • 逻辑PayController.isPay()):
    1. 调用 PayInfoService.isPay() 查询状态。
    2. 返回布尔值(true 表示已支付)。
  • 输出ResponseEntity<Boolean>

三、时序图

以下是支付交易的时序图,使用 Mermaid 语法生成:

sequenceDiagram participant U as 用户 participant F as 前端 participant P as PayController participant S as PayInfoService participant O as OrderFeignClient participant L as SegmentFeignClient participant T as 第三方支付平台 participant N as PayNoticeController participant R as RocketMQ U->>F: 点击支付 F->>P: POST /pay/order (orderIds) P->>S: pay(userId, payParam) S->>L: getSegmentId() L-->>S: payId S->>O: getOrdersAmountAndIfNoCancel(orderIds) O-->>S: payAmount S->>S: 保存 PayInfo S-->>P: PayInfoBO (payId) P-->>F: payId F->>T: 唤起支付 (payId, payAmount) U->>T: 输入密码支付 T-->>N: POST /notice/pay/order (payId) N->>S: getByPayId(payId) S-->>N: PayInfo N->>S: paySuccess(payInfoResult, orderIds) S->>S: 更新 PayInfo (payStatus=1) S->>R: 发送消息 (ORDER_NOTIFY_TOPIC) R-->>S: 发送成功 N-->>T: SUCCESS F->>P: GET /pay/isPay/{orderIds} P->>S: isPay(orderIds, userId) S-->>P: isPay (1/0) P-->>F: true/false

说明

  • 图中展示了从用户支付到状态更新的完整链路。
  • PayNoticeController.submit() 被视为第三方回调的入口。
  • RocketMQ 确保支付成功后订单状态同步。

四、链路特点

  1. 分布式 ID :通过 SegmentFeignClient 生成 payId,确保唯一性。
  2. 状态机payStatus 驱动支付流程(未支付 -> 已支付)。
  3. 最终一致性:RocketMQ 保证支付状态与订单状态同步。
  4. 安全性:事务控制和消息发送的幂等性设计。
  5. 可追溯性payId 贯穿整个链路。

五、注意事项与优化建议

  1. 回调安全性
    • 当前代码未验证第三方签名,生产环境需添加签名校验(如微信的 MD5 或支付宝的 RSA2)。
  2. 测试逻辑
    • PayController 中直接调用 submit() 是测试代码,实际应移除,由第三方触发。
  3. 异常处理
    • RocketMQ 发送失败时抛异常合理,但可增加重试机制或异步补偿。
  4. 前端交互
    • 返回的 payId 需配合第三方支付参数(如 prepay_id),否则前端无法唤起支付。

六、总结

该支付模块设计清晰,链路完整,从前端发起支付到第三方回调更新状态,再到通知下游服务,体现了微服务架构的典型特点。通过时序图可以直观理解各组件的交互逻辑,适合用于技术分享或面试准备。优化方向包括增强安全性、完善异常处理和规范化第三方支付集成。

相关推荐
Asthenia04123 分钟前
Spring事件机制:微服务架构下的子服务内部解耦合/多场景代码分析
后端
Asthenia041216 分钟前
面试官问我:Spring AOP的代理模式与实现原理深度剖析
后端
小马爱打代码29 分钟前
Spring Boot - 实现邮件发送
spring boot·后端
褚翾澜30 分钟前
Ruby语言的代码重构
开发语言·后端·golang
你的人类朋友1 小时前
浅谈Object.prototype.hasOwnProperty.call(a, b)
javascript·后端·node.js
仙灵灵2 小时前
前端的同学看过来,今天讲讲jwt登录
前端·后端·程序员
Home2 小时前
一、Java性能优化--Nginx篇(一)
后端
陈随易2 小时前
VSCode v1.99发布,王者归来,Agent和MCP正式推出
前端·后端·程序员
ShooterJ2 小时前
海量序列号的高效处理方案
后端
你的人类朋友2 小时前
CommonJS模块化规范
javascript·后端·node.js