下单接口的 items 是 List<OrderItem>,元素里的 quantity 标了 @Min(1),实际传 quantity=0 也能创建成功,库存扣减后订单金额是 0 元。乍看像缓存或者权限的锅,追下去往往不是。

curl -i -X POST http://127.0.0.1:8080/api/orders \
  -H 'Content-Type: application/json' \
  -d @order_items_zero.json

追下去是这么回事:只在 List 字段上写了 @Valid,没有真正进入元素类型,级联校验在集合这一层就断了。嵌套对象的注解需要 @Valid 逐层传递,漏一层后面全部跳过。控制器参数上的 @Valid 只校验最外层对象,集合元素不会自动展开。

「嵌套集合校验」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。

线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。

具体做法是,在 List<OrderItem> 字段上标 @Valid 让级联进入元素;确认元素类里写的是 @Min @NotNull 这类约束而不是 @Valid;用 quantity=0 和 quantity=-1 各发一次请求;补一条嵌套校验的单测 防止后续改 DTO 时丢注解。

验收就看一点,同样请求返回 400 错误字段是 items[0].quantity 订单不再落库。

作者 9823189