这个问题非常关键,而且经常被用错。
我按 一句话结论 → 对比表 → 使用场景 → 团队规范 给你讲清楚。
一句话结论(先记住)
@Valid是 JSR 标准校验,@Validated是 Spring 增强版
最重要的区别只有一句话:
🚨 只有
@Validated支持“分组校验”
一、核心区别对照表 ⭐
| 对比点 | @Valid |
@Validated |
|---|---|---|
| 来源 | JSR-303 / JSR-380 标准 | Spring 框架 |
| 所属包 | javax.validation.Validjakarta.validation.Valid |
org.springframework.validation.annotation.Validated |
| 是否支持分组 | ❌ 不支持 | ✅ 支持 |
| 是否支持嵌套校验 | ✅ 支持 | ✅ 支持 |
| 可用位置 | 方法参数 / 成员变量 | 类 / 方法 / 参数 |
| 是否推荐 | 基础可用 | 生产推荐 |
二、什么是「分组校验」(关键)
1️⃣ 场景说明(真实项目必用)
同一个 DTO:
- 新增:id 必须为空
- 修改:id 必须存在
2️⃣ 定义校验分组
public interface CreateGroup {}
public interface UpdateGroup {}
3️⃣ DTO 中使用分组
public class UserDTO {
@NotNull(groups = UpdateGroup.class, message = "修改时ID不能为空")
private Long id;
@NotBlank(groups = CreateGroup.class, message = "创建时用户名不能为空")
private String username;
}
4️⃣ Controller 中使用 @Validated
@PostMapping("/user")
public void create(
@RequestBody
@Validated(CreateGroup.class) UserDTO dto) {
}
@PutMapping("/user")
public void update(
@RequestBody
@Validated(UpdateGroup.class) UserDTO dto) {
}
❗如果这里换成 @Valid,分组会直接失效
三、使用位置上的差异(很多人不知道)
1️⃣ @Valid 的使用位置
public void save(@Valid UserDTO dto)
或嵌套:
@Valid
private AddressDTO address;
📌 不能放在类上
2️⃣ @Validated 的使用位置
@Validated
@RestController
public class UserController {
}
@Validated
public void save(UserDTO dto) {
}
📌 支持:
- 类
- 方法
- 参数
四、常见误区(踩一次就记住)
❌ 误区 1:@Valid 和 @Validated 可以随便混用
❌ 错
📌 结论:
- 无分组:都可以
- 有分组:必须
@Validated
❌ 误区 2:DTO 上写了校验就一定生效
❌ 错
必须满足 两点:
- Controller 参数上有
@Valid / @Validated - Spring 容器中存在校验器(Spring Boot 默认有)
❌ 误区 3:校验写在 Entity 上也一样
❌ 强烈不推荐
📌 原因:
- Entity 面向数据库
- DTO 面向接口
- 校验规则不一致
五、真实项目推荐用法(团队规范)
✅ 推荐标准(直接用)
// Controller
@PostMapping("/user")
public void create(
@RequestBody
@Validated(CreateGroup.class) UserCreateDTO dto) {
}
@PutMapping("/user/{id}")
public void update(
@PathVariable Long id,
@RequestBody
@Validated(UpdateGroup.class) UserUpdateDTO dto) {
}
❌ 不推荐
public void save(@Valid UserDTO dto)
📌 原因:
- 后期一定会遇到新增 / 修改规则不同
- 重构成本高
六、异常处理(你团队一定会用到)
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<?> handle(MethodArgumentNotValidException e) {
String msg = e.getBindingResult()
.getFieldError()
.getDefaultMessage();
return Result.fail(msg);
}
}
七、最终总结(面试 + 实战版)
✔
@Valid:
- 简单校验
- 无分组
- 标准注解
✔
@Validated:
- 分组校验
- Spring 推荐
- 生产首选
正文完
