对接支付宝订单流程

补充支付相关项目经验

图灵商城项目支付流程

全局概览

  • 支付通道: 当前实现了支付宝当面付(F2F)二维码支付。
  • 关键流程: 下单锁库存 → 生成支付二维码 → 支付宝异步回调验签 → 本地事务更新订单状态 → 事务消息提交 → 商品服务消费消息扣减真实库存(含幂等)。
  • 一致性策略: RocketMQ事务消息 + 本地事务日志 + 定时回查/超时关单,确保“支付-订单-库存”最终一致。
  • 幂等与安全: 使用事务ID落库做幂等校验;支付宝回调做签名验签。

端到端流程(按时间线)

  1. 下单并锁定库存(订单状态=待付款)
  • 在生成订单时锁定库存,订单状态初始化为待付款,后续支付成功才扣减真实库存。
  • 如果采用“异步下单+事务消息”,还会发一条“创建订单”的事务消息,用于后续“超时取消”。
  1. 生成支付宝支付二维码
  • 控制器 /order/tradeQrCode 调用交易服务生成当面付二维码,设置回调 notifyUrl,并将二维码路径写回订单。

这里所需参数,以及如何封装,在demo中皆已提供

// ... 省略若干构建请求参数 ...
.setNotifyUrl(tradePayProp.getPaySuccessCallBack()+"/1")// 支付成功回调地址,/1 表示支付宝
.setGoodsDetailList(goodsDetailList);
log.info("alipay callback url:--->"+builder.getNotifyUrl());
AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
// 成功后生成二维码图片并返回其http访问路径
  1. 支付宝异步回调(验签 + 触发支付成功逻辑)
  • 回调入口 /order/paySuccess/{payType};验签后取 out_trade_no 作为订单号,调用支付成功处理。

验证签名通过后,即开始正式扣减库存

// 1. 收集参数并验签
boolean isPassed = AlipaySignature.rsaCheckV2(param, Configs.getAlipayPublicKey(),"utf-8",Configs.getSignType());
// 2. 取出订单号并执行业务
if(isPassed){
    Long orderId = Long.parseLong(param.get("out_trade_no"));
    int count = portalOrderService.paySuccess(orderId,payType);
    // 写回给支付宝 "success"/"unSuccess"
}
  1. 订单服务:支付成功的本地事务 + 事务消息
  • 旧版是“直接改订单 + 远程扣库存”,目前核心实现改为“发事务消息 → 本地事务更新订单 → 提交消息由商品服务扣库存”,更安全。
// 使用事务消息机制发送扣减库存消息(包含 orderId/payType/明细列表/transactionId)
return reduceStockMsgSender.sendReduceStockMsg(orderId,payType,orderDetail)? 1 : -1;
  • 事务消息发送封装(携带事务ID用于幂等)
String destination = "reduce-stock";
String transactionId = UUID.randomUUID().toString();
Message<StockChangeEvent> message = MessageBuilder.withPayload(stockChangeEvent)
	//传递事务ID,用于回查事务是否执行
    .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
    .setHeader("orderId",orderId)
    .setHeader("payType",payType)
    .build();
// destination:目的地(主题),这里发送给reduce-stock这个topic  
// message:发送给消费者的消息体,需要使用MessageBuilder.withPayload() 来构建消息
// RocketMQ事务监听器:修改订单状态、回查支付状态
TransactionSendResult sendResult = extRocketMQTemplate.sendMessageInTransaction(destination,message,orderId);
  • 订单侧的“事务监听器”本地事务:更新订单状态=待发货、设置支付方式/支付时间,并记录事务日志,返回 COMMIT
Long orderId = Long.parseLong(String.valueOf(arg));
String transactionId = (String) message.getHeaders().get(RocketMQHeaders.TRANSACTION_ID);
Integer payType = Integer.valueOf((String)message.getHeaders().get("payType"));
// 修改订单状态 + 记录事务日志
portalOrderService.updateOrderStatus(orderId,payType,transactionId);
return RocketMQLocalTransactionState.COMMIT;
  • 事务状态回查:靠“本地事务日志”判断是否已执行过
int existTx = omsOrderMapper.isExistTx(transactionId);
return existTx > 0 ? COMMIT : UNKNOWN;
  1. 商品服务:消费“扣库存”消息并落幂等日志
  • 监听 reduce-stock 主题,按订单明细扣减真实库存;使用 transactionId 做幂等。
