【苍穹外卖 | 项目日记】第八天
本文总结了苍穹外卖项目第8天的学习内容,重点包括地址簿模块实现、用户下单功能开发以及微信支付业务流程理解。由于个人开发者无法直接使用微信支付功能,作者通过技术手段模拟支付流程,使用cpolar实现内网穿透来接收微信回调。文章详细介绍了微信支付的时序图、数据加密机制,以及用户下单功能中订单表与订单明细表的设计实现。同时分享了跳过真实支付的解决方案,并总结了订单状态维护、异常处理等关键技术点。通过本次
前言
今天是学习苍穹外卖项目的第八天。主要任务是导入地址簿模块功能、开发用户下单功能、学习微信支付相关业务逻辑。
由于微信支付功能需要企业资质,个人开发者无法直接使用,因此重点在于理解其业务流程和实现原理,并通过技术手段跳过实际支付环节。

一、今日完结任务
-
✅ 导入并测试地址簿模块功能代码
-
✅ 实现用户下单业务逻辑(订单表 + 订单明细表)
-
✅ 学习微信支付业务流程与接口设计
-
✅ 配置cpolar实现内网穿透,模拟微信回调
-
✅ 跳过微信支付模块,理解支付流程与回调机制
二、今日核心知识点总结
1. 微信支付业务逻辑
1.1 微信支付时序图与流程
微信支付涉及商户系统、微信支付平台、用户小程序三端交互,核心流程如下:

1.2 数据安全与加密机制
微信支付使用双向证书加密机制保证数据安全:
-
商户私钥:用于签名请求数据
-
微信平台证书:用于验证微信返回的数据
-
APIv3密钥:用于解密回调中的敏感信息(如支付金额、用户openid)
1.3 回调地址与内网穿透
微信支付成功后会异步回调商户系统的接口,因此需要一个公网可访问的回调地址。开发阶段使用cpolar实现内网穿透,将本地服务暴露为临时公网域名,用于接收微信支付结果通知。
2. cpolar 内网穿透
2.1 作用与原理
cpolar 是一个内网穿透工具,可将本地服务映射到公网域名,使外部网络(如微信服务器)能够访问本地开发环境。
2.2 使用步骤
-
-
配置 authtoken(从官网获取)
-
启动隧道,获取临时域名(如
https://xxxx.cpolar.top)
-
获取到内网穿透映射出的公网域名
2.3 注意事项
-
临时域名每隔24小时会变化,适合开发测试
-
生产环境需使用固定域名 + 备案
三、遇到的问题:跳过微信支付模块
1. 问题描述
微信支付功能需要企业资质并开通商户号,个人开发者无法直接使用。因此在学习和测试阶段,需要跳过真实的微信支付环节。
2. 解决思路
参考博主XZY_one的博客:cpolar官网 最终成功跳过微信支付业务。
四、今日实战收获
1. 地址簿模块功能导入与测试
地址簿模块实现了用户地址的增删改查、设置默认地址等功能。代码结构清晰,采用经典的 Controller → Service → Mapper 三层架构,并使用了 MyBatis 注解与 XML 混合开发方式。
关键代码:
// 设置默认地址(事务控制)
@Transactional
public void setDefault(AddressBook addressBook) {
// 1. 将该用户所有地址设为非默认
addressBook.setIsDefault(0);
addressBook.setUserId(BaseContext.getCurrentId());
addressBookMapper.updateIsDefaultByUserId(addressBook);
// 2. 将当前地址设为默认
addressBook.setIsDefault(1);
addressBookMapper.update(addressBook);
}
2. 用户下单业务实现
用户下单涉及两张表:orders(订单表)和 order_detail(订单明细表),是一对多关系。
下单流程:
-
校验地址和购物车是否为空
-
向订单表插入一条记录
-
向订单明细表批量插入购物车中的商品
-
清空当前用户的购物车
-
返回订单编号和支付信息
关键代码:
@Transactional
public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
// 1. 校验地址与购物车
AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
if (addressBook == null) {
throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
}
// 2. 构造订单数据
Orders order = new Orders();
BeanUtils.copyProperties(ordersSubmitDTO, order);
order.setNumber(String.valueOf(System.currentTimeMillis()));
order.setStatus(Orders.PENDING_PAYMENT);
order.setOrderTime(LocalDateTime.now());
// 3. 插入订单
orderMapper.insert(order);
// 4. 插入订单明细
List<OrderDetail> orderDetailList = shoppingCartList.stream()
.map(cart -> {
OrderDetail detail = new OrderDetail();
BeanUtils.copyProperties(cart, detail);
detail.setOrderId(order.getId());
return detail;
}).collect(Collectors.toList());
orderDetailMapper.insertBatch(orderDetailList);
// 5. 清空购物车
shoppingCartMapper.deleteByUserId(userId);
// 6. 返回VO
return OrderSubmitVO.builder()
.id(order.getId())
.orderNumber(order.getNumber())
.orderAmount(order.getAmount())
.orderTime(order.getOrderTime())
.build();
}
3. 微信支付模块理解与模拟
虽然跳过了真实支付,但完整理解了以下流程:
-
JSAPI 下单接口调用
-
小程序调起支付
-
异步通知接收与解密
-
订单状态更新
支付成功回调处理:
@RequestMapping("/paySuccess")
public void paySuccessNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. 读取并解密微信回调数据
String body = readData(request);
String plainText = decryptData(body);
// 2. 解析订单号
JSONObject jsonObject = JSON.parseObject(plainText);
String outTradeNo = jsonObject.getString("out_trade_no");
// 3. 更新订单状态
orderService.paySuccess(outTradeNo);
// 4. 返回成功响应给微信
responseToWeixin(response);
}
五、小知识点总结
用户下单模块
-
表结构设计:订单表(
orders)记录订单基本信息,订单明细表(order_detail)记录订单中的商品详情,两者通过order_id关联。 -
业务异常处理:在下单前先校验地址是否存在、购物车是否为空,提前阻断无效请求。
-
Mapper 设计原则:一个数据库表对应一个 Mapper 接口,职责清晰。
-
订单号生成:使用
String.valueOf(System.currentTimeMillis())生成唯一订单号。 -
主键返回:插入订单时设置
useGeneratedKeys="true",获取自增主键用于关联明细表。
订单支付模块
-
支付时序图:理解微信支付中商户、微信、用户三端的交互顺序。
-
加密与签名:微信支付使用
.pem证书文件进行数据加密和签名验证。 -
内网穿透命令:使用
cpolar http 8080将本地 8080 端口暴露到公网。 -
回调解密:使用
AesUtil工具类结合apiV3Key解密微信回调数据。 -
支付状态枚举:订单状态(1待付款、2待接单…)和支付状态(0未支付、1已支付)分开维护。
总结
今日完成了地址簿、用户下单和微信支付(模拟)三大模块的学习。虽然因资质限制无法真实调用微信支付,但通过理解业务流程、支付回调机制,依然掌握了支付功能的核心逻辑。尤其是 cpolar 内网穿透 和 微信支付业务逻辑 两部分,是本次学习的重点突破。
更多推荐



所有评论(0)