【苍穹外卖 Day09|订单管理与配送范围校验】
前言Day09 的实战围绕订单模块展开用户需要能查看和复用历史订单商家需要按订单状态处理业务同时系统还要在下单前判断收货地址是否处于配送范围内。这几个功能共享同一条主线订单状态必须按照业务规则流转任何状态修改前都要先完成必要校验。文章结合当前项目代码梳理用户端订单、商家端订单管理以及 5 公里配送范围校验的实现。一、先确定订单的状态与流转规则订单表中的 status 和 payStatus 分别描述业务状态与支付状态。当前项目定义如下publicstaticfinalIntegerPENDING_PAYMENT1;publicstaticfinalIntegerTO_BE_CONFIRMED2;publicstaticfinalIntegerCONFIRMED3;publicstaticfinalIntegerDELIVERY_IN_PROGRESS4;publicstaticfinalIntegerCOMPLETED5;publicstaticfinalIntegerCANCELLED6;publicstaticfinalIntegerUN_PAID0;publicstaticfinalIntegerPAID1;publicstaticfinalIntegerREFUND2;正常的状态流转为待付款 → 待接单 → 已接单 → 派送中 → 已完成。用户或商家取消订单、商家拒单时订单会进入已取消状态。这里不能只根据前端按钮判断能否操作。服务层必须重新查询订单并以数据库中的状态作为判断依据。例如商家接单时当前订单必须处于待接单状态publicvoidconfirm(Longid){OrdersordersDBrequireOrder(id);if(!ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){thrownewOrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);}OrdersordersOrders.builder().id(ordersDB.getId()).status(Orders.CONFIRMED).build();orderMapper.update(orders);}requireOrder 负责查询订单并处理订单不存在的情况通过校验后再构造只包含待更新字段的 Orders 对象交给 Mapper。这样可以避免前端重复提交或请求过期时把订单写入错误状态。二、用户端历史订单列表、详情、取消与再来一单用户端接口统一位于/user/order下Day09 新增的核心接口包括GetMapping(/historyOrders)publicResultPageResulthistoryOrders(OrdersPageQueryDTOordersPageQueryDTO){returnResult.success(orderService.historyOrders(ordersPageQueryDTO));}GetMapping(/orderDetail/{id})publicResultOrderVOorderDetail(PathVariableLongid){returnResult.success(orderService.orderDetail(id));}PutMapping(/cancel/{id})publicResultcancel(PathVariableLongid){orderService.cancel(id);returnResult.success();}PostMapping(/repetition/{id})publicResultrepetition(PathVariableLongid){orderService.repetition(id);returnResult.success();}1. 历史订单列表为什么还要查询订单明细订单列表不仅要展示订单号、金额和下单时间还要展示菜品信息。因此订单分页查询完成后服务层会遍历当前页订单根据订单 id 查询订单明细表并将结果放进 OrderVO。publicPageResulthistoryOrders(OrdersPageQueryDTOordersPageQueryDTO){ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());PageHelper.startPage(ordersPageQueryDTO.getPage(),ordersPageQueryDTO.getPageSize());PageOrderVOpageorderMapper.pageQuery(ordersPageQueryDTO);for(OrderVOorderVO:page.getResult()){ListOrderDetaildetailsorderdetailMapper.getByOrderId(orderVO.getId());orderVO.setOrderDetailList(details);tryFillAddress(orderVO);}returnnewPageResult(page.getTotal(),page.getResult());}BaseContext.getCurrentId() 把当前登录用户 id 写入查询条件保证用户只能看自己的订单。Mapper 中的用户 id、状态、订单号、手机号和下单时间均是可选条件最后按下单时间倒序排列selectidpageQueryresultTypecom.sky.vo.OrderVOselect * from orderswhereiftestnumber ! null and number ! and number like concat(%, #{number}, %)/ififtestuserId ! nulland user_id #{userId}/ififteststatus ! nulland status #{status}/if/whereorder by order_time desc/select2. 查询详情时补齐数据并校验订单归属用户请求订单详情时不能直接用订单 id 返回数据。项目先验证订单是否属于当前用户再将订单、订单明细和地址组装为 OrderVOprivateOrdersrequireUserOrder(Longid){OrdersordersrequireOrder(id);if(!orders.getUserId().equals(BaseContext.getCurrentId())){thrownewOrderBusinessException(MessageConstant.ORDER_NOT_FOUND);}returnorders;}publicOrderVOorderDetail(Longid){returntoOrderVO(requireUserOrder(id));}这一步既是业务校验也是接口数据隔离。测试时可用 A 用户的 token 请求 B 用户的订单详情预期应返回订单不存在或业务异常而不是暴露订单内容。3. 取消订单与再来一单当前项目的取消逻辑会校验订单归属将状态改为已取消并记录取消时间当支付状态为已支付时会进入退款处理入口。当前代码以日志模拟退款申请文章不把它描述为真实微信退款已经完成。再来一单不重新创建订单而是将原订单明细转换为购物车数据再批量插入购物车表publicvoidrepetition(Longid){LonguserIdBaseContext.getCurrentId();ListOrderDetaildetailsorderdetailMapper.getByOrderId(id);ListShoppingCartcartsdetails.stream().map(detail-{ShoppingCartcartnewShoppingCart();BeanUtils.copyProperties(detail,cart,id);cart.setUserId(userId);cart.setCreateTime(LocalDateTime.now());returncart;}).collect(Collectors.toList());shoppingCartMapper.insertBatch(carts);}复制时排除原订单明细 id避免把旧记录的主键带入购物车。接口返回成功后前端跳转购物车即可让用户确认数量、口味和地址再重新提交订单。三、商家端订单管理围绕状态处理订单商家端接口前缀为 /admin/order包含订单搜索、状态数量统计、详情查询和订单状态处理。1. 搜索与状态数量统计订单搜索复用 OrdersPageQueryDTO支持订单号、手机号、状态、开始时间和结束时间等条件。分页结果中的每条订单还会补充菜品名称和数量供管理端列表直接展示。状态统计则按待接单、待派送和派送中三种状态分别查询publicOrderStatisticsVOstatistics(){OrderStatisticsVOresultnewOrderStatisticsVO();result.setToBeConfirmed(orderMapper.countByStatus(Orders.TO_BE_CONFIRMED));result.setConfirmed(orderMapper.countByStatus(Orders.CONFIRMED));result.setDeliveryInProgress(orderMapper.countByStatus(Orders.DELIVERY_IN_PROGRESS));returnresult;}对应 SQL 很简单但状态常量必须和前端标签一致selectidcountByStatusresultTypejava.lang.Integerselect count(*) from orders where status #{status}/select2. 拒单、派送和完成订单的校验差异拒单只允许待接单订单操作已支付订单需要进入退款入口并记录拒单原因和取消时间publicvoidreject(OrdersRejectionDTOdto){OrdersordersDBorderMapper.getById(dto.getId());if(ordersDBnull||!ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){thrownewOrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);}if(ordersDB.getPayStatus().equals(Orders.PAID)){log.info(申请退款:{},ordersDB.getNumber());}orderMapper.update(Orders.builder().id(ordersDB.getId()).status(Orders.CANCELLED).rejectionReason(dto.getRejectionReason()).cancelTime(LocalDateTime.now()).build());}派送订单必须从已接单状态进入派送中完成订单必须从派送中进入已完成。把每个动作的前置状态写死在服务层订单流转才不会被任意接口跳过。操作允许的原状态更新后的状态额外信息接单待接单已接单无拒单待接单已取消拒单原因、取消时间已支付时退款派送已接单派送中无完成派送中已完成无商家取消订单存在已取消取消时间已支付时退款四、下单前增加 5 公里配送范围校验实战要求规定收货地址距离门店超过 5 公里时下单失败。当前项目将门店地址和百度地图 AK 放入环境配置再在提交订单过程中调用地图 Web 服务。公共配置文件只保留结构真实门店地址和 AK 应放到开发环境配置中提交博客时必须脱敏sky:shop:address:${sky.shop.address}baidu:ak:${sky.baidu.ak}服务层的处理顺序是调用地理编码接口把门店地址转换成经纬度用同一接口解析用户完整收货地址调用驾车路线规划接口得到路线距离当距离大于 5000 米时抛出“超出配送范围”异常只有校验通过才插入订单和订单明细。核心拦截点位于 submitOrderorders.setAddress(buildAddress(addressBook));orders.setUserId(userId);checkOutOfRange(orders.getAddress());orderMapper.insert(orders);checkOutOfRange 中先调用地理编码接口解析两个地址再调用驾车路线规划接口。路线接口的起点和终点坐标格式是“纬度,经度”项目解析首条路线的 distance 字段并以米为单位与 5000 比较。JSONObjectresultjsonObject.getJSONObject(result);JSONArrayroutes(JSONArray)result.get(routes);Integerdistance(Integer)((JSONObject)routes.get(0)).get(distance);if(distance5000){thrownewOrderBusinessException(超出配送范围);}地址解析或路线规划响应的 status 不为 0 时当前代码会抛出“店铺地址解析失败”“收货地址解析失败”或“配送路线规划失败”。这样能阻止无效地址继续创建订单也能让前端给出明确提示。五、如何测试与排查可以先通过 Swagger 接口文档逐个验证再进行前后端联调。建议按以下顺序准备数据创建一笔已支付、待接单订单验证商家接单、拒单和取消订单将订单接单后验证派送再将订单改为派送中验证完成使用当前用户查询历史订单与详情再换一个用户 token 验证订单归属校验调用再来一单检查购物车中是否新增原订单的菜品和套餐明细分别使用门店附近和明显超出范围的收货地址提交订单观察下单成功与“超出配送范围”异常。排查配送校验时优先检查门店地址是否配置、AK 是否有效、地址是否能被解析以及路线响应中是否存在 result.routes。排查订单状态异常时先查询数据库中的状态和支付状态再确认调用的接口是否满足对应动作的前置状态。总结Day09 完成的是一条完整的订单处理链路用户端能管理历史订单商家端能按状态处理订单系统在创建订单前还会根据实际驾车路线拦截超出范围的地址。实现订单模块时每一次状态变化都要有明确的前置条件、需要记录的字段和可验证的结果。

相关新闻

AI生成界面质量保障:组件语义快照实践指南

AI生成界面质量保障:组件语义快照实践指南

1. 组件语义快照:AI生成界面的质量守门人在AI直接生成用户界面的新时代,我们面临一个根本性挑战:如何确保机器输出的界面不仅能用,而且用得明白。去年我在负责某企业级AI设计系统时,曾遇到一个典型案例——同一个红色按…

2026/10/19 2:14:21 阅读更多 →
Spring Boot集成LDAP实现企业级用户管理

Spring Boot集成LDAP实现企业级用户管理

1. 项目概述在企业级应用开发中,用户与组织数据管理是一个常见且关键的需求。传统的关系型数据库虽然能够满足基本存储需求,但在跨系统用户数据同步、权限集中管理等方面存在明显短板。LDAP(轻量级目录访问协议)作为一种专门优化的…

2026/10/17 20:33:14 阅读更多 →
Buck拓扑中自举电路与串联电阻的设计要点

Buck拓扑中自举电路与串联电阻的设计要点

1. 自举电路在Buck拓扑中的核心作用在采用高侧N沟道MOSFET的Buck电路中,自举电路(Bootstrap Circuit)是一个精妙而关键的设计。这个电路通常由自举电容(Cboot)和自举二极管(Dboot)组成&#xff…

2026/10/18 2:03:28 阅读更多 →

最新新闻

Provider 不属于 Agent 核心:rpi 的分层理由与收益

Provider 不属于 Agent 核心:rpi 的分层理由与收益

先把项目定位说清楚,否则"为什么这样分层"没有判断依据。 rpi 是一个 Rust 原生的 coding-agent runtime,加一个建立在它之上的终端 agent。九个 crate 覆盖 provider 适配、可恢复的 agent 循环、工具、会话持久化、终端界面和一套稳定的插件…

2026/10/19 2:14:32 阅读更多 →
2026考证培训刷题功能模块怎么搭建

2026考证培训刷题功能模块怎么搭建

考证培训的核心业务是让学员大量刷题、熟悉题型、模考查漏。搭建刷题模块,本质是把题库、答题活动、成绩记录三件事组织起来。乔拓云教育系统是一款专为教育培训机构打造的在线教育解决方案,支持课程售卖、教务管理、学员运营、营销推广等核心场景。 刷题…

2026/10/19 2:14:32 阅读更多 →
STM32+FreeRTOS智能定时电路板实战:从抄板打样到低功耗稳定运行

STM32+FreeRTOS智能定时电路板实战:从抄板打样到低功耗稳定运行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:14:32 阅读更多 →
MM32G0001入门级MCU选型与实操避坑指南

MM32G0001入门级MCU选型与实操避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:14:32 阅读更多 →
工业自动化上位机实战:通讯协议、数据采集与老化测试系统设计

工业自动化上位机实战:通讯协议、数据采集与老化测试系统设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:14:32 阅读更多 →
纠正一句默认配置:入门档不等于日常档编程

纠正一句默认配置:入门档不等于日常档编程

很多笔记把入门档写成默认项。这句需要加条件。 | 用法 | 先看哪一档 | 还要核对 | |---|---|---| | 偶尔试一次 | 入门档 | 期限。短期限和长期限不能只比总价 | | 每个工作日都在用 | 日常档 | 够不够当天的活 | | 卡在一件具体任务 | 更高档 | 页面写明多了什么&#xff0c…

2026/10/19 2:13:32 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →