@Valid vs @Validated

Last Modified: 2023/02/26

概述

@Valid 和 @Validated 的区别有以下几点:

  • @Valid 是 jsr 380 规范中定义的,而 @Validated 则是 spring 框架特有的;
  • @Validated 支持分组校验;
  • @Valid 可用于嵌套校验。

以上是不同点,但是这两个注解都是用来完成 Bean 校验的。

分组校验

在项目中,我们有时候会遇到引导页面,这种页面分为多步,每一步收集一组相关信息。例如用户注册页面,第一步收集用户基本信息,如:用户名、密码;第二步收集扩展信息,如:性别、年龄和爱好等。这些都是用户信息,所以服务端我们用 UserInfo 统一收集这些信息。

为了支持分组,需要为每个分组定义一个 interface,用于标识分组:

// 该分组用于标识用户基本信息
public interface UserBasicInfo {
}
// 该分组用于标识用户扩展信息
public interface UserExtendInfo {
}

紧接着定一个收集用户信息的 POJO,该 POJO 将会使用到上面的分组:

public class UserInfo {

  @NotBlank(message = "用户名不能为空", groups = UserBasicInfo.class)
  private String name;
  @NotBlank(message = "密码不能为空", groups = UserBasicInfo.class)
  private String password;

  // 以下是扩展信息部分,注意 groups 值为 UserExtendInfo.class
  @Size(min = 18, max = 120, groups = UserExtendInfo.class)
  private int age;
  @NotBlank(message = "爱好不能为空", groups = UserExtendInfo.class)
  private String hobby;
  @NotBlank(message = "性别不能为空", groups = UserExtendInfo.class)
  private String gender;
  // 篇幅关系,省略 getter/setter
}

再下来,就是 controller 方法中使用 @Validated 注解配合之前为标识分组而定义的 interface 完成校验:

@RestController
public class UserController {
  @PostMapping("/basicInfo")
  public String validateBasicInfo(@Validated(UserBasicInfo.class) UserInfo info) {
    // 注意 @Validated 注解使用了 UserBasicInfo.class
    // ...
  }
  
  @PostMapping("/extendInfo")
  public String validateExtendInfo(@Validated(UserExtendInfo.class) UserInfo info) {
    // ...
  }
}

之所以使用分组校验是因为每一步只校验某个分组的信息,其他信息为空,如果不使用分组,肯定校验失败。

注:从 spring boot 2.3 开始需要引入 spring-boot-starter-validation

<dependency> 
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

嵌套校验

嵌套校验就是所谓 nested validation。这里假设一个订单信息 OrderInfo,OrderInfo 包含了用户信息 Customer,校验的时候我们需要校验包含在订单信息中的用户信息,做法很简单,只需要给 customer 字段上添加一个 @Valid 注解即可。

public class Customer {
  @NotBlank(message = "customer id required")
  private String id;
}

public class OrderInfo {
  // 为了支持嵌套校验,这里需要在嵌套对象上使用 @Valid 注解 
  @Valid
  @NotNull(message = "customer info required")
  private Customer customer;
}

在 controller 方法中我们可以使用 @Valid 也可以使用 @Validated。

@PostMapping("/order")
public void createOrder(@Valid OrderInfo info) {
  //...
}

jsr 308 实现

jsr 308 只是一个 bean 校验的规范,spring 中默认使用的实现是 hibernate-validator。

有问题吗?点此反馈!

温馨提示:反馈需要登录