如果之后需要的话,会再开博客描写,这样会显得主题突出一些。
后续扩展部分会解释message,groups,payload三个核心属性等。
自定义注解部分,会给出蚂蚁金服内部真实采用的自定义校验注解。
二,简介简单来说,就是通过Validation框架,进行数据的各类校验。从Java的基本数据类型到自定义封装数据类型,从非空判断到正则表达式判断,都是Validation框架所支持的。
在Validation之前,层次架构中,开发者总是采用分层验证模型。就是分别在控制层,服务层,数据层等分别对目标对象的目标属性进行校验。很明显,这是非常不优雅的,而且开发效率低,因为存在大量重复校验逻辑。
而Validation则提出一个元数据验证模型,而在Spring体系中,则表现为Java Bean验证模型。站在Spring角度来说,无论是在哪个层次,都是针对Java Bean进行验证的。所以,Validation则通过在目标Bean上添加约束注解,以及背后的验证程序,实现了一个对业务代码无侵入的校验功能。
三,使用方法 1.添加依赖 <!-- Validation 相关依赖 --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>这是Validation框架的核心依赖。
该依赖是包含在SpringBoot的spring-boot-web-starter中的。所以如果使用了前面Spring-boot-web-starter依赖,则不需要再次引入Validation框架的依赖。
至于EL等依赖,常用于自定义注解,具体可以根据需要进行依赖引入。
2.添加约束注解针对目标Bean,针对不同属性的验证需求,添加不同的约束注解。
如UserVo的userId,添加@NotNull注解,表示这个属性在验证框架中不可为空。
有关约束注解,后面有详尽描述。
3.开启验证即使对元数据模型添加了约束注解,但是还没有明确开启验证流程。站在Validation框架的角度,它并不知道应该在什么时候进行校验。因为除了控制层,我们还可能在服务层验证。即使是在服务层,一个调用链路,可能涉及多个方法,也需要确定在哪个方法进行验证。
那么,开启验证的方法有两种(也许还有别的方法,欢迎补充):
验证注解:@Validated或者@Valid
初始化验证器:Validation.buildDefaultValidatorFactory().getValidator();
验证注解@Validated注解的效果与@Valid是一样的,毕竟@Validated是SpringBoot对@Valid注解的封装(@Valid是Java的自带的注解)。而@Validated注解是包含在SpringBoot的spring-boot-web-starter中的。
在对应位置添加@Validated注解(当程序执行到这里,就会执行对应的校验逻辑):
自定义对象(启动注解在自定义对象前) @PostMapping("save.do") @ResponseBody public ServerResponse saveConfig(@Validated(InclinationConfig.ConfigCommitGroup.class) InclinationConfig inclinationConfig) { // 业务逻辑 } 基本数据类型() @Validated public class demo { @PostMapping("get.do") @ResponseBody public ServerResponse getConfig(int configId) { // 业务逻辑 } }针对Java基本数据类型的@NotNull,则需要将对应类上添加@Validated注解。
验证器初始化,建立验证器对象(Validator对象):
// 验证器对象 private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();获取验证结果集合(这里也就是开启验证的时间位置):
// 验证结果集合 private Set<ConstraintViolation<UserInfo>> set = validator.validate(userInfo); // 验证过程可以添加分组信息 private Set<ConstraintViolation<UserInfo>> set = validator.validate(userInfo,UserInfo.RegisterGroup.class);处理验证结果集合:
set.forEach(item -> { // 输出验证错误信息 System.out.println(item.getMessage()); });当然啦。更多情况下,我们是直接抛出异常的:
// 判断验证结果集是否为空(验证结果集放的都是验证失败时的message) if(!CollectionUtils.isEmpty(set)) { // 循环时,采用StringBuilder可以有效提高效率(详见String,StringBuilder,StringBuffer三者区别) StringBuilder exceptionMessage = new StringBuilder(); set.forEach(validationItem -> { exceptionMessage.append(validationItem.getMessage()); }); // 直接抛出异常(其实这也就是@Valid注解的默认校验器的做法) throw new Exception(exceptionMessage.toStrring()); } 四,约束注解 1.初级应用:常用注解这里给出了Validation框架(validation-api-2.0.1.Final)中constraints下全部的注解说明:
空值校验:
@Null:目标值为null。比如,注册时的userId当然是null(即使不为null,系统也不会采用的)。
@NotNull:目标值不为null。比如,登录时的userId当然不为null(当然也可能是通过了外部鉴权,然后内部裸奔)。
@NotEmpty:目标值不为empty。相较于上者,增加了对空值的判断(就是""无法通过@NotEmpty的校验)
@NotBlank:目标值不为blank。相较于上者,增加了对空格的判断(就是空格无法通过@NotBlank校验的)
范围校验:
@Min:针对数值类型,目标值不能低于该注解设定的值。
@Max:针对数值类型,目标值不能高于该注解设定的值。
@Size:针对集合类型,目标集合的元素数量不可以高于max参数,不可以低于min参数。
@Digits:针对数值类型,目标值的整数位数必须等于integer参数设定的值,小数位数必须等于fraction参数设定的值。
@DecimalMax:针对数值类型,目标值必须小于该注解设定的值。
@DecimalMin:针对数值类型,目标值必须大于该注解设定的值。
@Past:针对于日期类型,目标值必须是一个过去的时间。
@PastOrPresent:针对于日期类型,目标值必须是一个过去或现在的时间。
@Future:针对于日期类型,目标值必须是未来的时间。
@FutureOrPresent:针对于日期类型,目标值必须是未来或未来的时间。
@Negative:针对数值类型,目标值必须是负数。
NegativeOrZero:针对数值类型,目标值必须是非正数。
@Positive:针对数值类型,目标值必须是正数。
@PositiveOrZero:针对数值类型,目标值必须是非负数。
其他校验:
@AssertTrue:针对布尔类型,目标值必须为true。
@AssertFalse:针对布尔类型,目标值必须为false。
@Email:针对字符串类型,目标值必须是Email格式。
@URL:针对字符串类型,目标值必须是URL格式。
@Pattern:针对字符串类型,目标值必须通过注解设定的正则表达式。