Spring Boot参数校验学得快的关键是先跑通接口再拆解原理:需引入spring-boot-starter-validation依赖、Controller加@Validated或参数前加@Valid;掌握@NotBlank、@NotNull、@Size、@Email、@Pattern五个常用注解;支持嵌套校验(@Valid)和分组校验(groups);最后用@RestControllerAdvice统一处理错误响应。

直接上手,别绕弯——Spring Boot 参数校验学得快的关键是:先跑通一个接口,再拆解每一步为什么这么写,最后扩展场景。不需要背注解,而是理解“谁在什么时候校什么、错的时候怎么拦、提示怎么统一”。
第一步:搭好环境,让校验真正生效
很多初学者卡在“加了注解没反应”,其实是漏了两件事:
- 必须引入 spring-boot-starter-validation 依赖(Spring Boot 2.3+ 版本不再默认包含,要手动加)
- Controller 类上要加 @Validated(单个参数校验)或方法参数前加 @Valid(对象校验),两者不能混用或遗漏
比如路径变量校验,这样写才生效:
```java@RestController
@RequestMapping("/user")
@Validated // ← 这行不能少
public class UserController {
@GetMapping("/{id}")
public String get(@PathVariable @Min(1) Long id) {
return "OK";
}
}
第二步:掌握 5 个最常用注解,覆盖 80% 场景
不用记全,先熟用这几个,按字段类型对号入座:
- @NotBlank → 字符串(非 null + 去空格后非空),适合用户名、标题
- @NotNull → 包装类(Integer、Long 等),避免空指针;不适用于 String(用 @NotBlank)
- @Size(min=1, max=20) → 字符串长度或集合大小,比 @Length 更通用
- @Email → 邮箱格式(正则已内置,不用自己写)
- @Pattern(regexp = "^1[3-9]\d{9}$") → 手机号等自定义格式,注意 regexp 是字符串字面量
实体类里组合使用很自然:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
public class UserDTO {
@NotBlank(message = "用户名必填")
@Size(max = 16)
private String username;
@Email(message = "邮箱格式错误")
private String email;
@Pattern(regexp = "^1[3-9]\d{9}$", message = "手机号不合法")
private String phone;
}
第三步:对象嵌套和分组校验,应对真实业务
实际项目里 DTO 往往有子对象或不同操作阶段(新增/修改),这时需要:
- 嵌套校验:在字段上加 @Valid,让校验穿透到内部对象。例如订单含多个商品项,商品 DTO 也需加 @NotBlank 等注解
- 分组校验:定义 Create 和 Update 两个空接口,字段上用 groups 指定适用场景,Controller 方法里用 @Validated(Create.class) 触发对应规则
比如 ID 在创建时应为空、更新时必须存在,靠一个字段两种约束就能搞定,不用写 if 判断。
第四步:错误响应要友好,别让前端猜
校验失败默认返回 400 + 一堆英文堆栈,必须拦截并转成统一 JSON 格式:
- 写一个 @RestControllerAdvice 类,用 @ExceptionHandler(MethodArgumentNotValidException.class) 捕获对象校验异常
- 用 BindingResult 或异常里的 getBindingResult().getFieldErrors() 提取每个字段的 message
- 组装成 { "code": 400, "msg": "用户名不能为空", "details": [...] } 这样的结构返回
这样前端能直接展示具体哪个输入框错了,而不是弹个“请求失败”。










