Spring Boot Validation 使用手册
目标:5 分钟上手,覆盖 99% 场景,避坑指南 + 速查表
一、@Valid vs @Validated ------ 关键区别
| 特性 | @Valid (JSR-303) | @Validated (Spring 扩展) |
|---|---|---|
| 来源 | Java 标准(javax.validation) | Spring 框架提供 |
| 分组校验 | ✅ 支持 | ✅ 支持(更常用) |
| 方法级校验 | ❌ 不支持 | ✅ 支持(但需在类或方法上显式标注) |
| 参数校验 | ❌ 仅支持 @RequestBody |
✅ 支持 @RequestParam / @PathVariable |
✅推荐用法:
-
Controller 层:
-
简单校验 →
@Valid -
需分组 或 校验 查询/路径参数 →
@Validated
-
-
Service 层 → 仅在需要校验的类/方法上加
@Validated
二、快速启用
1. 引入依赖(Spring Boot 2.3+ 需手动加)
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2. Service 层校验
java
// 方式1:在 Service 类上加 @Validated(推荐)
@Service
@Validated // ← 仅此 Service 启用方法校验
public class UserService {
public void save(@Valid UserCreateDTO dto) { // 自动校验
// ...
}
}
// 方式2:在具体方法上加(不常用)
@Service
public class OrderService {
@Validated
public void createOrder(@Valid OrderDTO dto) {
// ...
}
}
三、所有常用注解速查表
基础校验
| 注解 | 说明 | 示例 |
|---|---|---|
@NotNull |
不能为 null |
@NotNull Long id |
@NotEmpty |
非 null 且非空(Collection/String) | @NotEmpty List<String> tags |
@NotBlank |
字符串专用:trim 后非空 | @NotBlank String username |
💡 字符串必填优先用
@NotBlank(防" "空格)
数值 & 日期
| 注解 | 说明 | 示例 |
|---|---|---|
@Min(0) / @Max(100) |
整数范围 | @Min(18) Integer age |
@DecimalMin("0.01") |
小数范围 | BigDecimal price |
@Positive |
> 0 | @Positive Integer count |
@Past / @Future |
日期校验 | @Past LocalDate birthday |
格式校验
| 注解 | 说明 | 示例 |
|---|---|---|
@Size(min=6, max=20) |
长度 | @Size(min=6) String password |
@Email |
邮箱 | @Email String email |
@Pattern(regexp = "...") |
正则 | @Pattern(regexp = "^1[3-9]\d{9}$") String phone |
@URL |
URL 格式 | @URL String homepage |
四、高级用法
1. 嵌套对象校验
java
public class OrderDTO {
@Valid // ← 关键!否则 Address 不校验
private Address shippingAddress;
}
2. List 元素校验(⚠️ 注意兼容性)
java
// JDK ≥ 8u20 + Spring Boot ≥ 2.3 才支持
private List<@Valid OrderItem> items;
// 兼容写法(推荐)
public class ItemList {
@Valid
private List<OrderItem> items;
}
3. 分组校验
java
public interface Create {}
public interface Update {}
public class UserDTO {
@Null(groups = Create.class)
@NotNull(groups = Update.class)
private Long id;
}
// Controller
public Result create(@Validated(Create.class) @RequestBody UserDTO dto) { ... }
五、避坑指南(必看!)
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 校验不生效 | 忘记加 @Valid/@Validated |
Controller 参数前加注解 |
| 嵌套对象不校验 | 字段没加 @Valid |
在嵌套字段上加 @Valid |
| Service 层无效 | Service 类未加 @Validated |
只在需要的 Service 上加 @Validated |
| List 校验失效 | JDK/Spring Boot 版本低 | 用封装类或手动校验 |
| 参数校验失败 | 用 @Valid 校验 @RequestParam |
改用 @Validated |
六、最佳实践
-
DTO 专用:只在校验 DTO,不在 Entity 上校验
-
错误消息友好:
message = "密码长度需6-20位" -
复杂逻辑放 Service:如"用户名不能重复" → Service 中查 DB
-
Service 校验按需开启:仅在需要参数校验的 Service 上加
@Validated -
快速测试:看是否返回自定义错误(不是 500)
✅ 记住:Validation 只做"格式"校验,不做"业务"校验!
七、速查 Cheat Sheet
| 场景 | 用法 | 示例 |
|---|---|---|
| 字符串非空 | @NotBlank |
@NotBlank String name |
| 数字范围 | @Min + @Max |
@Min(1) @Max(100) Integer score |
| 邮箱 | @Email |
@Email String email |
| 手机号 | @Pattern |
@Pattern(regexp = "^1[3-9]\d{9}$") |
| 分组校验 | @Validated(Group.class) |
Controller 参数 |
| Service 校验 | 在 Service 类上加 @Validated |
@Service @Validated public class XxxService |
| 查询参数校验 | 必须 @Validated |
@RequestParam @Min(1) int page |