AI帮我写了个Spring Boot校验,线上漏掉了这组边界条件

AI帮我写了个Spring Boot校验,线上漏掉了这组边界条件

目录

  • 那个周五下午的发布
  • AI给的标准答案
  • 边界条件从哪漏的
  • 手动补全的校验逻辑
  • 现在我怎么让AI写校验
  • 几条经验

那个周五下午的发布

周五下午五点,我点了发布按钮。本来只是个常规迭代,给订单创建接口加一个参数校验。结果不到半小时,客服群里开始刷屏:"客户反馈下单时报参数错误,但前台明明填对了。"

我看了日志,ValidationException堆里有一行特别刺眼:javax.validation.ConstraintViolationException: 收货地址不能为空。问题是,那个订单是电子卡券,本来就不需要收货地址。

这段校验代码是AI上午帮我写的。需求描述很简单:"给订单创建接口加上参数校验,收货人、手机号、地址必填,金额不能为0。" AI给了我一整段@Valid加自定义注解的代码,看起来专业又规范。我照着集成进去,本地跑了几条用例都没问题,就直接合了。

结果上线就翻车。

AI给的标准答案

AI产出的代码结构大概是下面这样,我贴的是实际核心部分:

```java @Data public class OrderCreateRequest { @NotBlank(message = "收货人不能为空") private String consignee;

复制代码
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String mobile;

@NotBlank(message = "收货地址不能为空")
private String address;

@NotNull(message = "订单金额不能为空")
@Min(value = 1, message = "订单金额必须大于0")
private BigDecimal amount;

} ```

Controller里加一行@Valid,全局异常捕获里处理一下,齐活。AI甚至还提醒我"金额用BigDecimal避免精度问题"。

这个答案本身没有错。放在电商实物订单场景里,基本够用了。但它不知道我们业务里还有电子卡券、自提订单、企业团购这三种类型,它们的校验规则完全不一样。

边界条件从哪漏的

问题出在业务类型这个字段上。我们的订单有个orderType字段:

  • 实物订单:需要收货人、手机号、地址
  • 电子卡券:只需要手机号和邮箱,不需要地址
  • 自提订单:需要手机号和自提点ID,不需要地址
  • 企业团购:需要企业税号和联系人,不要个人地址

AI生成的代码把address做成了通用必填项,没有根据orderType做条件校验。电子卡券用户传了空地址,Spring Validation直接抛异常,订单创建失败。

更隐蔽的是手机号规则。1[3-9]\d{9}这个正则看起来标准,但我们的企业团购订单允许留座机号,而自提订单的手机号可能是门店固话转接。AI按照"通用手机号"来校验,把两类真实订单都拦下来了。

还有一个没暴露出来的问题:金额校验。@Min(1)表示金额必须大于等于1。但电子卡券经常有0.01元的测试商品,企业团购可能有0元预付订单。AI不知道这些,一律按"大于0"处理。

手动补全的校验逻辑

我当天回滚后,自己补了一个分组校验的方案。核心思路是按orderType分组,不同业务类型用不同的校验组:

```java public interface OrderCreateRequest { interface Physical {} interface Virtual {} interface Pickup {} interface Enterprise {} }

@Data public class OrderCreateRequest { @NotNull(message = "订单类型不能为空", groups = {Physical.class, Virtual.class, Pickup.class, Enterprise.class}) private Integer orderType;

复制代码
@NotBlank(message = "收货人不能为空", groups = Physical.class)
private String consignee;

@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确", groups = {Physical.class, Virtual.class, Pickup.class})
private String mobile;

@NotBlank(message = "收货地址不能为空", groups = Physical.class)
private String address;

@NotBlank(message = "邮箱不能为空", groups = Virtual.class)
@Email(message = "邮箱格式不正确", groups = Virtual.class)
private String email;

@NotNull(message = "自提点ID不能为空", groups = Pickup.class)
private Long pickupPointId;

@NotBlank(message = "企业税号不能为空", groups = Enterprise.class)
private String enterpriseTaxNo;

@NotNull(message = "订单金额不能为空")
@DecimalMin(value = "0.00", message = "订单金额不能为负数")
private BigDecimal amount;

} ```

Controller里根据orderType选择校验组:

java @PostMapping("/orders") public ResponseEntity<?> createOrder( @RequestBody @Validated(OrderCreateRequest.Physical.class) OrderCreateRequest request) { // 实际业务中根据 orderType 动态选择校验组 }

当然,真实代码里我把校验组选择封装成了一个工具方法,根据orderType的值决定调用哪个组。否则Controller里会写得很脏。

现在我怎么让AI写校验

这次之后我总结了一个规律:AI写校验代码时,会默认你只有一个最标准的场景。你如果不告诉它业务分支,它就不会考虑分支。

现在我再让AI写校验,会把需求拆成三段:

第一段说业务类型和字段:"订单有四种类型:实物、电子卡券、自提、企业团购。字段包括收货人、手机号、地址、邮箱、自提点ID、企业税号、金额。"

第二段说每种类型必填什么:"实物需要收货人、手机号、地址;电子卡券需要手机号和邮箱;自提需要手机号和自提点ID;企业团购需要企业税号和联系人。"

第三段说特殊规则:"金额允许为0但不能为负数;电子卡券可能有0.01元商品;手机号在实物/电子卡券/自提场景下必须是11位手机号,企业团购场景下可以是座机或手机号。"

把这三段一起给AI,它基本能生成接近可用的分组校验代码。我再人工检查一遍有没有漏掉的字段和组。

几条经验

AI生成的校验代码最大的问题不是语法错误,而是"业务假设不完整"。它默认你的模型是简单的、通用的、单一场景的。真实业务往往是多分支、有特例、需要条件判断的。

给AI写校验需求时,把"哪些字段在哪些条件下必填"说清楚,比把字段校验规则本身说清更重要。AI不缺正则和注解的知识,它缺的是你对业务规则的理解。

另外,校验规则不要一次性堆在实体类上。分组校验、自定义注解、或者按业务类型拆分成多个Request对象,都是更稳妥的做法。AI能帮你写,但分组策略得你自己设计。

那天回滚后,我在周会上说了一句话:"AI能让校验代码写得更快,但别让AI替你决定什么该校验、什么不该校验。"这句话后来成了我们团队用AI写校验时的默认提醒。

相关推荐
JRedisX8 小时前
Java从零手写企业级内存数据库
java
萧瑟余晖8 小时前
JDK 20 新特性详解
java·开发语言
唐老板8 小时前
给 AI 套上缰绳:Harness Engineering 是什么
ai编程
hdsoft_huge8 小时前
SpringBoot系列17:日志体系Logback配置,日志分割、脱敏、异常堆栈收集规范(生产级落地)
java·spring boot·logback
吃饱了得干活8 小时前
扫码登录如何实现?从原理到实战
java·spring boot·redis
我要割麦子8 小时前
从零到一手撸 Agent 系列 — 第 4 篇:工具的契约 — Tool 接口与注册表
agent·ai编程
未曾※放弃꿈8 小时前
Cursor 添加与切换背景图片教程(附带背景图)
ai编程
JRedisX8 小时前
JRedisX 项目骨架搭建指南 从零开始 — 手把手教你搭
java
zx1154508 小时前
Java 反射 (SpringBoot篇)
java·架构