视频加载失败

苍穹外卖 Day04:用户端订单与模拟支付

735 字
4 分钟
苍穹外卖 Day04:用户端订单与模拟支付

当日改动集中在 sky-server 与 sky-pojo:用户端订单模块新增 OrderController、OrderServiceImpl、OrderMapper(含 xml)与 OrderDetailMapper,返回 VO 统一放在 sky-pojo;套餐管理的 SetmealMapper.xml 同日起步。

用户端订单接口#

OrderController 映射在 /user/order 下,共三个接口:

  • POST /submit 用户下单,返回 OrderSubmitVO
  • PUT /payment 订单支付(模拟支付,跳过微信支付验证直接标记已支付),返回 OrderPaymentVO
  • GET /historyOrders 历史订单分页查询,返回 PageResult

下单流程#

OrderServiceImpl.submit(OrdersSubmitDTO) 的完整链路:

  1. 校验地址簿:addressBookMapper.getById,为空抛 AddressBookBusinessException
  2. 校验购物车:BaseContext.getCurrentId() 取当前用户 id,shoppingCartMapper.list 查询,为空抛 ShoppingCartBusinessException
  3. 组装 Orders:BeanUtils.copyProperties 复制属性,补 orderTime=now、payStatus=UN_PAID、status=PENDING_PAYMENT、number=时间戳,并从地址簿取 phone/consignee/address 做快照
  4. orderMapper.insert 写入订单,useGeneratedKeys 回填主键 id
  5. 遍历购物车逐条转 OrderDetail(copyProperties 后 setOrderId=orders.getId()),orderDetailMapper.insertBatch 批量插入订单明细
  6. shoppingCartMapper.deleteByUserId 清空该用户购物车
  7. 封装 OrderSubmitVO(id/number/amount/orderTime)返回

订单、订单明细、清空购物车跨多张表,整个方法在一个事务内完成。

支付与状态流转#

  • payment(OrdersPaymentDTO):按 orderNumber 查订单,已支付(PAID)则抛 OrderBusinessException("该订单已支付");否则调 paySuccess 模拟支付成功,返回空的 OrderPaymentVO
  • paySuccess(outTradeNo):查订单后更新 status=TO_BE_CONFIRMED、payStatus=PAID、checkoutTime=now,走 orderMapper.update 的动态 SQL

订单状态与支付状态常量定义在 sky-pojo 的 Orders.java:

  • status:PENDING_PAYMENT=1、TO_BE_CONFIRMED=2、CONFIRMED=3、DELIVERY_IN_PROGRESS=4、COMPLETED=5、CANCELLED=6
  • payStatus:UN_PAID=0、PAID=1、REFUND=2

历史订单分页#

page(page, pageSize, status):PageHelper.startPage 物理分页 → orderMapper.pageQuery 按 userId + status 过滤、order_time 倒序 → 遍历每单调 orderDetailMapper.getByOrderId 补明细,封装成 OrderVO → 最终包成 PageResult。

一对多 VO 封装(订单 + 明细列表)在遍历处形成 N+1 查询,见下文可优化点。

Mapper 层 SQL#

OrderMapper(接口 + xml):

  • insert:全字段 insert,配 useGeneratedKeys="true" keyProperty="id" 回填主键
  • getByNumber:注解 @Select("select * from orders where number=#{orderNumber}")
  • update:<set> 动态更新,cancel/rejection/payStatus/payMethod/checkoutTime/status/deliveryTime 均为可选字段
  • pageQuery:<where> 按 number/phone/userId/status/beginTime/endTime 动态过滤,order_time desc 排序

OrderDetailMapper 提供 insertBatch(批量插入明细)与 getByOrderId。

套餐管理 Mapper 起步#

新增 SetmealMapper.xml,先落四条语句:

  • insert:useGeneratedKeys 回填 id
  • update:动态 set
  • pageQuery:left join category 联表查出 categoryName
  • list:条件列表查询

admin/user 两端的 SetmealController、SetmealService(Impl)、SetmealMapper 此前已在工程中就位。

踩坑修复#

  • RedisConfiguration.redisTemplate 方法缺失 @Bean 注解,导致自定义 StringRedisSerializer 不生效——@Autowired 注入的实际是 Spring Boot 默认的 JDK 序列化模板;补上 @Bean 后恢复正常。
  • UserServiceImpl 中残留无用 import org.aspectj.bridge.Message,删除。

可优化点#

  • RedisConfiguration.redisTemplate 使用原始类型 RedisTemplate(未带泛型),改为 RedisTemplate<String,Object> 可获得类型安全并消除 unchecked 警告(警告级,不影响编译)。
  • 历史订单分页当前是「分页查订单 + 逐条查明细」的 N+1 结构;订单量大时可先取出本页订单 id,再 WHERE order_id IN (...) 批量查明细,按 orderId 分组组装。

代码锚点#

知识点代码位置
多表事务(订单+明细+清购物车)OrderServiceImpl.submit
useGeneratedKeys 主键回填 → 明细 setOrderIdOrderMapper.xml insert、OrderServiceImpl.submit
PageHelper 物理分页 + 动态过滤 + 倒序OrderServiceImpl.page + OrderMapper.xml pageQuery
一对多 VO 封装(订单+明细列表)N+1OrderServiceImpl.page 遍历 getByOrderId
动态 SQL <set> 部分更新订单OrderMapper.xml update
模拟支付状态流转OrderServiceImpl.payment/paySuccess
@Bean 自定义 RedisTemplate 序列化器RedisConfiguration

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
苍穹外卖 Day04:用户端订单与模拟支付
https://ryuki.icu/posts/sky-takeout-day04/
作者
RK
发布于
2026-08-22
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
RK
Long may the sunshine
公告
Long may the sunshine
分类
标签
最新动态
站点天气
天气加载中…
站点统计
文章
27
分类
6
标签
59
总字数
39,139
篝火已燃
0 天
最后活动
0 天前
每日一签