1)Day09 你要完成的功能清单(交付物)
两大模块 + 一个优化点:
- 用户端历史订单模块:查询历史订单、查询订单详情、取消订单、再来一单
- 商家端订单管理模块:订单搜索、各状态数量统计、查询订单详情、接单、拒单、取消、派送、完成
- 优化:用户下单时校验配送范围(5公里),超出则下单失败
验收方式:按原型做需求分析→按接口文档做实现→Swagger + 前后端联调测试
2)先把“订单状态流转”刻进脑子(后面全靠它判错)
用户端历史订单接口会用到状态过滤(1待付款、2待接单、3已接单、4派送中、5已完成、6已取消)
商家端的操作本质都是“校验状态 → 更新状态”,比如:
- 派送:只有 已接单(3) 才能派送,更新为派送中
- 完成:只有 派送中(4) 才能完成,更新为已完成并记录时间
你写每个接口前先写一句: “允许的前置状态是什么?” ,不满足就抛
ORDER_STATUS_ERROR这类业务异常。
3)模块A:用户端历史订单(4个功能)
A1. 查询历史订单(分页 + 可按状态)
业务规则:分页查询;可按状态查;列表要展示下单时间/状态/金额/订单明细(商品名、图片等)
实现套路(核心就这几步):
- Controller:
GET /historyOrders接收 page/pageSize/status - Service:
PageHelper.startPage→ordersPageQueryDTO塞 userId、status →orderMapper.pageQuery - 遍历订单:按 orderId 查明细
orderDetailMapper.getByOrderId,封装到OrderVO.orderDetailList
学习点:这是典型的“主表分页 + 子表明细补齐”(会有 N+1 查询,但课程场景OK)。
A2. 查询订单详情
你要返回:订单基本信息 + 明细(商品名/数量/单价)这类数据
实现上通常就是:orderMapper.getById(id) + orderDetailMapper.getByOrderId(id) → 填进 OrderVO
A3. 取消订单(用户端)
取消这种接口一定要先写“业务规则”:只有特定状态允许取消,并且如果已支付要走退款逻辑(参考答案里商家拒单/取消都有“已支付则退款”的模式)
你写的时候建议按这个顺序:
- 查订单是否存在
- 校验状态是否允许取消(只允许“待付款/待接单”等)
- 若已支付:调用退款(课程里一般有 wechatPayUtil 之类)
- 更新订单:状态=已取消、取消原因/取消时间、必要时 payStatus=退款
A4. 再来一单(把旧订单明细复制到购物车)
参考答案实现非常标准:
- 先查当前用户 id
- 用订单 id 查订单明细
orderDetailMapper.getByOrderId(id) - stream 把
OrderDetail → ShoppingCart,复制属性(排除 id),补 userId/createTime shoppingCartMapper.insertBatch批量插入
学习点:批量插入、BeanUtils 拷贝、stream 映射,这个是以后写“从A复制到B”的通用模板。
4)模块B:商家端订单管理(8个功能)
B1. 订单搜索(分页 + 条件筛选)
业务规则:订单号/手机号模糊搜索;按状态筛;按下单时间筛;分页展示;空结果提示未找到
实现建议:
- DTO 里通常有:number、phone、status、beginTime、endTime、page/pageSize
- mapper.xml 用动态 SQL(
<if test=...>)拼 where 条件 - 列表页往往还要拼一个 “dishes” 字符串(例如 “宫保鸡丁1; 米饭2”)供前端展示
B2. 各状态订单数量统计
实现思路:对每个状态 countStatus(status),再封装到 OrderStatisticsVO
Mapper 参考答案直接用 SQL:select count(id) from orders where status = #{status}
B3. 查询订单详情
业务规则:展示订单基本信息 + 订单明细
实现:同用户端详情,只是字段可能更多(收货人/地址/备注等)。
B4. 接单
商家接单=状态改为“已接单”,接口 PUT /confirm
B5. 拒单
关键:只能拒“待接单” ;若已支付则退款;写入拒单原因、拒单时间
B6. 取消订单(商家端)
关键:只允许取消特定状态(参考答案给的是“待接单/已接单”);已支付则退款;写取消原因/时间
B7. 派送订单
只有状态为 已接单(3) 才能派送,更新为派送中
B8. 完成订单
只有状态为 派送中(4) 才能完成,更新为已完成并记录时间
5)优化点:下单时校验“超出配送范围(5公里)”
实战要求:超出 5 公里则下单失败;基于百度地图开放平台;店铺地址配置在 yml
你要做的事情
- application.yml 配置
sky.shop.address(店铺地址)sky.baidu.ak(百度地图 AK)
参考答案也用@Value注入这两个配置
- 在 OrderServiceImpl 写校验方法 checkOutOfRange(address)
核心逻辑:
- 调 geocoding 接口把店铺地址→经纬度
- 调 geocoding 接口把用户收货地址→经纬度
- 调 directionlite driving 获取距离 distance;
distance > 5000抛异常“超出配送范围”
- 在 submitOrder 里尽早调用校验
day08 的 submitOrder 里已经有“地址为空/购物车为空”的异常处理
你把checkOutOfRange(addressBook.getDetail())放在“地址校验通过之后、构造订单之前”最合适(失败就直接返回,不污染数据)。
6)一套最小测试用例(做完就算过关)
-
用户端:
- historyOrders:status 为空/有值都能分页查到
- repetition:调用后 shopping_cart 表新增多条记录
-
商家端:
- confirm:待接单→已接单
- delivery:已接单→派送中
- complete:派送中→已完成(deliveryTime 写入)
-
配送范围:
- 配一个很远的收货地址,下单直接失败并提示“超出配送范围”