一、介绍

Spring Validation 验证框架对参数的验证机制提供了@Validated (Spring’s JSR-303 规范,是标准 JSR-303 的一个变种),javax 提供了@Valid(标准 JSR-303 规范),配合 BindingResult 可以直接提供参数验证结果。其中对于字段的特定验证注解,比如 @NotNull。
两者在检验 Controller 的入参是否符合规范时,使用@Validated 或者 @Valid 在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同:

  1. @Validated
    分组:提供分组功能,可在入参验证时,根据不同的分组采用不同的验证机制。
    可注解位置:可以用在类型、方法和方法参数上。但是不能用在成员属性上
    嵌套验证:用在方法入参上无法单独提供嵌套验证功能;不能用在成员属性上;也无法提供框架进行嵌套验证;能配合嵌套验证注解 @Valid 进行嵌套验证。
  2. @Valid
    分组:无分组功能
    可注解位置:可以用在方法、构造函数、方法参数和成员属性上(两者是否能用于成员属性上直接影响能否提供嵌套验证的功能)
    嵌套验证:用在方法入参上无法单独提供嵌套验证功能;能够用在成员属性上,提示验证框架进行嵌套验证;能配合嵌套验证注解@Valid进行嵌套验证。

二、使用

1. SpringBoot 2.3.0后需要添加依赖

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

2. 配置 validation 使出现校验失败即返回

@Configuration
public class WebConfig {@Beanpublic Validator validator() {ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).configure()//failFast的意思只要出现校验失败的情况,就立即结束校验,不再进行后续的校验。.failFast(true).buildValidatorFactory();return validatorFactory.getValidator();}@Beanpublic MethodValidationPostProcessor methodValidationPostProcessor() {MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();methodValidationPostProcessor.setValidator(validator());return methodValidationPostProcessor;}
}

4. 编写全局异常捕获,捕获验证失败,统一返回

@Slf4j
@ControllerAdvice
public class ValidatedExceptionHandler {@ResponseBody@ExceptionHandler(BindException.class)public String exceptionHandler2(BindException exception) {BindingResult result = exception.getBindingResult();if (result.hasErrors()) {return result.getAllErrors().get(0).getDefaultMessage();}return "参数不可为空!";}@ResponseBody@ExceptionHandler(MethodArgumentNotValidException.class)public String exceptionHandler2(MethodArgumentNotValidException exception) {BindingResult result = exception.getBindingResult();if (result.hasErrors()) {return result.getAllErrors().get(0).getDefaultMessage();}return "参数不可为空!";}
}

5. 定义Dto,在参数上添加注解校验

@Data
public class ValidDto {@NotEmpty(message = "name 不可为空!")private String name;@NotBlank(message = "userId 不可为空!")private String userId;@Min(value = 1, message = "年龄有误!")@Max(value = 120, message = "年龄有误!")private int age;@NotBlank(message = "邮箱不可为空!")@Email(message = "邮箱有误!")private String email;@NotBlank(message = "mobile不可为空!")@Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$", message = "手机号码有误!")private String mobile;@NotNull(message = "validVo 不可为空!")@Validprivate ValidVo validVo;@NotEmpty(message = "list1 不可为空!")@Size(min = 1, max = 2, message = "list1 数据过大")@Validprivate List<ValidVo> list1;
}
@Data
public class ValidVo {@NotBlank(message = "gender is null")private String gender;@NotBlank(message = "test is null")private String test;
}

6. Controller

@RestController
@RequestMapping("/valid")
@CrossOrigin
public class ValidController {@GetMapping("/GetTest")public String getTest(@Valid ValidDto dto, BindingResult result) {if (result.hasErrors()) {return result.getAllErrors().get(0).getDefaultMessage();}return "success";}@GetMapping("/GetTest2")public String getTest2(@Validated ValidDto dto) {return "success";}@GetMapping("/GetTest3")public String getTest3(@Validated @RequestBody ValidDto dto) {return "success";}
}

三、分组校验

对一个DTO类需要有多中验证方式,在不同的情况下使用不同验证方式,比如在某些情况下我们希望param1,param2比传,其他可为空,在另一个接口我们又希望param3,param4比穿,其他的可为空,这种情况下,就可以使用分组校验。
Sping Vaild如果不指定Group,默认为 Default.class

  1. 定义Group
//分组1
public interface GroupValid1 {
}
//分组2
public interface GroupValid2 {
}
  1. DTO
