ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

@Validated和@Valid用法详解(JSR-303)

2022-06-26 23:01:01  阅读:175  来源: 互联网

标签:303 校验 Valid 分组 JSR Validated class


背景

一个管理系统,有个excel导入的功能,需要对用户导入的每一行的每一列的每一个字段做校验,如果有错误需要记录下来,后续用户可以通过批次查询到当次导入的数据哪里有问题,可根据提示修改。代码里面会出现大量的if-else,且和业务没有关系,这时候SpringBoot的validation起大作用了。

JSR

讲validation之前需要先了解一下JSR。JSR是Java Specification Requests 的缩写,意思是Java规范提案。是指向JCR(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。

JSR-303

JSR-303是Java EE 6中的一项子规范,叫做Bean Validation,Hibernate Validator是 Bean Validation 的参考实现。Hibernate Validator 提供了 JSR303规范中所有内置constraint的实现,除此之外还有一些附加的constraint。SpringBoot 中的 bean validation 集成了Hibernate Validator 和 tomcat-embed-el(可参照传送门),做了一套自己的Spring's JSR-303规范。具体区别其实就是@Validated@Valid的区别。

Hibernate validator

用法

讲用法之前先讲一下@Valid@Validated的区别,由它们的区别带出两者相同的用法和不同的用法。

@Valid和@Validated的区别

Spring Validation验证框架对参数的验证机制提供了@Validated(Spring的JSR-303规范,是标准JSR-303的一个变种),Javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。

@Valid属于Javax.validation包下,是jdk给提供的,是使用Hibernate validation的时候使用(java的JSR303声明了@Valid这类接口,而Hibernate-validator对其进行了实现)

@Validated是org.springframework.validation.annotation包下的,是spring提供的,是只用Spring validator校验机制使用

在检验Controller的入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同:

1.分组

@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
@Valid:作为标准的JSR-303规范,还没有吸收分组的功能

@Validated会有分组的概念,后面默认是有一个Default.class,当你的@Validated后面没有加任何校验分组信息的时候默认会加Default分组,而对于被校验的对象的属性字段,如果你在属性的校验标签里面没有指定分组会添加到默认分组Default里面。所以如果你的对象里面的每个属性都指定了分组信息,而接口上面并没有添加分组信息会出现@Validated“失效的情况”,实际是因为它校验的是Default分组,而没有字段属于Default分组。上述校验不管加不加@ReqeustBody都能完成校验,但是都不能完成嵌套的校验。

//Vo
@Data
public class UserVo {

   //在分组EditUser时,验证id不能为空,其他情况下不做验证
   @NotNull(groups={EditUser.class})
   private Long id;

   @NotEmpty(message = "用户名不能为空", groups = {AddUser.class, EditUser.class})
   private String username;

   @Size(min=6 ,max= 20 , message = "密码最少6位,最高20位", groups = {AddUser.class, EditUser.class})
   private String password;

   //此处不填分组消息表示所有分组都需要校验
   @NotNull(groups = {AddUser.class, EditUser.class})
   private UserIdCardVo userIdCardVo;
}

//controller
@PostMapping("/add")
public String addUser(@RequestBody @Validated({AddUser.class}) UserVo vo, BindingResult result) throws APIException, JsonProcessingException {
 //测试全局拦截器
 if (null == vo) {
   throw new APIException(ResultCode.FAILED, "用户信息为空!");
}
 ObjectMapper mapper = new ObjectMapper();
 System.out.println(result.toString());
 System.out.println(vo);
 if (result.hasErrors()) {
   StringBuilder sb = new StringBuilder();
   for (ObjectError error : result.getAllErrors()) {
     System.out.println(mapper.writeValueAsString("捕获到的单个error对象:" + error));
     System.out.println(error.getDefaultMessage());
     sb.append(error.getDefaultMessage()).append(",");
  }
   throw new APIException(ResultCode.FAILED, sb.toString());
}
 return "success";
}

@Valid由于不支持分组,所以对于所以校验标签里面添加了groups字段的都不会校验会跳过。 @Valid 加不加@RequestBody 基本校验会进行,嵌套校验需要在嵌套的对象上面加@Valid则可以进行嵌套校验,由于没有分组的概念,对于不同情况校验字段不同则需要在业务逻辑里面判断。

//VO
@Data
public class CustomerInfoVo {
   //在分组EditUser时,验证id不能为空,其他情况下不做验证
   private Long id;

   @NotEmpty(message = "用户名不能为空")
   private String username;

   @Size(min=6 ,max= 20 , message = "密码最少6位,最高20位")
   private String password;

   //此处不填分组消息表示所有分组都需要校验
   @NotNull
   @Valid
   private UserIdCardVo userIdCardVo;
}

//controller
@PostMapping("/add")
public String addCustomer(@RequestBody @Valid CustomerInfoVo vo, BindingResult result) throws APIException, JsonProcessingException {
 //测试全局拦截器
 if (null == vo) {
   throw new APIException(ResultCode.FAILED, "用户信息为空!");
}
 ObjectMapper mapper = new ObjectMapper();
 System.out.println(result.toString());
 System.out.println(vo);
 if (result.hasErrors()) {
   StringBuilder sb = new StringBuilder();
   for (ObjectError error : result.getAllErrors()) {
     System.out.println(mapper.writeValueAsString("捕获到的单个error对象:" + error));
     System.out.println(error.getDefaultMessage());
     sb.append(error.getDefaultMessage()).append(",");
  }
   throw new APIException(ResultCode.FAILED, sb.toString());
}
 return "success";
}

注意:

BindException是@Validation单独使用校验失败时产生的异常
MethodArgumentNotValidException是@RequestBody和@Validated配合时产生的异常,比如在传参时如果前端的json数据里部分缺失@RequestBody修饰的实体类的属性就会产生这个异常
BindingResult对于上述两种异常都可以捕获,直接放在校验标签后面就可以

2.注解地方

@Validated:用在类型、方法和方法参数上。但不能用于成员属性
@Valid:可以用在方法、构造函数、方法参数和成员属性上(所以可以用@Valid实现嵌套验证)

3.依赖

//@Validated:SpringBoot有专门的started里面已经包含了Hibernate Validator,依赖如下
   <!--        validation相关-->
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-validation</artifactId>
   </dependency>
     
//@Valid:Hibernate Validor,对于非SpringBoot项目可以单独引入
   <dependency>
     <groupId>org.hibernate.validator</groupId>
     <artifactId>hibernate-validator</artifactId>
     <version>6.0.7.Final</version>
   </dependency>        

 

示例代码

参考:

1.https://blog.csdn.net/weixin_44440642/article/details/106335653
2.https://mp.weixin.qq.com/s/eZS9dQ8I2FWEP6ykeDAHUg
3.https://www.cnblogs.com/zhangww/p/14786219.html
4.https://www.cnblogs.com/softidea/p/12192444.html
5.https://blog.csdn.net/qin_zhimou/article/details/100098884
6.https://blog.csdn.net/m0_50867266/article/details/119329618
 

标签:303,校验,Valid,分组,JSR,Validated,class
来源: https://www.cnblogs.com/ashScc/p/16414649.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有