Spring 校验终极指南:@Valid vs @Validated 区别与实战

这个问题非常关键,而且经常被用错
我按 一句话结论 → 对比表 → 使用场景 → 团队规范 给你讲清楚。


一句话结论(先记住)

@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 上写了校验就一定生效

❌ 错

必须满足 两点

  1. Controller 参数上有 @Valid / @Validated
  2. 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 推荐
  • 生产首选
正文完
 0
评论(没有评论)
验证码