第四天的重点是把 SalesOrderService 补完整,加上订单在生命周期里几个关键的"变化"——状态变更、加急标记切换、交期变更,并且给每一次变化都留痕。写完之后用 curl 做了一轮接口测试,记录一下这一天的思路。
今天要解决的问题
前几天把订单创建(createOrder)和基础查询(listAll、listByStatus、getById)跑通了,但一个订单管理系统光能"建"是不够的——它还得能反映真实业务里订单状态的流转:客户临时要求加急了怎么办?交期要往后拖怎么办?评审通过了怎么把状态推进到下一步?这些变化不仅要落到订单本身,还得有据可查,所以变更记录(OrderChangeRecord)也要跟着一起写。
设计思路:一个通用的记录方法打底
与其在每个"变更"方法里都重复写一遍记录逻辑,不如先抽一个私有的 recordChange 方法出来,接收变更类型、字段名、旧值、新值、操作人和备注,统一负责写入变更记录表。这里有个小细节:如果新旧值完全相同,就直接返回、不写记录——避免产生一堆"没有实际变化"的噪音数据。
有了这个通用方法打底,具体的三个业务方法就都很轻:
状态变更(updateStatus):按订单 ID 找到订单,记下旧状态,更新为新状态,保存后调用 recordChange 留痕。
加急标记切换(toggleUrgent):逻辑结构和状态变更几乎一样,只是字段换成了 urgent 这个布尔值。
交期变更(updateExpectedDeliveryDate):这个方法比前两个多了一层业务判断——如果订单当前处于"生产中""待备货""待发货"这几个状态,说明交期一变可能会打乱后续排产计划,这时候不能默默改完就完事,得把订单状态顺势拉回"变更待评审"(CHANGE_PENDING),逼着流程重新走一遍评审。所以这个方法里实际上会产生两条变更记录:一条是交期本身的变化,一条是因交期变化联动触发的状态变化。
一点设计取舍
recordChange 里对 oldValue/newValue 的判空处理用了三元表达式套 equals,写法不算优雅,但胜在直接:oldValue == null ? newValue == null : oldValue.equals(newValue)。对于这种一次性的内部工具方法,清晰比精巧更重要。
另外交期变更那个方法里,"是否需要触发重新评审"的判断被提前算出来存成一个布尔变量(shouldTriggerReview),而不是在后面重复判断两次——一次用来决定要不要改状态,一次用来决定要不要写第二条变更记录。这样两处逻辑共享同一个判断结果,不容易出现改了一处忘了改另一处的情况。
测试环节
写完代码,用 curl 走了一遍完整流程,思路是:
先起服务——这一步之前踩过 MySQL 启动失败的坑,得先确认数据库能连上,不然 Spring Boot 应用直接起不来。
建一个测试订单,拿到返回的订单 ID。
依次调用状态变更、加急切换、交期变更三个接口,都指向刚才那个 ID。
验证变更记录有没有真的写进 order_change_record 表——目前还没有配套的查询接口,只能直接连数据库客户端看表数据。
最后一步其实是个待办:下一步打算加一个 GET /api/orders/{id}/changes 接口,把某个订单的完整变更历史直接查出来,省得每次测试都要开数据库客户端手动核对。
小结
Day 4 把订单从"能创建"往"能管理"推进了一步:状态流转、加急标记、交期变更三件事都有了各自的接口,也都留下了可追溯的变更记录。核心收获是"通用记录方法 + 前置判断变量"这套小模式——业务方法本身写起来很薄,但该有的追溯能力一点没少。接下来的重点是把变更记录的查询接口补上,让这些留痕真正"看得见"。

posted on 2026-08-29 16:49  chenyun_922  阅读(5)  评论(0)    收藏  举报