@Data
public class GroupParamDto {@NotNull(message = "param1 is null !", groups = {GroupValid1.class})private String param1;@NotNull(message = "param2 is null !", groups = {GroupValid1.class})private String param2;@NotNull(message = "param3 is null !", groups = {GroupValid2.class})private String param3;@NotNull(message = "param4 is null !", groups = {GroupValid2.class})private String param4;@NotNull(message = "param5 is null !", groups = {GroupValid1.class, GroupValid2.class})private String param5;@NotNull(message = "param6 is null !", groups = {GroupValid1.class, GroupValid2.class})private String param6;//不指定默认 Default.class @NotNull(message = "param7 is null !")private String param7;
}
  1. Controller
@Slf4j
@RestController
@RequestMapping("group")
public class GroupTestController {//分组校验@GetMapping("/test1")public String test1(@Validated({GroupValid1.class, GroupValid2.class}) GroupParamDto dto) {log.info(dto.toString());return "success";}
}

运行上面的逻辑,在DTO中所有指定groups 为 GroupValid1.class, GroupValid2.class的字段必传。

四、分组序列

默认情况下,不同组别的约束验证是无序的,然而在某些情况下,约束验证的顺序却很重要,如果第二个组中的约束验证依赖于第一个组的参数来进行验证,这个时候就需要组之间有一定的顺序。

一个组可以定义为其他组的序列,使用它进行验证的时候必须符合该序列规定的顺序。在使用组序列验证的时候,如果序列前边的组验证失败,则后面的组将不再给予验证。

  1. Group
@javax.validation.GroupSequence({GroupValid2.class, GroupValid1.class})
public interface GroupSequence {
}
  1. Controller
//分组序列
@GetMapping("/test2")
public String testSequence(@Validated({GroupSequence.class}) GroupParamDto dto) {log.info(dto.toString());return "success";
}

五、校验多个对象

在Controller中很多情况下不只是单个对象,需要对多个对象进行校验,加入校验只需在每个对象前加入@Validated注解即可。

  1. 再新建一个DTO
@Data
public class GroupNameDto {@NotNull(message = "name1 is null !", groups = {GroupValid1.class})private String name1;@NotNull(message = "name2 is null !", groups = {GroupValid2.class})private String name2;
}
  1. Controller
//校验多个对象
@GetMapping("/test4")
public String test4(@Validated({Default.class}) GroupParamDto dto, @Validated({GroupValid2.class}) GroupNameDto nameDto) {log.info(dto.toString());log.info(nameDto.toString());return "success";
}

六、自定义验证

上面讲到的参数校验,全都是在Controller 控制层做的参数校验,但是有些情况我们还需要在其他地方校验,比如在我自定义的方法,需要对参数校验,总不能还要按个if判断吧。

  1. 自定义 ValidationUtil类,实现快速校验和全部校验
import org.hibernate.validator.HibernateValidator;import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;public class ValidationUtil {//开启快速结束模式 failFast (true)private static Validator failFastValidator = Validation.byProvider(HibernateValidator.class).configure().failFast(true).buildValidatorFactory().getValidator();//全部校验private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//注解验证参数(快速失败模式)public static <T> ValidResult fastFailValidate(T obj, Class<?>... group) {Set<ConstraintViolation<T>> constraintViolations = failFastValidator.validate(obj, group);//返回异常resultif (constraintViolations.size() > 0) {return ValidResult.error(constraintViolations.iterator().next().getMessage());}return ValidResult.success();}//注解验证参数(全部校验)public static <T> ValidResult allCheckValidate(T obj, Class<?>... group) {Set<ConstraintViolation<T>> constraintViolations = validator.validate(obj, group);if (constraintViolations.size() > 0) {List<String> errorMessages = new LinkedList<String>();Iterator<ConstraintViolation<T>> iterator = constraintViolations.iterator();while (iterator.hasNext()) {ConstraintViolation<T> violation = iterator.next();errorMessages.add(violation.getMessage());}return ValidResult.error(String.join(",", errorMessages));}return ValidResult.success();}
}
  1. 编写ValidResult返回封装
@Data
public class ValidResult {private boolean hasError;private String errMessage;public static ValidResult error(String errMessage) {ValidResult result = new ValidResult();result.hasError = true;result.errMessage = errMessage;return result;}public static ValidResult success() {ValidResult result = new ValidResult();result.hasError = false;return result;}}
  1. DTO
@Data
public class MyDto {@NotNull(message = "name is null!",groups = {GroupValid1.class})private String name;@NotNull(message = "message is null!",groups = {GroupValid2.class})private String message;
}
  1. 校验
public String test2(MyDto dto) {ValidResult result = ValidationUtil.fastFailValidate(dto, GroupValid1.class);
//  ValidResult result = ValidationUtil.allCheckValidate(dto);if (result.isHasError()) {return result.getErrMessage();}return "success";
}