@RocketMQMessageListener(consumerGroup = "${rocketmq.consumer.group}",topic = "${rocketmq.consumer.topic}")
public class ReduceStockMsgConsumer implements RocketMQListener<StockChangeEvent> {
    public void onMessage(StockChangeEvent stockChangeEvent) {
        stockManageService.reduceStock(stockChangeEvent);
    }
}
// 幂等校验:存在事务记录直接返回
if(skuStockMapper.isExistTx(stockChangeEvent.getTransactionId())>0){ return; }
// 扣减冻结库存(真实库存)
skuStockMapper.updateSkuStock(stockChangesList);
// 记录事务日志用于幂等
skuStockMapper.addTx(stockChangeEvent.getTransactionId());
  1. 超时未支付的订单处理(订单创建事务消息 + 回查 + 取消)
  • 下单时会发“创建订单”的事务消息,监听器会用 Redis 记录回查次数,循环查询支付宝交易状态;超过次数未支付则关单并发送取消消息,消费者释放锁定库存。
if(retryTimes >= maxTryMums){
    // 订单置为无效,返回 COMMIT(触发取消订单消费者释放锁定库存)
} else {
    // 查询支付宝支付状态,已支付则 ROLLBACK(丢弃消息),未支付则回查次数+1返回 UNKNOWN
}
@RocketMQMessageListener(... topic = "${rocketmq.tulingmall.asyncOrderTopic}")
public void onMessage(String message) {
    // 取消订单 & 释放锁定库存
    omsPortalOrderService.cancelOrder(orderId,memberId);
}

关键状态与类型

/*订单状态:0待付款;1待发货;2已发货;3已完成;4已关闭;5无效订单*/
public static final int ORDER_STATUS_UNPAY = 0;
public static final int ORDER_STATUS_UNDELIVERY = 1;
// ...
/*支付方式:0未支付;1支付宝;2微信*/
public static final int ORDER_PAY_TYPE_ALIPAY = 1;

安全与配置要点

  • 支付宝验签: 使用平台公钥与一致的 sign_type 验签;回调里剔除 sign_type 字段参与验签。
  • 回调地址: 通过配置 trade.zhifu.qrcode.paySuccessCallBack 注入,生成二维码时带上 notifyUrl
  • 配置加载: 支付宝参数读取 zfbinfo.properties
private static String alipayPublicKey; // 支付宝RSA公钥,用于验签支付宝应答
private static String signType;        // 签名类型
public synchronized static void init(String filePath) { configs = new PropertiesConfiguration(filePath); ... }

面试亮点与可复述要点

  • 支付对账与一致性: 采用“支付回调 + 事务消息 + 本地事务日志 + 幂等 + 超时回查”的组合拳,确保支付触发的后续库存扣减“最终一致”。
  • 库存两阶段: 下单先“锁定库存”,支付成功后“扣减真实库存”,取消/超时释放锁定库存,避免超卖。
  • 事务消息落地: 订单服务在本地事务内更新订单并记录 transactionId,提交消息后由商品服务消费;两端均用“事务日志”做幂等。
  • 回查策略: 未支付场景通过消息事务回查 + Redis计数 + 最多重试 + 关单,使系统可在外部系统不可靠时自愈。
  • 安全合规: 回调验签、过滤 sign_type、仅认 out_trade_no 作为业务订单号,回调响应“success”/“unSuccess”。

可优化建议(面试加分)

  • 补齐微信支付实现与统一支付抽象(策略模式),兼容多通道。
  • 回调参数签名验签后做参数完整性校验(金额、商户号等)与订单状态幂等检查,补齐退款回滚流程。
  • 结合“事务外盒/本地消息表”进一步强化可靠投递与失败补偿。
  • 使用延迟消息替代回查或优化回查间隔与次数策略。

要点小结

  • 支付宝当面付二维码 → 回调验签 → 订单本地事务更新 + 事务消息 → 商品服务幂等扣库存。
  • 订单创建事务消息 + 回查机制 → 超时关单并释放锁定库存。
  • 事务ID日志做幂等;核心在“事务消息+最终一致性”的工程化实现。

面试中,支付问题点

支付相关的项目经验核心关注的是与支付渠道(如支付宝、微信支付等)的对接逻辑、订单与支付的联动流程、以及支付环节中的技术细节(如接口调用、签名验证、回调处理、异常场景应对等)。而支付宝订单流程的对接通常会涉及这些关键环节:

  • 比如调用支付宝 SDK 生成支付参数、发起支付请求;
  • 处理支付宝的同步 / 异步回调(验证签名、解析支付结果、更新订单状态);
  • 可能涉及的支付超时处理、重复支付校验;
  • 甚至可能包括与业务系统(如订单系统、库存系统)的联动逻辑等。

面试时,你可以重点阐述这部分经验的细节,比如:

  • 具体负责了哪些环节(如支付参数组装、回调接口开发、订单状态同步等);
  • 对接过程中遇到的技术问题(如签名失败、回调重复触发、网络超时等)及解决方案;
  • 如何保证支付流程的安全性(如签名验证、参数加密)和数据一致性(如分布式事务、幂等性处理)。

这些细节能体现你对支付流程的理解和技术实现能力,足以证明你具备支付相关的项目经验。如果还有其他相关延伸(如退款流程、对账逻辑等),也可以补充说明,进一步丰富你的经验展示。