别再混淆了!一文带你搞懂@Valid和@Validated的区别

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

上篇文章我们简单介绍和使用了一下Springboot的参数校验,同时也用到了 @Valid 注解和 @Validated 注解,那它们之间有什么不同呢?

区别

先总结一下它们的区别:

  1. 来源

    • @Validated :是Spring框架特有的注解,属于Spring的一部分,也是JSR 303的一个变种。它提供了一些 @Valid 所没有的额外功能,比如分组验证。
    • @Valid:Java EE提供的标准注解,它是JSR 303规范的一部分,主要用于Hibernate Validation等场景。
  2. 注解位置

    • @Validated : 用在类、方法和方法参数上,但不能用于成员属性。
    • @Valid:可以用在方法、构造函数、方法参数和成员属性上。
  3. 分组

    • @Validated :支持分组验证,可以更细致地控制验证过程。此外,由于它是Spring专有的,因此可以更好地与Spring的其他功能(如Spring的依赖注入)集成。
    • @Valid:主要支持标准的Bean验证功能,不支持分组验证。
  4. 嵌套验证

    • @Validated :不支持嵌套验证。
    • @Valid:支持嵌套验证,可以嵌套验证对象内部的属性。

这些理论性的东西没什么好说的,记住就行。我们主要看分组嵌套验证是什么,它们怎么用。

实操阶段

话不多说,通过代码来看一下分组嵌套验证

为了提示友好,修改一下全局异常处理类:

@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     *  参数校检异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseResult<?> handle(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();

        StringJoiner joiner = new StringJoiner(";");

        for (ObjectError error : bindingResult.getAllErrors()) {
            String code = error.getCode();
            String[] codes = error.getCodes();

            String property = codes[1];
            property = property.replace(code ,"").replaceFirst(".","");

            String defaultMessage = error.getDefaultMessage();
            joiner.add(property+defaultMessage);
        }
        return handleException(joiner.toString());
    }

    private ResponseResult<?> handleException(String msg) {
        ResponseResult<?> result = new ResponseResult<>();
        result.setMessage(msg);
        result.setCode(500);
        return result;
    }
}

分组校验

分组验证是为了在不同的验证场景下能够对对象的属性进行灵活地验证,从而提高验证的精细度和适用性。一般我们在对同一个对象进行保存或修改时,会使用同一个类作为入参。那么在创建时,就不需要校验id,更新时则需要校验用户id,这个时候就需要用到分组校验了。

对于定义分组有两点要特别注意

  1. 定义分组必须使用接口。
  2. 要校验字段上必须加上分组,分组只对指定分组生效,不加分组不校验。

有这样一个需求,在创建用户时校验用户名,修改用户时校验用户id。下面对我们对这个需求进行一个简单的实现。

  1. 创建分组

CreationGroup 用于创建时指定的分组:

public interface CreationGroup {
}

UpdateGroup 用于更新时指定的分组:

public interface UpdateGroup {
}
  1. 创建用户类

创建一个UserBean用户类,分别校验 username 字段不能为空和id字段必须大于0,然后加上CreationGroupUpdateGroup 分组。

/**
 * @author 公众号-索码理(suncodernote)
 */
@Data
public class UserBean {

    @NotEmpty( groups = {CreationGroup.class})
    private String username;

    @Min(value = 18)
    private Integer age;

    @Email(message = "邮箱格式不正确")
    private String email;

    @Min(value  = 1 ,groups = {UpdateGroup.class})
    private Long id;
}
  1. 创建接口

ValidationController 中新建两个接口 updateUsercreateUser

@RestController
@RequestMapping("validation")
public class ValidationController {

    @GetMapping("updateUser")
    public UserBean updateUser(@Validated({UpdateGroup.class})  UserBean userBean){
        return userBean;
    }

    @GetMapping("createUser")
    public UserBean createUser(@Validated({CreationGroup.class})  UserBean userBean){
        return userBean;
    }
}
  1. 测试

先对 createUser接口进行测试,我们将id的值设置为0,也就是不满足id必须大于0的条件,同样 username 不传值,即不满足 username 不能为空的条件。

通过测试结果我们可以看到,虽然id没有满足条件,但是并没有提示,只提示了username不能为空。

再对 updateUser接口进行测试,条件和测试 createUser接口的条件一样,再看测试结果,和 createUser接口测试结果完全相反,只提示了id最小不能小于1

至此,分组功能就演示完毕了。

嵌套校验

介绍嵌套校验之前先看一下两个概念:

  1. 嵌套校验(Nested Validation) 指的是在验证对象时,对对象内部包含的其他对象进行递归验证的过程。当一个对象中包含另一个对象作为属性,并且需要对这个被包含的对象也进行验证时,就需要进行嵌套校验。

  2. 嵌套属性指的是在一个对象中包含另一个对象作为其属性的情况。换句话说,当一个对象的属性本身又是一个对象,那么这些被包含的对象就可以称为嵌套属性

