苍穹外卖-day09

3 阅读5分钟

1)Day09 你要完成的功能清单(交付物)

两大模块 + 一个优化点:

  • 用户端历史订单模块:查询历史订单、查询订单详情、取消订单、再来一单
  • 商家端订单管理模块:订单搜索、各状态数量统计、查询订单详情、接单、拒单、取消、派送、完成
  • 优化:用户下单时校验配送范围(5公里),超出则下单失败

验收方式:按原型做需求分析→按接口文档做实现→Swagger + 前后端联调测试


2)先把“订单状态流转”刻进脑子(后面全靠它判错)

用户端历史订单接口会用到状态过滤(1待付款、2待接单、3已接单、4派送中、5已完成、6已取消)
商家端的操作本质都是“校验状态 → 更新状态”,比如:

  • 派送:只有 已接单(3) 才能派送,更新为派送中
  • 完成:只有 派送中(4) 才能完成,更新为已完成并记录时间

你写每个接口前先写一句: “允许的前置状态是什么?” ,不满足就抛 ORDER_STATUS_ERROR 这类业务异常。


3)模块A:用户端历史订单(4个功能)

A1. 查询历史订单(分页 + 可按状态)

业务规则:分页查询;可按状态查;列表要展示下单时间/状态/金额/订单明细(商品名、图片等)
实现套路(核心就这几步):

  1. Controller:GET /historyOrders 接收 page/pageSize/status
  2. Service:PageHelper.startPageordersPageQueryDTO 塞 userId、status → orderMapper.pageQuery
  3. 遍历订单:按 orderId 查明细 orderDetailMapper.getByOrderId,封装到 OrderVO.orderDetailList

学习点:这是典型的“主表分页 + 子表明细补齐”(会有 N+1 查询,但课程场景OK)。


A2. 查询订单详情

你要返回:订单基本信息 + 明细(商品名/数量/单价)这类数据
实现上通常就是:orderMapper.getById(id) + orderDetailMapper.getByOrderId(id) → 填进 OrderVO


A3. 取消订单(用户端)

取消这种接口一定要先写“业务规则”:只有特定状态允许取消,并且如果已支付要走退款逻辑(参考答案里商家拒单/取消都有“已支付则退款”的模式)
你写的时候建议按这个顺序:

  1. 查订单是否存在
  2. 校验状态是否允许取消(只允许“待付款/待接单”等)
  3. 若已支付:调用退款(课程里一般有 wechatPayUtil 之类)
  4. 更新订单:状态=已取消、取消原因/取消时间、必要时 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

你要做的事情

  1. application.yml 配置
  • sky.shop.address(店铺地址)
  • sky.baidu.ak(百度地图 AK)
    参考答案也用 @Value 注入这两个配置
  1. 在 OrderServiceImpl 写校验方法 checkOutOfRange(address)
    核心逻辑:
  • 调 geocoding 接口把店铺地址→经纬度
  • 调 geocoding 接口把用户收货地址→经纬度
  • 调 directionlite driving 获取距离 distance;distance > 5000 抛异常“超出配送范围”
  1. 在 submitOrder 里尽早调用校验
    day08 的 submitOrder 里已经有“地址为空/购物车为空”的异常处理
    你把 checkOutOfRange(addressBook.getDetail()) 放在“地址校验通过之后、构造订单之前”最合适(失败就直接返回,不污染数据)。


6)一套最小测试用例(做完就算过关)

  • 用户端:

    • historyOrders:status 为空/有值都能分页查到
    • repetition:调用后 shopping_cart 表新增多条记录
  • 商家端:

    • confirm:待接单→已接单
    • delivery:已接单→派送中
    • complete:派送中→已完成(deliveryTime 写入)
  • 配送范围:

    • 配一个很远的收货地址,下单直接失败并提示“超出配送范围”