Java 参数校验之 @Valid vs @Validated 速查笔记

Java 参数校验之 @Valid vs @Validated 速查笔记

1. 来源与定位

维度 @Valid @Validated
规范 JSR-303/JSR-380(javax.validation) Spring Framework 扩展
所在包 javax.validation.Valid org.springframework.validation.annotation.Validated
核心定位 标准校验触发器 带“分组”特性的校验触发器

2. 功能差异速览

功能 @Valid @Validated
触发标准校验
支持分组(groups)
支持嵌套校验 ❌(仅能写在类/方法/参数上,不能递归)
使用位置 字段、构造器、方法参数、返回值 类、方法、方法参数
需要配合 Spring AOP ✅(类上必须加 @Validated 才能激活方法参数校验)

3. 使用场景对照

场景 推荐注解 原因
Controller 入参是 复杂 Bean @Valid@Validated 简单、语义清晰
Controller 入参是 简单类型(String、int…) @Validated 必须写在 上,再对参数加约束注解 只有 Spring 的方法级校验支持
需要 分组校验(新增/更新不同规则) @Validated(Group.class) 分组是 Spring 扩展
需要 嵌套校验(对象里还有对象) @Valid 写在属性或集合上 支持递归

4. 代码示例

4.1 基本 Bean 校验(无分组)

// Bean
public class UserDTO {
    @NotBlank
    private String name;
    @Min(18)
    private int age;
}

// Controller
@RestController
@RequestMapping("/user")
public class UserController {

    @PostMapping("/add")
    public String add(@Valid @RequestBody UserDTO dto) { // @Validated 亦可
        return "saved";
    }
}

4.2 分组校验(新增/更新)

// 1. 定义分组标记接口
public interface Create {}
public interface Update {}

// 2. Bean 中指定分组
public class UserDTO {
    @NotNull(groups = Update.class)
    private Long id;

    @NotBlank(groups = {Create.class, Update.class})
    private String name;

    @Min(value = 18, groups = Create.class)
    private int age;
}

// 3. Controller
@RestController
@RequestMapping("/user")
public class UserController {

    @PostMapping                // 新增
    public String create(@Validated(Create.class) @RequestBody UserDTO dto) {
        return "created";
    }

    @PutMapping                 // 更新
    public String update(@Validated(Update.class) @RequestBody UserDTO dto) {
        return "updated";
    }
}

4.3 方法参数为简单类型(String)

@RestController
@RequestMapping("/hello")
@Validated   // ✅ 必须加在类上,才能激活方法参数校验
public class HelloController {

    @GetMapping
    public String hi(
            @NotBlank(message = "name 不能为空") @RequestParam String name) {
        return "Hi, " + name;
    }
}

@Valid 写在简单参数上 无效@Validated 放在方法上也 无效


4.4 嵌套校验(三层结构)

// 最内层
public class Stock {
    @Min(value = 1, message = "库存必须大于0")
    private int quantity;
}

// 第二层
public class Item {
    @NotBlank
    private String name;

    @DecimalMin("0.01")
    private BigDecimal price;

    @Valid   // 递归校验
    @NotNull
    private Stock stock;

    // 更推荐这样写
    // @NotNull
    // private @Valid Stock stock;
}

// 最外层
public class OrderDTO {
    @NotBlank
    private String orderNo;

    @Valid   // List 中每个元素都校验
    @NotEmpty
    private List<Item> items;

    // 更推荐这样写
    // @NotEmpty
    // private List<@Valid Item> items;
}

// Controller
@RestController
@RequestMapping("/orders")
public class OrderController {

    @PostMapping
    public String create(@Valid @RequestBody OrderDTO dto) { // @Validated 亦可
        return "order created";
    }
}

5. 常见误区提醒

  1. @Valid 无法指定分组;需要分组请用 @Validated(Group.class)
  2. 简单参数(String、int…)的校验必须把 @Validated 写在 上,再对参数加约束注解。
  3. @Validated 不支持嵌套校验;嵌套请用 @Valid(放在类名上和放在属性上效果一样,前者更推荐,如 private @Valid Stock stock;)。
  4. @Valid 可以放在 List<@Valid Item> 上,Spring 会逐条校验(放在泛型上和放在属性上效果一样,前者更推荐,如 private List<@Valid Item> items;)。

6. 一句话速记

  • 复杂对象@Valid(@Validated 亦可)
  • 简单参数 → 类上加 @Validated
  • 不同规则@Validated(Group.class)
  • 嵌套对象 → 属性上加 @Valid
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容