一、 微信支付业务流程
在苍穹外卖中,我们选择的是微信小程序支付产品。其核心流程如下:
- 下单与申请支付:用户在小程序端点击支付,后端调用微信系统的“JSAPI下单”接口,生成预支付交易单。
- 获取支付参数:后端获取微信返回的预支付标识(prepay_id),并进行再次签名,将支付参数返回给小程序。
- 调起支付:小程序调用微信原生支付组件,用户完成付款。
- 支付结果通知:微信后台会向商户系统(后端)发送支付回调通知,告知支付结果。商户系统接收后需进行数据解密并更新订单状态。
二、 准备工作
由于微信支付对安全性要求极高,开发前必须完成以下配置:
- 安全凭证:需要准备好商户私钥文件(
apiclient_key.pem)和平台证书,并在application-dev.yml中配置相关路径、商户号(mchid)及 APIv3 密钥。 - 内网穿透(cpolar) :因为微信后台无法直接访问你本地的
localhost接口,必须使用 cpolar 工具获取一个公网临时域名,用于接收微信的支付回调(Notify URL)。
三、 核心代码实现
1. 配置层 (application.yml)
在配置文件中通过 sky.wechat 配置项读取微信支付所需的全部参数,包括 appid、secret 以及回调地址 notifyUrl。
2. Mapper 层 (OrderMapper)
需要实现以下方法:
getByNumberAndUserId:根据订单号和用户 ID 查询订单信息。update:用于动态修改订单的支付方式、支付状态及结账时间。
3. Service 层 (OrderServiceImpl)
核心逻辑包含两个方法:
payment:调用weChatPayUtil.pay向微信申请支付。如果订单已支付,则抛出业务异常;否则封装预支付交易单数据返回。paySuccess:在支付成功后,将订单状态修改为“待接单”(TO_BE_CONFIRMED),支付状态改为“已支付”,并记录结账时间。
4. 控制层 (OrderController & PayNotifyController)
OrderController:提供PUT /user/order/payment接口,处理用户的支付请求。PayNotifyController:负责接收微信后台的异步通知。包含读取原始数据、使用 AES 解密(基于apiV3Key)、更新订单状态,最后向微信响应SUCCESS以防重复推送。
四、 辅助学习建议
- 理解解密过程:微信推送的数据是加密的 JSON 字符串。你需要仔细阅读
PayNotifyController中的decryptData方法,理解如何通过AesUtil工具类解出包含商户订单号(out_trade_no)的明文文本。 - 事务一致性:虽然支付结果由微信通知,但在
paySuccess方法内部修改订单状态时,需确保数据库操作的准确性。 - 功能自测:在测试时,务必保持 cpolar 隧道处于开启状态,并确保小程序端的
baseUrl或后端的notifyUrl使用的是最新的临时域名。
概念类比: 微信支付就像是在超市柜台扫码结账:
- 你告诉收银员(后端)你要付钱。
- 收银员在 POS 机(微信接口)上输入金额,POS 机打印出一个收款码(预支付交易单参数)。
- 你用手机扫码并输入密码。
- 超市的系统(后端)一直等着 POS 机的信号。一旦 POS 机吐出小票(回调通知),收银员看到“支付成功”后,才会在你的购物单(数据库订单)上盖一个“已付”的章,允许你提货。