苍穹外卖 Day04:用户端订单与模拟支付
当日改动集中在 sky-server 与 sky-pojo:用户端订单模块新增 OrderController、OrderServiceImpl、OrderMapper(含 xml)与 OrderDetailMapper,返回 VO 统一放在 sky-pojo;套餐管理的 SetmealMapper.xml 同日起步。
用户端订单接口
OrderController 映射在 /user/order 下,共三个接口:
POST /submit用户下单,返回OrderSubmitVOPUT /payment订单支付(模拟支付,跳过微信支付验证直接标记已支付),返回OrderPaymentVOGET /historyOrders历史订单分页查询,返回PageResult
下单流程
OrderServiceImpl.submit(OrdersSubmitDTO) 的完整链路:
- 校验地址簿:
addressBookMapper.getById,为空抛AddressBookBusinessException - 校验购物车:
BaseContext.getCurrentId()取当前用户 id,shoppingCartMapper.list查询,为空抛ShoppingCartBusinessException - 组装
Orders:BeanUtils.copyProperties复制属性,补 orderTime=now、payStatus=UN_PAID、status=PENDING_PAYMENT、number=时间戳,并从地址簿取 phone/consignee/address 做快照 orderMapper.insert写入订单,useGeneratedKeys回填主键 id- 遍历购物车逐条转
OrderDetail(copyProperties 后 setOrderId=orders.getId()),orderDetailMapper.insertBatch批量插入订单明细 shoppingCartMapper.deleteByUserId清空该用户购物车- 封装
OrderSubmitVO(id/number/amount/orderTime)返回
订单、订单明细、清空购物车跨多张表,整个方法在一个事务内完成。
支付与状态流转
payment(OrdersPaymentDTO):按 orderNumber 查订单,已支付(PAID)则抛OrderBusinessException("该订单已支付");否则调paySuccess模拟支付成功,返回空的OrderPaymentVOpaySuccess(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 回填 idupdate:动态 setpageQuery:left join category 联表查出 categoryNamelist:条件列表查询
admin/user 两端的 SetmealController、SetmealService(Impl)、SetmealMapper 此前已在工程中就位。
踩坑修复
RedisConfiguration.redisTemplate方法缺失@Bean注解,导致自定义StringRedisSerializer不生效——@Autowired注入的实际是 Spring Boot 默认的 JDK 序列化模板;补上@Bean后恢复正常。UserServiceImpl中残留无用 importorg.aspectj.bridge.Message,删除。
可优化点
RedisConfiguration.redisTemplate使用原始类型RedisTemplate(未带泛型),改为RedisTemplate<String,Object>可获得类型安全并消除 unchecked 警告(警告级,不影响编译)。- 历史订单分页当前是「分页查订单 + 逐条查明细」的 N+1 结构;订单量大时可先取出本页订单 id,再
WHERE order_id IN (...)批量查明细,按 orderId 分组组装。
代码锚点
| 知识点 | 代码位置 |
|---|---|
| 多表事务(订单+明细+清购物车) | OrderServiceImpl.submit |
| useGeneratedKeys 主键回填 → 明细 setOrderId | OrderMapper.xml insert、OrderServiceImpl.submit |
| PageHelper 物理分页 + 动态过滤 + 倒序 | OrderServiceImpl.page + OrderMapper.xml pageQuery |
| 一对多 VO 封装(订单+明细列表)N+1 | OrderServiceImpl.page 遍历 getByOrderId |
动态 SQL <set> 部分更新订单 | OrderMapper.xml update |
| 模拟支付状态流转 | OrderServiceImpl.payment/paySuccess |
| @Bean 自定义 RedisTemplate 序列化器 | RedisConfiguration |
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!





