有这样一个需求,在保存用户时,用户地址必须要填写。下面来简单看下示例:

  1. 创建地址类 AddressBean

AddressBean 设置 countrycity两个属性为必填项。

@Data
public class AddressBean {

    @NotBlank
    private String country;

    @NotBlank
    private String city;
}
  1. 修改用户类,将AddressBean作为用户类的一个嵌套属性

特别提示:想要嵌套校验生效,必须在嵌套属性上加 @Valid 注解。

@Data
public class UserBean {

    @NotEmpty(groups = {CreationGroup.class})
    private String username;

    @Min(value = 18)
    private Integer age;

    private String email;

    @Min(value  = 1 ,groups = {UpdateGroup.class})
    private Long id;

	//嵌套验证必须要加上@Valid
    @Valid
    @NotNull
    private AddressBean address;
}
  1. 创建一个嵌套校验测试接口
@PostMapping("nestValid")
public UserBean nestValid(@Validated @RequestBody UserBean userBean){
    System.out.println(userBean);
    return userBean;
}
  1. 测试

我们在传参时,只传 country字段,通过响应结果可以看到提示了city 字段不能为空。
响应结果

可以看到使用了 @Valid 注解来对 Address 对象进行验证,这会触发对其中的 Address 对象的验证。通过这种方式,可以确保嵌套属性内部的对象也能够参与到整体对象的验证过程中,从而提高验证的完整性和准确性。

总结

本文介绍了@Valid注解和@Validated注解的不同,同时也进一步介绍了Springboot 参数校验的使用。不管是 JSR-303JSR-380又或是 Hibernate Validator ,它们提供的参数校验注解都是有限的,实际工作中这些注解可能是不够用的,这个时候就需要我们自定义参数校验了。下篇文章将介绍一下如何自定义一个参数校验器。

往期推荐

欢迎关注我的公众号“索码理”,原创技术文章第一时间推送。

  • 34
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: @Valid注解和@Validated注解都是用于校验数据的注解,但是它们的使用场景略有不同。 @Valid注解是JSR-303规范中定义的注解,用于校验JavaBean中的属性值是否符合规范。它可以用在方法参数、方法返回值、方法参数中的属性、方法返回值中的属性等位置上。在Spring Boot中,我们可以在Controller中使用@Valid注解来校验请求参数是否符合规范。 @Validated注解是Spring框架中提供的注解,它可以用于校验方法参数是否符合规范。它支持分组校验,可以根据不同的场景对参数进行不同的校验。在Spring Boot中,我们可以在Service层或者Controller中使用@Validated注解来校验方法参数是否符合规范。 总的来说,@Valid注解用于校验JavaBean中的属性值,而@Validated注解用于校验方法参数。两者都可以用于校验数据,但是使用场景略有不同。 ### 回答2: @Valid注解和@Validated注解都用于校验数据的有效性,但是它们有所不同。 @Valid注解是来自于javax.validation规范中的注解,是用于Bean Validation校验的,它可以用于校验Java Bean对象中的字段。@Valid注解只能加在某个目标类型参数上,并且该参数类型需要是一个对象,它可以递归验证对象中的所有字段和对象。 @Validated注解则是Spring框架提供的注解,是用于Spring校验的,它可以用于校验方法和参数。@Validated注解用于验证参数和返回值,通常放在接口方法上。@Validated注解描述的约束条件必须是JSR303支持的约束条件的JavaBean,而@Valid注解不支持约束条件。 总的来说,@Valid注解是制定了JSR303规范而来的,属于Bean Validation更多的是参数校验,而@Validated注解是Spring框架专门提供的注解,用于控制层的校验,其作用与@Valid注解类似,但更加灵活,能进行更多的分组约束、级联验证等。 ### 回答3: @Valid注解和@Validated注解是Java中用于数据校验的两个注解。它们都是基于Bean Validation规范的,提供了对Java Bean属性进行校验的功能。 @Valid注解用于进行简单的数据校验,它可以在Controller层的方法参数中对参数进行校验。它的作用是告诉Spring框架对该参数进行数据校验,如果校验失败,则会抛出ConstraintViolationException异常。该注解使用时需要配合bindingResult参数一起使用,bindingResult参数用于接收校验结果。 @Validated注解更加强大,除了提供了@Valid注解的功能外,它还可以在Service层和Dao层对方法参数进行校验。它支持Spring Expression Language(SpEL)表达式,并提供了基于分组校验的功能。基于分组校验可以根据不同的校验场景,对同一个实体进行不同的校验,增强了数据校验的灵活性。 除了以上的差异,还有一个重要区别:@Valid注解是标准的Java注解,而@Validated注解是Spring提供的注解。因此,如果项目中只使用了Spring框架,那么可以直接使用@Validated注解。但如果使用的是标准的Java环境,则需要使用@Valid注解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

索码理

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值