尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
用工订单状态机:从待确认到已完成,我拿 6 个状态挡住了所有非法跳变
零工平台的工单生命周期比想象中长用户提交申请 → 雇主确认 → 开工打卡 → 完工结算 → 双方评价 → 完成。早期版本里状态就是个字符串字段service 里随手order.setOrderStatus(WORKING)改着改着就乱了——有人从待确认直接改成已完成支付回调还没到订单先跳到终态了钱和状态对不上客服天天来要人。后来我把状态迁移收敛成一张合法跳转表OrderStatusMachine。凡是没登记的迁移直接抛异常拒绝。这篇把设计思路和踩过的坑讲清楚。六个状态一张迁移表状态常量在BizConstants里定义WAIT_ENSURE待确认→ WAIT_START待开工→ WORKING工作中→ WAIT_PAY待结算→ WAIT_COMMENT待评价→ FINISH已完成外加 CANCEL已取消作为分支出口。状态机核心就一个静态表从哪个状态能到哪些状态写死publicfinalclassOrderStatusMachine{privatestaticfinalMapALLOWEDnewHashMap();static{// 待确认 → 待开工 / 取消allow(BizConstants.ORDER_STATUS_WAIT_ENSURE,BizConstants.ORDER_STATUS_WAIT_START,BizConstants.ORDER_STATUS_CANCEL);// 待开工 → 工作中 / 取消allow(BizConstants.ORDER_STATUS_WAIT_START,BizConstants.ORDER_STATUS_WORKING,BizConstants.ORDER_STATUS_CANCEL);// 工作中 → 待结算allow(BizConstants.ORDER_STATUS_WORKING,BizConstants.ORDER_STATUS_WAIT_PAY);// 待结算 → 待评价支付回调allow(BizConstants.ORDER_STATUS_WAIT_PAY,BizConstants.ORDER_STATUS_WAIT_COMMENT);// 待评价 → 已完成仅评价双方完成后由评价服务迁移allow(BizConstants.ORDER_STATUS_WAIT_COMMENT,BizConstants.ORDER_STATUS_FINISH);}publicstaticvoidassertTransition(StringfromStatus,StringtoStatus){if(fromStatusnull||toStatusnull){thrownewJeecgBootException(订单状态参数无效);}if(fromStatus.equals(toStatus)){thrownewJeecgBootException(订单状态未变化);}SetnextALLOWED.get(fromStatus);if(nextnull||!next.contains(toStatus)){thrownewJeecgBootException(订单状态不允许从[statusLabel(fromStatus)]变更为[statusLabel(toStatus)]);}}publicstaticbooleanisTerminal(Stringstatus){returnBizConstants.ORDER_STATUS_FINISH.equals(status)||BizConstants.ORDER_STATUS_CANCEL.equals(status);}}注意待评价 → 已完成这一条注释里写了仅评价服务迁移意思是这段迁移不在通用的改状态接口里开放谁都不许碰。通用改状态接口该挡的全挡住对外有一个updateOrderStatus(id, orderStatus, imgs)它先做三道拦截// 1. 终态不可再变if(OrderStatusMachine.isTerminal(order.getOrderStatus())){throwBizException.of(BizErrorCodes.ORDER_STATUS_INVALID,订单已结束无法变更状态);}// 2. 高级状态必须走专用接口打卡、结算、评价if(BizConstants.ORDER_STATUS_WORKING.equals(orderStatus)||BizConstants.ORDER_STATUS_WAIT_PAY.equals(orderStatus)||BizConstants.ORDER_STATUS_WAIT_COMMENT.equals(orderStatus)||BizConstants.ORDER_STATUS_FINISH.equals(orderStatus)){throwBizException.of(BizErrorCodes.ORDER_STATUS_INVALID,该状态请使用打卡/结算/评价专用接口);}// 3. 状态机校验合法迁移OrderStatusMachine.assertTransition(order.getOrderStatus(),orderStatus);第二道拦截是精髓。打卡、结算、评价这些高价值状态变更必须走各自专用接口里面有完整的业务校验打卡要传图片、结算要核对金额防止有人拿通用接口绕过业务逻辑直接改状态。支付回调里迁移状态还要记日志工资结算后微信支付回调触发WAIT_PAY → WAIT_COMMENT迁移后立刻写一条订单日志把状态流转轨迹留下来publicbooleanpaySalarySuccess(StringorderSn,BigDecimalpaidAmount){JobOrderorderqueryByOrderSn(orderSn);if(ordernull||!BizConstants.ORDER_STATUS_WAIT_PAY.equals(order.getOrderStatus())){throwBizException.of(BizErrorCodes.ORDER_STATUS_INVALID,订单非待结算状态支付回调被忽略);}OrderStatusMachine.assertTransition(order.getOrderStatus(),BizConstants.ORDER_STATUS_WAIT_COMMENT);// 条件更新防止重复回调重复迁移booleanupdatedupdateLambda().eq(id,order.getId()).eq(order_status,BizConstants.ORDER_STATUS_WAIT_PAY)// 乐观锁status 也参与条件.set(order_status,BizConstants.ORDER_STATUS_WAIT_COMMENT).set(pay_money,paidAmount).update();if(updated){orderLogService.addOrderLog(BizConstants.ORDER_STATUS_WAIT_COMMENT,order.getId(),null,null);}returnupdated;}order_status同时出现在 WHERE 条件里这就是最朴素的乐观锁——两个支付回调并发进来只有一个能 update 成功另一个 updatedfalse 直接丢弃天然防重复迁移。踩坑记录重复回调把订单状态改穿了现象线上出现一笔订单支付回调触发后订单直接到了已完成中间的待评价状态没出现过评价表里也没有任何记录。排查过程查job_order_log只有两条记录待结算→待评价、然后直接就出现一条已完成。按代码逻辑待评价→已完成只能由评价服务迁移评价都没做怎么会完成继续追日志发现同一个 orderSn 的支付回调进来了两次——第一次成功把状态改成待评价第二次回调进来时旧代码里没有状态校验直接又执行了评价服务的一个内部方法把状态顶到了已完成。定位思路问题出在迁移入口太多。评价服务内部为了省事自己写了一段如果状态是待支付就顺手改成已完成的兼容逻辑绕过了状态机也绕过了日志。状态迁移没有统一收口到状态机 日志谁都能偷偷改。最终解决两条硬规矩。第一支付回调迁移必须带order_status乐观锁条件重复回调只能有一次生效。第二全项目 grep 掉所有绕过assertTransition的裸 setOrderStatus 调用评价服务改成走专用接口内部兼容代码删干净。从此订单日志完整状态再没穿过。可直接复用的清单状态迁移表 assertTransition统一收口非法迁移直接抛异常别让 service 各自判断。高价值状态工作中/待结算/待评价/已完成禁用通用改状态接口强制走打卡/结算/评价专用接口。回调类迁移用order_status参与 WHERE 做乐观锁重复回调天然幂等。每次合法迁移写订单日志状态轨迹可审计排查状态怎么变的不用猜。终态FINISH/CANCEL一律不可再迁移接口入口先挡。项目源码https://gitee.com/gzqkl/xllg
RELATED

相关推荐

安卓新闻App源码实战:从环境配置到功能扩展的完整指南

安卓新闻App源码实战:从环境配置到功能扩展的完整指南

简介:这是一套基于 Android Studio 开发的安卓新闻 App 项目源码与配套报告,面向计算机相关专业正在准备期末大作业的学生,以及需要项目实战练习的初学者。项目经导师指导并通过评审,获得 98 分,难度适中,源…

📅 2026/10/10 4:39:24
OpenClaw安装全记录:从环境准备到编译排错,一步步带你跑通

OpenClaw安装全记录:从环境准备到编译排错,一步步带你跑通

说个事儿,折腾了两天两夜,OpenClaw 终于在我机器上跑起来了。看着终端里跳出那行版本号的时候,我长舒了一口气——这东西的安装坑是真的多,网上资料又七零八落,一个人闷头试错实在太费劲。所以这篇不是教程复读&#x…

📅 2026/10/10 4:39:24
字母异位词分组:哈希表与字符串排序的经典应用

字母异位词分组:哈希表与字符串排序的经典应用

字母异位词分组,力扣 Hot 100 列表里的常客,原题编号 49。我第一次刷到它的时候正在准备技术面试,当时心想:这题不就是把字母一样的单词放一起吗,能有多难?结果真上手之后才发现,最直观的两两比…

📅 2026/10/10 4:39:24
MORE NEWS

更多资讯

📰

CSP-J/S初赛1000页资料集高效使用指南:从知识模块到错题归因

简介:这份资料集面向备战NOIP CSP-J(入门级)与CSP-S(提高级)初赛第一轮的青少年选手及信奥教练,系统梳理了初赛所需的核心知识体系。内容围绕计算机结构与组成、进制转换、原反补码、操作系统与网络基础展开…

📰

AI 代理技能模块实战:用自然语言生成可交互架构图

昨天在 GitHub 上刷到一个很有意思的仓库,名字叫 archify。项目定位很直白:给 AI 代理用的技能模块(skill module),让你用自然语言描述系统,AI 自动生成一张可以点击、缩放、带信息面板的可交互架构图。这个…

📰

俄罗斯条形码代办水有多深?从业15年老手揭秘8个隐形大坑

做俄罗斯市场的朋友,十个有九个问过同一个问题:做俄罗斯市场条形码申请找谁才不会被坑?我在条码代理行业摸爬滚打15年,服务过创维、科大讯飞、名创优品等上百家出口企业,今天说点得罪人的大实话。俄罗斯条形码申请机构…

📰

终端AI助手实战:让命令自动执行的安全设计与落地指南

我一直觉得,终端里的 AI 助手如果不碰命令,那就跟个只会念字典的翻译官一样,看着啥都懂,真上了战场却使唤不动。市面上的 AI 聊天工具已经够多了,但大多数都停在"帮你想清楚"的层面,而不是"…

📰

PL/SQL Developer 11 高效使用指南:窗口选择、模板变量与 Preferences 配置

简介:这份《PL/SQL Developer 11 中文手册》面向 Oracle 数据库开发人员、DBA 及 PL/SQL 初学者,用于解决工具上手难、功能查找不便的问题,帮助读者系统掌握这款 Windows 平台集成开发环境的使用方法。资源为单个 PDF 文档,压缩包…

📰

Codex反复重连5/5?从心跳机制到日志定位的完整排查指南

如果你也在用 Codex 跑一些耗时比较长的工程任务,大概率遇到过这样一个画面:任务进行到一半,终端底部突然出现一行Reconnecting...,计数器从 1 慢慢爬到 5,你以为它要恢复了,结果数字停在 5/5 没多久&#…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