@Validated注解和@Valid注解区别

@Validated注解和@Valid注解区别

@Valid@Validated 都是用来校验接收参数的,其中 @Validated是Spring的注解,对 @Valid 进行了封装,所有功能强大。 @Valid 是javax包下的注解属于JDK提供的。

  • @Valid 没有分组的功能
  • @Validated 提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
  • @Valid 可以用在方法、构造函数、方法参数和成员属性(字段)上,支持嵌套检测
  • @Validated 可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上,不支持嵌套检测

SpringBoot项目中使用需要先引入以下Maven

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

@Validated注解和@Valid注解使用场景

  • 给请求参数添加校验
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @Data
    @EqualsAndHashCode(callSuper = false)
    @ApiModel(value="TabUserInfo对象", description="用户表")
    public class TabUserInfo implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "姓名")
    // validated参数校验
    @NotNull(message = "姓名不能为空")
    private String name;

    @ApiModelProperty(value = "手机")
    private String mobile;

    @ApiModelProperty(value = "年龄")
    private Integer age;
    }
  • Controller层
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @PostMapping("saveOrUpdate")
    public R saveOrUpdate(@RequestBody @Valid TabUserInfo userInfo) {

    boolean saved = userInfoService.saveOrUpdate(userInfo);
    if (saved) {
    return R.ok().message("操作成功");
    } else {
    return R.error().message("操作失败");
    }
    }
  • Postman测试
    1
    2
    3
    4
    5
    {
    "id":"5",
    "mobile": "13201235669",
    "name": null
    }
  • IDEA控制台的打印
    1
    DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.fu99999.note.result.R com.fu99999.note.controller.TabUserInfoController.saveOrUpdate(com.fu99999.note.pojo.entity.TabUserInfo): [Field error in object 'tabUserInfo' on field 'name': rejected value [null]; codes [NotNull.tabUserInfo.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [tabUserInfo.name,name]; arguments []; default message [name]]; default message [姓名不能为空]] ]

    @Valid 的校验不通过会抛出异常,在使用 @Valid 注解的请求参数后面可以跟一个 BindingResult 对象,这个对象的作用是将所有的异常信息存起来。在源码中可以看出 BindingResult 继承 Error 对象,异常的信息可以从 Errors 中拿到。下面我们自己写一个工具类来返回这些信息。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class HandleValidateErr {

    public static R handleValidateErr(BindingResult bindingResult){
    String message = "";
    List<ObjectError> allErrors = bindingResult.getAllErrors();
    for (ObjectError allError : allErrors) {
    message = allError.getDefaultMessage();
    if(StringUtils.isNotBlank(message)){
    break;
    }
    }
    return R.error().message(message);
    }
    }
  • 给Controller层添加BindingResult对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @PostMapping("saveOrUpdate")
    public R saveOrUpdate(@RequestBody @Valid TabUserInfo userInfo, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
    return HandleValidateErr.handleValidateErr(bindingResult);
    }
    boolean saved = userInfoService.saveOrUpdate(userInfo);
    if (saved) {
    return R.ok().message("操作成功");
    } else {
    return R.error().message("操作失败");
    }
    }
  • 返回结果

    @Validated的使用方法和@Valid相同,因为本来就是对@Valid注解的封装

@Validated的分组校验

  • 分别校验Gropu1和Gropu2接口类
    1
    2
    public interface Gropu1 {
    }
    1
    2
    public interface Gropu2 {
    }
  • 在实体类中分别加入Gropu1和Gropu2的校验规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    @Data
    @EqualsAndHashCode(callSuper = false)
    @ApiModel(value="TabUserInfo对象", description="用户表")
    public class TabUserInfo implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "姓名")
    @NotNull(message = "姓名不能为空")
    private String name;

    // Group2的参数校验
    @Pattern(groups = Group2.class, regexp= "123456",message ="手机号必须是123456" )
    @ApiModelProperty(value = "手机")
    private String mobile;

    // Group1的参数校验
    @Min(groups = Group1.class,value=18,message = "age1必须大于等于18")
    @ApiModelProperty(value = "年龄")
    private Integer age;
    }
  • 在Controller添加两个校验接口
    1
    2
    3
    4
    5
    6
    7
    8
    @GetMapping("getGroup1Validated")
    public R getGroup1Validated(@Validated(Group1.class) @RequestBody TabUserInfo userInfo) {
    return R.ok().data("userInfo",userInfo);
    }
    @GetMapping("getGroup2Validated")
    public R getGroup2Validated(@Validated(Group2.class) @RequestBody TabUserInfo userInfo) {
    return R.ok().data("userInfo",userInfo);
    }
  • 校验结果

    @Validated(Gropu1.class)如果指定了分组,那么只会对指定分组下的参数进行校验,别的不会管