目录
一、 管理端接口实现 (后台管理系统)
一、订单搜索 (高权重 - 核心管理功能)
1.Controller (OrderController):
2.Service (OrderService):
3.ServiceImpl (OrderServiceImpl):
1.使用MyBatis分页插件PageHelper
2.基础数据查询
4.Mapper (OrderMapper):
5.Mapper XML (OrderMapper.xml):
6.数据转换处理
6.1getOrderVOList(ordersPage);查询订单详情数据 订单分为:订单基础信息+订单详情数据=完整订单信息 这两个信息是放在不同表内的,他们以逻辑外键 订单ID相连
6.2 getOrderDishesStr(orders); 将订单信息拼接为字符串显示
7.结果封装
二、各个状态的订单数量统计 (高权重 - 管理概览)
1.Controller (OrderController):
1.OrderStatisticsVO返回参数编辑
2.Service (OrderService):
3.ServiceImpl (AdminOrderServiceImpl): 编辑编辑
4.Mapper (OrderMapper): 编辑
三、查询订单详情 (高权重 - 操作基础)
1.Controller (OrderController):
2.Service (OrderService):
3.ServiceImpl (OrderServiceImpl):编辑
3.1数据获取流程:
3.2对象转换:
4.Mapper (OrderMapper):
5.getByOrderId()orderDetailMapper.getByOrderId(orders.getId());编辑
四、接单 (核心操作)
1.Controller (OrderController):
2.Service (OrderService):
3.ServiceImpl (OrderServiceImpl):
4.Mapper (OrderMapper): void update(Order order); (通用更新方法)
5.Mapper XML (OrderMapper.xml): 编写 UPDATE 语句更新状态、confirm_time、operator 等字段。编辑
五、拒单 (核心操作)
1.Controller (OrderController):
OrdersRejectionDTO类:
2.Service (AdminOrderService):
3.ServiceImpl (AdminOrderServiceImpl):
4.Mapper (OrderMapper): 同上(更新)。
5.Mapper XML (OrderMapper.xml): 同上(更新更多字段:状态、取消原因类型、取消原因、取消时间)。
六、派送订单 (核心操作)
1.Controller (AdminOrderController):
2.Service (AdminOrderService):
3.ServiceImpl (AdminOrderServiceImpl):
4.Mapper (OrderMapper): 同上。
5.Mapper XML (OrderMapper.xml): 同上(更新状态、delivery_time)。
七、完成订单 (核心操作)
1.Controller (AdminOrderController):
2.Service (AdminOrderService):
3.ServiceImpl (AdminOrderServiceImpl):
4.Mapper (OrderMapper): 同上。
5.Mapper XML (OrderMapper.xml): 同上(更新状态、completion_time)。
八、取消订单 (管理端)
1.Controller (AdminOrderController):
2.Service (AdminOrderService):
3.ServiceImpl (AdminOrderServiceImpl):
4.Mapper (OrderMapper): 同上。
5.Mapper XML (OrderMapper.xml): 同上(更新状态、取消原因类型、取消原因、取消时间)。
二、 用户端接口实现 (小程序/APP)
一.用户下单 (最高权重 - 核心业务起点)
1.Controller (UserOrderController):
2.Service (UserOrderService):
3.ServiceImpl (UserOrderServiceImpl):
4.Mapper
5.Mapper XML (list(动态查询菜品或套餐信息), insert(插入订单数据), insert(插入订单详情)):
二、订单支付 (最高权重 - 核心交易环节)
1.Controller (UserOrderController):
2.Service (UserOrderService):
3.ServiceImpl (UserOrderServiceImpl):
4.Mapper (OrderMapper): 查询订单 (selectByNumberAndUserId), 更新订单状态/支付信息 (update)。
三、历史订单查询 (高权重 - 用户常用)
1.Controller (UserOrderController):
2.Service (UserOrderService):
3.ServiceImpl (UserOrderServiceImpl):
4.Mapper (OrderMapper):
5.Mapper XML (OrderMapper.xml): 编辑
四、查询订单详情 (用户端)
1.Controller (UserOrderController):
2.Service (UserOrderService):
3.ServiceImpl (UserOrderServiceImpl):
4.Mapper (OrderMapper):
5.Mapper XML (OrderMapper.xml): 同管理端详情查询SQL,增加 user_id = #{userId} 条件。
五、取消订单 (用户端)
1.Controller (UserOrderController):
2.Service (UserOrderService):
3.ServiceImpl (UserOrderServiceImpl):
4.Mapper (OrderMapper): 同上(更新)。
5.Mapper XML (OrderMapper.xml): 同上(更新状态、取消原因类型、取消时间)。
六、再来一单 (提升复购)
1.Controller (UserOrderController):
2.Service (UserOrderService):
3.ServiceImpl (UserOrderServiceImpl):
4.Mapper (OrderMapper, OrderDetailMapper, ShoppingCartMapper):
5.Mapper XML (OrderMapper.xml, OrderDetailMapper.xml, ShoppingCartMapper.xml):
七、催单 (提升体验)
1.Controller (UserOrderController):
2.Service (UserOrderService):
3.ServiceImpl (UserOrderServiceImpl):
4.Mapper (): 无
5.Mapper XML (): 无
三、 关键技术与注意事项
四、 总结
引言
-
项目背景: 简述项目核心业务,突出订单模块的核心地位。
-
技术栈: Spring Boot, Spring MVC, MyBatis (Mapper, XML), Lombok (可选), 数据库 (MySQL等)。
-
分层架构简述: 快速回顾
Controller
->Service
(Interface) ->ServiceImpl
(Implementation) ->Mapper
(Interface) ->Mapper.xml
的数据流和职责。 -
本文目标: 聚焦订单模块接口设计,详细讲解管理端和用户端核心接口的实现思路与关键代码,涵盖 Controller、Service、ServiceImpl、Mapper 及 XML 的协作。
一、 订单模块核心实体与状态流转
-
Order
实体核心字段: (简要列出,如 id, userId, amount, status, createTime, updateTime, address, items/snapshot 等) -
订单状态 (Status Enum): 定义关键状态(如:
待支付
、待接单
、已接单/制作中
、派送中
、已完成
、已取消
、已拒绝
),并配以状态流转图,清晰展示管理端和用户端操作如何触发状态变化。
一、 管理端接口实现 (后台管理系统)
按操作频率和业务重要性排序
通用返回参数:
Result
一、订单搜索 (高权重 - 核心管理功能)
代码核心逻辑:分页查询订单数据,将基础订单信息转换为包含详情的VO对象,并封装为分页结果返回。具体流程为:首先通过
PageHelper
设置分页参数并执行订单主表查询;随后调用getOrderVOList
方法将查询到的订单数据转换为VO对象(此过程会补充查询订单详情数据);最后将总记录数和VO列表封装到PageResult
对象中返回。
1.Controller (OrderController
):
GET /admin/order/conditionSearch
- 参数:OrdersPageQueryDTO
- 返回:Result<PageResult>
OrdersPageQueryDTO参数
2.Service (OrderService
):
/*** 根据提供的数据 查询匹配的订单* @param ordersPageQueryDTO* @return*/PageResult QueryOrderAll(OrdersPageQueryDTO ordersPageQueryDTO);
3.ServiceImpl (OrderServiceImpl
):
关键点详解分页初始化
1.使用MyBatis分页插件PageHelper
设置当前页码(page
)和每页记录数(pageSize
)
注意:这行代码必须紧挨在Mapper调用前,否则会导致分页失效java
PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
2.基础数据查询
Page<Orders> ordersPage = orderMapper.OrderPage(ordersPageQueryDTO);
执行Mapper层查询,返回Page<Orders>
对象
ordersPage
包含:
当前页的订单数据列表(
List<Orders>
)分页信息(总记录数、总页数等)
4.Mapper (OrderMapper
):
Page<Orders> OrderPage(OrdersPageQueryDTO ordersPageQueryDTO);
5.Mapper XML (OrderMapper.xml
):
编写动态 SQL (<where>
, <if>
) 处理各种可选查询条件。
关联查询必要的关联信息(如用户信息、订单项快照等)。
实现高效分页 (limit
)。
6.数据转换处理
List<OrderVO> orderVOList = getOrderVOList(ordersPage);
6.1getOrderVOList(ordersPage);查询订单详情数据 订单分为:订单基础信息+订单详情数据=完整订单信息 这两个信息是放在不同表内的,他们以逻辑外键 订单ID相连
/*** 根据order 查询order的详细信息* @param ordersPage* @return*/private List<OrderVO> getOrderVOList(Page<Orders> ordersPage){//创建封装类列表List<OrderVO> orderVOList=new ArrayList<>();//获取当前页的列表数据List<Orders> ordersList=ordersPage.getResult();//判断集合是否为空if(!CollectionUtils.isEmpty(ordersList)){//遍历每个数据for (Orders orders:ordersList){//创建封装类OrderVO orderVO=new OrderVO();//拷贝BeanUtils.copyProperties(orders,orderVO);//拼接描述信息(格式:宫保鸡丁*3;)String orderDishes=getOrderDishesStr(orders);//插入描述信息orderVO.setOrderDishes(orderDishes);orderVOList.add(orderVO);}}return orderVOList;}
6.2 getOrderDishesStr(orders); 将订单信息拼接为字符串显示
/*** 拼接订单详细信息* @param orders* @return*/private String getOrderDishesStr(Orders orders){//查询订单详细信息List<OrderDetail> orderDetailList=orderDetailMapper.getByOrderId(orders.getId());// 将每一条订单菜品信息拼接为字符串(格式:宫保鸡丁*3;)List<String> orderDishes=orderDetailList.stream().map(x->{String orderDish=x.getName()+"*"+x.getNumber()+";";return orderDish;}).collect(Collectors.toList());// 将该订单对应的所有菜品信息拼接在一起return String.join("",orderDishes);}
7.结果封装
return new PageResult(ordersPage.getTotal(), orderVOList);
构建包含以下内容的分页响应:
ordersPage.getTotal()
:总记录数(来自Page对象)
orderVOList
:当前页的VO数据列表
-
二、各个状态的订单数量统计 (高权重 - 管理概览)
这段代码的核心逻辑是:统计订单三种状态(退款、已确认、派送中)的数量并封装成VO对象返回。具体通过三次独立查询获取各状态订单数量:先查询退款状态订单数,再查询已确认状态订单数,最后查询派送中状态订单数,最终将这些统计值设置到OrderStatisticsVO对象的对应属性中返回。
1.Controller (OrderController
):
GET /admin/order/statistics
- 参数:无
- 返回:自定义
OrderStatisticsVO
,包含各状态订单数量。
1.OrderStatisticsVO返回参数

2.Service (OrderService
):
OrderStatisticsVO QueryOrderStatusNums();
3.ServiceImpl (AdminOrderServiceImpl
): 

4.Mapper (OrderMapper
): 
三、查询订单详情 (高权重 - 操作基础)
这段代码的核心逻辑是:根据订单ID查询订单主信息及关联的订单详情列表,组装为VO对象返回。具体过程为:首先通过订单ID查询主订单数据(
Orders
对象),再根据该订单ID查询对应的订单详情列表(OrderDetail
集合),最后将主订单属性拷贝到OrderVO
对象并设置详情列表后返回。
1.Controller (OrderController
):
GET: /admin/order/details/{id}
参数: Long id (订单Id)
- 返回:
OrderVO
,包含订单所有详细信息(主表信息、用户信息、地址、订单项详情等)。 - OrderVO参数
2.Service (OrderService
):
OrderVO QueryOrderDeliver(Long id);
3.ServiceImpl (OrderServiceImpl
):
-
3.1数据获取流程:
- 先通过订单ID查询主表信息(
Orders
) - 再通过订单ID查询关联的明细数据(
OrderDetail
) -
3.2对象转换:
- 使用
BeanUtils.copyProperties
简化属性复制 - 最后组装成前端需要的VO对象
4.Mapper (OrderMapper
):
orderMapper.SelectOrderID(id);
5.getByOrderId()
orderDetailMapper.getByOrderId(orders.getId());
四、接单 (核心操作)
这段代码的核心逻辑是:验证并执行订单接单操作。具体流程为:首先根据传入的ID查询订单数据,校验订单是否存在且处于待接单状态(状态码为REFUND);若校验失败则抛出业务异常;校验通过后创建新订单对象,设置ID并将状态更新为已确认(CONFIRMED),最后调用Mapper执行状态更新。
1.Controller (OrderController
):
PUT /admin/order/confirm
- 参数:
OrdersConfirmDTO
(包含orderId
,可能包含接单备注等)。 - 返回:操作成功信息。
OrdersConfirmDTO参数:
2.Service (OrderService
):
void confirmOrder(OrdersConfirmDTO ordersConfirmDTO);
3.ServiceImpl (OrderServiceImpl
):
- 查询订单
- 校验订单状态是否为
待接单
。 - 更新订单状态为
已接单
(Order.Status.CONFIRMED
),设置接单状态。 - 调用
OrderMapper.update(Order order)
。
4.Mapper (OrderMapper
): void update(Order order);
(通用更新方法)
5.Mapper XML (OrderMapper.xml
): 编写 UPDATE
语句更新状态、confirm_time
、operator
等字段。
五、拒单 (核心操作)
这段代码的核心逻辑是:执行订单拒单操作并更新订单状态。具体流程为:首先验证订单是否存在且处于待接单状态(状态码REFUND),校验失败则抛出异常;通过校验后创建新订单对象,设置订单状态为已取消(CANCELLED),同时记录拒单原因和取消时间(当前时间),最后调用Mapper执行更新。其中包含一段被注释的退款逻辑(支付状态下需调用微信退款接口),但当前未实际执行。
1.Controller (OrderController
):
PUT /admin/order/rejection
- 参数:
OrdersRejectionDTO
(包含orderId
,rejectionReason
- 必填)。 - 返回:操作成功信息。
OrdersRejectionDTO类:
2.Service (AdminOrderService
):
void rejectionOrder(OrdersRejectionDTO ordersRejectionDTO);
3.ServiceImpl (AdminOrderServiceImpl
):
- 校验订单状态是否为
待接单
。 - 更新订单状态为
已取消
,取消原因类型为 前端传输的拒绝原因、取消时间。 - 调用
OrderMapper.update(Order order)
。 - (重要) 如果原订单已支付,调用支付退款接口。
4.Mapper (OrderMapper
): 同上(更新)。
5.Mapper XML (OrderMapper.xml
): 同上(更新更多字段:状态、取消原因类型、取消原因、取消时间)。
六、派送订单 (核心操作)
这段代码的核心逻辑是:执行订单派送操作,将订单状态从待派送更新为派送中。具体流程为:首先根据订单ID查询订单数据,校验订单是否存在且处于待派送状态(状态码CONFIRMED);若校验失败则抛出业务异常;通过校验后创建新订单对象,设置ID并将状态更新为派送中(DELIVERY_IN_PROGRESS),最后调用Mapper执行状态更新。
1.Controller (AdminOrderController
):
PUT /admin/order/delivery/{id}
参数:Long id(订单Id)
- 返回:操作成功信息。
2.Service (AdminOrderService
):
void delivery(Long id);
3.ServiceImpl (AdminOrderServiceImpl
):
- 校验订单状态是否为 待派送
- 更新订单状态为
派送中
(Order.Status.DELIVERY_IN_PROGRESS
)。 - 设置订单ID,订单状态
- 调用
OrderMapper.update(...)
。
4.Mapper (OrderMapper
): 同上。
5.Mapper XML (OrderMapper.xml
): 同上(更新状态、delivery_time
)。
七、完成订单 (核心操作)
这段代码的核心逻辑是:执行订单完成操作,将派送中的订单更新为已完成状态。具体流程为:首先根据订单ID查询订单数据,校验订单是否存在且处于派送中状态(状态码DELIVERY_IN_PROGRESS);校验失败则抛出业务异常;通过校验后创建新订单对象,设置ID、将状态更新为已完成(COMPLETED)并记录当前送达时间,最后调用Mapper执行状态更新。
1.Controller (AdminOrderController
):
PUT /admin/order/complete/{id}
参数:Long id(订单Id)
- 返回:操作成功信息。
2.Service (AdminOrderService
):
void complete(Long id);
3.ServiceImpl (AdminOrderServiceImpl
):
- 校验订单状态是否为
派送中
。 - 更新订单状态为
已完成
(Order.Status.COMPLETED
)。 - 设置订单ID,订单状态、完成时间
- 调用
OrderMapper.update(...)
。
4.Mapper (OrderMapper
): 同上。
5.Mapper XML (OrderMapper.xml
): 同上(更新状态、completion_time
)。
八、取消订单 (管理端)
这段代码的核心逻辑是:执行订单取消操作,将已接单订单更新为已取消状态。具体流程为:首先根据订单ID查询订单数据,校验订单是否存在且处于已接单状态(状态码CONFIRMED);校验失败则抛出业务异常;通过校验后创建新订单对象,设置ID、将状态更新为已取消(CANCELLED)并记录取消原因及当前取消时间,最后调用Mapper执行状态更新。其中包含一段被注释的退款逻辑(支付状态下需调用微信退款接口),但当前未实际执行。
1.Controller (AdminOrderController
):
PUT /admin/order/cancel
- 参数:
OrdersCancelDTO
(包含orderId
,cancelReason
- 必填)。 - 返回:操作成功信息。
OrdersCancelDTO参数:
2.Service (AdminOrderService
):
void cancel(OrdersCancelDTO ordersCancelDTO);
3.ServiceImpl (AdminOrderServiceImpl
):
- 校验订单状态(通常允许在
已接单
等状态取消,具体看业务)。 - 更新订单状态为
已取消
,记录取消原因、取消时间 - 调用
OrderMapper.update(...)
。 - (重要) 如果原订单已支付,调用支付退款接口。
4.Mapper (OrderMapper
): 同上。
5.Mapper XML (OrderMapper.xml
): 同上(更新状态、取消原因类型、取消原因、取消时间)。
二、 用户端接口实现 (小程序/APP)
按用户操作流程和核心体验排序
一.用户下单 (最高权重 - 核心业务起点)
这段代码的核心逻辑是:执行用户下单全流程,包括地址与购物车校验、订单数据构建与插入、订单明细生成、购物车清理及结果返回。具体流程为:首先校验配送地址有效性及用户购物车非空;随后构建订单主数据(填充地址、用户信息、时间戳订单号等),设置初始状态为待付款并插入订单表;接着遍历购物车条目转换为订单明细对象并批量插入;完成后清空用户购物车;最终封装订单ID、下单时间、订单号和金额等基础信息返回VO对象。整个过程通过
@Transactional
保证事务一致性。
1.Controller (UserOrderController
):
POST /user/order/submit
- 参数:
OrdersSubmitDTO
(包含地址ID、支付方式、备注、购物车商品信息等)。 - 返回:
OrderSubmitVO
(包含orderId
,orderNumber
,orderAmount
,orderTime
等)。
OrderSubmitVO参数
2.Service (UserOrderService
):
OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO);
3.ServiceImpl (UserOrderServiceImpl
):
-
数据校验
-
验证配送地址有效性(地址簿ID存在性)
-
验证用户购物车非空(通过用户ID查询购物车条目)
-
-
订单创建
-
构建订单主数据(复制DTO属性,填充时间戳订单号、用户信息、地址信息等)
-
设置初始状态:待付款(
PENDING_PAYMENT
)和未支付(UN_PAID
) -
执行订单主表插入
-
-
订单明细处理
-
遍历购物车条目,转换为订单明细对象(关联新订单ID)
-
批量插入订单明细表
-
-
清理购物车
-
删除当前用户购物车所有条目
-
-
返回结果
-
封装基础订单信息(ID、下单时间、订单号、金额)返回
-
4.Mapper
/*** 根据id查询* @param id* @return*/
@Select("select * from address_book where id = #{id}")
AddressBook getById(Long id);
/*** 动态查询菜品或套餐信息* @param shoppingCart* @return*/
List<ShoppingCart> list(ShoppingCart shoppingCart);
/*** 根据id查询地址* @param addressId* @return*/
@Select("select * from address_book where id=#{addressId}")
AddressBook getByUserId(Long addressId);
/*** 插入订单数据* @param orders*/
void insert(Orders orders);
/*** 插入订单详情* @param orderDetailList*/
void inset(List<OrderDetail> orderDetailList);
/*** 清空购物车* @param userId*/
@Delete("delete from shopping_cart where user_id=#{userId}")
void DeleShoppingCart(Long userId);
5.Mapper XML (list(动态查询菜品或套餐信息), insert(插入订单数据), insert(
插入订单详情)
):
- list(动态查询菜品或套餐信息)
- insert(插入订单数据)
insert(
插入订单详情)
二、订单支付 (最高权重 - 核心交易环节)
这段代码的核心逻辑是:模拟微信支付流程,生成预支付交易单并返回支付参数。具体流程为:首先获取当前用户信息(含openid),调用微信支付工具生成预支付单(传入订单号、象征性金额0.01元、固定描述和用户openid);若返回结果提示"ORDERPAID"(订单已支付)则抛出业务异常;最终将支付接口返回的JSON数据转换为VO对象,并特殊处理package字段(避免Java关键字冲突)后返回。注:实际支付场景因缺少商户资质无法真实调用,仅作演示用途。
1.Controller (UserOrderController
):
PUT /user/order/payment
- 参数:
OrdersPaymentDTO
(包含orderNumber
,payMethod
- 可能微信支付码等)。 - 返回:支付结果信息(根据支付平台返回封装)。
2.Service (UserOrderService
):
OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception;
3.ServiceImpl (UserOrderServiceImpl
):
校验订单号有效性、订单状态为 待支付
、订单用户归属。
调用第三方支付接口 (如微信支付):
- 构造支付请求参数(订单号、金额、描述、用户openid等)。
- 发起预支付请求,获取预支付交易标识 (prepay_id)。
- 生成小程序/APP端调起支付所需参数(签名、时间戳等)。
- (模拟支付场景): 直接修改订单状态为
待接单
,记录支付时间。 - 返回支付参数或成功标识。
4.Mapper (OrderMapper
): 查询订单 (selectByNumberAndUserId
), 更新订单状态/支付信息 (update
)。
三、历史订单查询 (高权重 - 用户常用)
这段代码的核心逻辑是:分页查询当前用户的历史订单(支持状态过滤),并将每个订单与其详情列表组合为VO对象返回。具体流程为:首先设置分页参数并构建查询条件(包含当前用户ID和订单状态);执行分页查询获取订单主数据;遍历每个订单,根据订单ID查询对应的订单详情列表;将主订单属性拷贝到VO对象并设置详情列表;最终封装分页结果(总记录数+VO列表)返回。
1.Controller (UserOrderController
):
GET /user/order/historyOrders
- 参数:页码、每页条数、订单状态(可选,可查询多个状态)。
- 返回:分页对象
PageResult
,包含订单概览信息列表。
2.Service (UserOrderService
):
PageResult PageOrder(int page, int pageSize, Integer status);
3.ServiceImpl (UserOrderServiceImpl
):
-
分页初始化
通过PageHelper.startPage()
设置分页参数(页码+每页数量) -
构建查询条件
-
获取当前用户ID(
BaseContext.getCurrentId()
) -
设置订单状态过滤条件(
status
参数) -
封装为DTO对象(
OrdersPageQueryDTO
)
-
-
主订单查询
调用orderMapper.OrderPage()
执行分页查询,获取订单主表数据(Page<Orders>
对象) -
订单详情装配
遍历每个订单:-
根据订单ID查询关联的订单详情(
orderDetailMapper.getByOrderId()
) -
将主订单属性拷贝到VO对象(
BeanUtils.copyProperties
) -
将详情列表注入VO对象(
setOrderDetailList()
) -
组装为VO列表(
orderVOS
)
-
-
返回分页结果
封装总记录数(ordersPage.getTotal()
)和VO列表到PageResult
对象返回
4.Mapper (OrderMapper
):
/*** 查询订单 根据封装类查询* @param ordersPageQueryDTO* @return*/
Page<Orders> OrderPage(OrdersPageQueryDTO ordersPageQueryDTO);
@Select("select * from order_detail where order_id=#{OrderID}")
List<OrderDetail> getByOrderId(Long OrderID);
5.Mapper XML (OrderMapper.xml
): 
四、查询订单详情 (用户端)
这段代码的核心逻辑是:根据订单ID查询订单主信息及关联的详情列表,组装成VO对象返回。具体执行流程为:首先校验订单ID非空(若为空则返回null);随后通过ID查询主订单数据,再根据订单ID查询对应的订单详情列表;最后创建VO对象,将主订单属性拷贝至VO并注入详情列表后返回。
1.Controller (UserOrderController
):
GET /user/order/orderDetail/{id}
参数:Long id(订单Id)
- 返回:
OrderVO
(同管理端详情,但确保只返回当前用户的数据)。
2.Service (UserOrderService
):
OrderVO OrderByDetai(Long id);
3.ServiceImpl (UserOrderServiceImpl
):
-
订单ID校验
首先检查传入的订单ID是否为null
,若为空直接返回null
(避免无效查询) -
主订单查询
调用orderMapper.SelectOrderID(id)
获取订单主表数据(Orders
对象)
注意:此处未处理orders
为null
的情况(订单不存在时后续会抛NPE) -
订单详情查询
通过orderDetailMapper.getByOrderId()
根据订单ID查询关联的菜品/商品明细(返回List<OrderDetail>
) -
VO对象组装
-
创建
OrderVO
空对象 -
使用
BeanUtils.copyProperties
将主订单属性拷贝到VO -
将详情列表注入VO的
orderDetailList
属性
-
-
返回完整数据
返回包含主订单信息+详情列表的OrderVO
对象
4.Mapper (OrderMapper
):
/*** 根据id查询订单* @param id* @return*/
@Select("select * from orders where id=#{id}")
Orders SelectOrderID(Long id);
/*** 查询订单详情信息* @param OrderID* @return*/
@Select("select * from order_detail where order_id=#{OrderID}")
List<OrderDetail> getByOrderId(Long OrderID);
5.Mapper XML (OrderMapper.xml
): 同管理端详情查询SQL,增加 user_id = #{userId}
条件。
五、取消订单 (用户端)
这段代码的核心逻辑是:处理用户取消订单请求,仅允许取消待支付(状态1)和待接单(状态2)的订单,其他状态需联系商家协商。具体流程为:首先验证订单存在性,再校验订单状态是否≤2(非此范围则抛出异常);通过校验后创建新订单对象,设置状态为已取消(6),记录"用户主动取消"原因及当前取消时间,最后调用Mapper执行状态更新。原始设计中待接单状态需触发退款逻辑(调用微信退款接口),但因支付功能未实现而被注释。
1.Controller (UserOrderController
):
PUT /user/order/cancel/{id}
参数:Long id(订单Id)
- 返回:操作成功信息。
2.Service (UserOrderService
):
void UpdateOrderStatus(Long id);
3.ServiceImpl (UserOrderServiceImpl
):
-
校验订单有效性
-
通过订单ID查询订单,若不存在则抛出异常
-
仅允许取消待支付(1)和待接单(2)状态的订单(状态值≤2),其他状态抛出异常
-
-
退款处理(注释状态)
-
原始设计:待接单状态需调用微信退款接口(因支付功能未实现,当前逻辑被注释)
-
若执行退款需更新支付状态为
REFUND
-
-
更新订单状态
-
设置订单状态为已取消(
CANCELLED
) -
记录取消原因为"用户主动取消"
-
记录取消时间为当前时间
-
调用Mapper执行状态更新
-
4.Mapper (OrderMapper
): 同上(更新)。
5.Mapper XML (OrderMapper.xml
): 同上(更新状态、取消原因类型、取消时间)。
六、再来一单 (提升复购)
这段代码的核心逻辑是:将指定订单的菜品详情复制到当前用户的购物车中,实现"再来一单"功能。具体流程为:首先获取当前用户ID;再根据订单ID查询原订单的菜品详情列表;通过流式处理将每个菜品详情对象转换为购物车对象(复制除ID外的所有属性,并设置用户ID和当前创建时间);最终将转换后的购物车对象列表批量插入数据库。
1.Controller (UserOrderController
):
POST /user/order/repetition/{id}
参数:Long id(订单Id)
- 返回:操作成功信息或新订单ID (可选)。
2.Service (UserOrderService
):
void repetitionOrder(Long id);
3.ServiceImpl (UserOrderServiceImpl
):
-
获取当前用户身份
BaseContext.getCurrentId()
获取当前登录用户的ID -
查询历史订单详情
通过orderDetailMapper.getByOrderId(id)
根据订单ID获取原订单包含的所有菜品/商品明细(List<OrderDetail>
) -
数据转换处理
使用 Java Stream API 将订单明细转换为购物车对象:orderDetailList.stream().map(x->{...})
-
对象拷贝:通过
BeanUtils.copyProperties
将菜品属性(名称、价格、数量等)从订单明细拷贝到新购物车对象 -
排除ID:拷贝时忽略原ID(
"id"
参数),确保插入时生成新ID -
绑定用户:设置购物车项的归属用户(
setUserId(userid)
) -
设置时间:添加当前时间作为创建时间(
setCreateTime(LocalDateTime.now())
)
-
-
批量写入数据库
shoppingCartMapper.insertBatch(shoppingCartList)
将转换后的购物车对象列表一次性批量插入购物车表
4.Mapper (OrderMapper
, OrderDetailMapper
, ShoppingCartMapper
):
/*** 查询订单详情信息* @param OrderID* @return*/
@Select("select * from order_detail where order_id=#{OrderID}")
List<OrderDetail> getByOrderId(Long OrderID);
/*** 批量插入购物车对象* @param shoppingCartList*/
void insertBatch(List<ShoppingCart> shoppingCartList);
5.Mapper XML (OrderMapper.xml
, OrderDetailMapper.xml
, ShoppingCartMapper.xml
):
七、催单 (提升体验)
这段代码的核心逻辑是:处理用户催单请求,通过WebSocket向所有在线商家客户端广播催单通知。具体流程为:首先根据订单ID查询订单数据,若订单不存在则抛出异常;随后构建包含催单类型标识(type=2)、订单ID及订单号文本的消息内容;将消息转换为JSON格式后,调用WebSocket服务端方法
sendToAllClient()
实时推送给所有已连接的商家端客户端,触发商家端的语音/弹窗提醒。
1.Controller (UserOrderController
):
GET /user/order/reminder/{id}
参数:Long id(订单Id)
- 返回:操作成功信息(“已提醒商家尽快处理”)。
2.Service (UserOrderService
):
void reminder(Long id);
3.ServiceImpl (UserOrderServiceImpl
):
-
订单查询与校验
-
根据订单ID查询订单数据(
orderMapper.SelectOrderID(id)
) -
若订单不存在,抛出业务异常(
OrderBusinessException
)
-
-
构建催单消息
创建包含催单信息的Map对象:Map map = new HashMap(); map.put("type", 2); // 消息类型:2=催单(区别于1=来单提醒) map.put("orderId", id); // 催单的订单ID map.put("content", "订单号: " + orders.getNumber()); // 拼接订单号文本
-
消息格式转换
使用JSON.toJSONString()
将Map对象转换为JSON字符串,准备网络传输 -
实时消息推送
调用webSocketServer.sendToAllClient()
将JSON格式的催单消息广播给所有已连接的商家端客户端
4.Mapper (): 无
5.Mapper XML (): 无
三、 关键技术与注意事项
-
事务管理 (
@Transactional
): 强调在下单
、涉及多表更新的操作(如取消订单涉及状态更新+退款申请)上使用事务保证数据一致性。 -
数据脱敏: 用户端返回的敏感信息(如电话号码、详细地址)适当脱敏。
-
状态校验: 所有状态变更操作 (
接单
、拒单
、取消
、完成
、支付
) 必须严格校验当前状态是否符合业务规则。 -
幂等性: 对于支付回调、重要的状态变更接口,考虑实现幂等(如通过唯一业务流水号)。
-
日志记录: 关键操作(尤其是管理端操作和支付相关)记录详细操作日志。
-
异常处理: 定义清晰的业务异常 (
OrderBusinessException
,AddressBookBusinessException
等),在Controller层统一捕获并返回友好错误信息。 -
参数校验: 使用
Spring Validation
(@Valid
) 或手动校验DTO参数的有效性、非空等。 -
DTO / VO 的应用: 清晰区分数据传输对象 (DTO) 和视图对象 (VO),避免实体类直接暴露给前端。
四、 总结
-
回顾订单模块的核心接口及其在管理端和用户端的分工。
-
强调分层设计 (Controller/Service/Mapper) 和状态机管理的重要性。
-
提示读者关注安全(权限、归属)、事务、幂等、日志等关键实践点。
-
展望可能的优化点:分库分表(海量订单)、订单超时自动取消(定时任务)、更复杂的统计报表等。