Spring Validation 验证框架全面总结相关推荐

  1. Spring Validation验证框架参数验证 @Validated 和 @Valid 的区别

    参数验证 @Validated 和 @Valid 的区别 Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303 规范,是标准 JSR- ...

  2. @Validated和@Valid区别:Spring validation验证框架对入参实体进行嵌套验证必须在相应属性(字段)加上@Valid而不是@Validated...

    Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR- ...

  3. 关于validation验证框架不起作用的解决方法

    搞了几天Validator框架验证,怎么做它都不起作用,我找了N个资料,都没查出来问题所在.终于,发现了问题,我把LoginForm.java(例子),就是表单Bean中的默认验证方法validate ...

  4. Spring Validation 校验

    一.概述 在 Web 应用中,客户端提交数据之前都会进行数据的校验,比如用户注册时填写的邮箱地址是否符合规范.用户名长度的限制等等,不过这并不意味着服务端的代码可以免去数据验证的工作,用户也可能使用 ...

  5. Spring Validation校验

    本文来说下现在使用的比较多的Spring Validation校验框架. 文章目录 概述 校验注解 JSR-303包含的注解 Hibernate Validator扩展的注解 简单使用 引入依赖 re ...

  6. jquery validation-jquery的验证框架 详解(1)

    jquery validation验证框架是一款非常优秀的客户端数据验证框架.我们在日常的项目中都会应用得到.今天开始我们会分两到三个个阶段 详细的了解这款插件 至于这款插件是多么的优秀,怎么个描述法 ...

  7. 跟杨春娟学SpringMVC笔记:Form表单之Spring验证框架

    跟杨春娟学SpringMVC笔记:Form表单之Spring验证框架 完成:第一遍 1.Spring框架验证和JSR303验证的不同之处在哪里? 不同一:Spirng框架验证需要实现Validator ...

  8. Android非空格式验证框架Validation的使用---第三方库学习笔记(四)

    Validation简介: 这是一个简单的函数库,使用注释语法来验证用户输入的表单信息.你仅需编写几行代码就可以实现一些表单验证功能,且显示的所有视图都将反馈给用户.它还带有一个可扩展的在线验证选项, ...

  9. spring mvc + JSR-303验证框架

    为什么80%的码农都做不了架构师?>>>    http://www.cnblogs.com/liukemng/p/3738055.html 在系列(4).(5)中我们展示了如何绑定 ...

  10. Spring Validation最佳实践及其实现原理,参数校验没那么简单!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:六点半起床 juejin.im/post/685654110 ...

最新文章

  1. Oculus也陷隐私门:向Facebook发送隐私数据
  2. Go 语言编程 — 程序运行环境
  3. 宝元系统u盘使用说明_教你如何使用U盘安装电脑系统
  4. eclipse mysql生成实体类_Eclipse实现数据库反向生成实体类(pojo)-------(插件安装和实现步骤的说明)...
  5. ROS project part 1: Ubuntu中安装opencv包以及相应的依赖
  6. PyTorch 之 requires_grad,requires_grad_(),grad_fn
  7. linux resin 服务功能,linux服务之resin
  8. python获取网页元素坐标_Python实战爬虫系统学习笔记一:解析网页中的元素
  9. java 获取方法_Java 反射理解(三)-- Java获取方法信息
  10. java自定义findbugs规则,定制 findbugs规则 - 阿里巴巴一个测试架构师 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  11. Centos-shell-简介
  12. 奇怪吸引子---Rucklidge
  13. vue中使用阿里矢量库彩色图标办法
  14. 51单片机——LED流水灯
  15. 深度神经网络与卷积神经网络的区别
  16. 小米 红米【AC2100】一键刷BREED【30秒刷完】小白脑残专用 无需工具TELNET + 检查坏块
  17. (已解决)vue数组添加数据后页面无法实时渲染
  18. The NPF driver isn't running. You may have trouble capturing or listing interfaces
  19. Proxmox集群网络配置
  20. 661. Image Smoother

热门文章

  1. 主成分分析二级指标权重_因子分析法如何确定主成分及各个指标的权重?
  2. python计算三角形斜边上的中线_直角三角形斜边上的中线的性质及其应用
  3. PPT怎么修改母版背景
  4. 带孔的打印纸怎么设置_带孔电脑打印纸规格尺寸的相关知识及应用范围
  5. Java语言实现会议安排问题,利用贪心法思想解决问题
  6. 逃离北上广的成本越来越高了
  7. synchronized的底层实现
  8. android高德地图自定义地图,Android集成高德地图如何自定义marker
  9. 计算机英语总结800,高三英语教师工作总结800字(通用5篇)
  10. 景深与光圈、拍摄距离和镜头焦距的关系