目录
引言
集合校验
普通集合
自定义对象的集合
级联校验
快速失败
自定义校验
接一篇文章化繁为简,使用Hibernate Validator实现参数校验(一)_往事如烟隔多年的博客-CSDN博客,本文继续对参数校验相关知识作以延伸。
当集合中存放的元素为包装类型时,采用如下方式进行校验。
校验方法
ResultDataVO createUserConsumption(@RequestBody
@NotEmpty(message="id列表不能为空")
List idList){
return ResultDataVO.success();
}
若此时接口需要批量传入用户信息,为了满足该条件创建如下的DTO对象,注意当前对象包含了分组校验信息,此时需要注意要验证集合对象时,必须使用@Valid注解,同时分组校验将失效。
UserDTO
public class UserDTO{
@NotNull(message = "id不能为空",groups = {UpdateGroup.class})
private Integer id;
@NotBlank(message = "名称不能为空",groups = {AddGroup.class,UpdateGroup.class,Default.class})
private String name;
@NotNull(message = "默认值不能为空")
private Integer defaultValue;
}
校验方法
ResultDataVO createUserConsumption(@RequestBody
@NotEmpty(message="参数列表不能为空")
@Valid List userList){
return ResultDataVO.success();
}
在上一步的集合校验中,若使用了@RequestBody + @Validated注解想对集合中元素进行分组校验时,会发现基础校验都将失效,而使用@Valid注解虽然解决了校验失效问题,但又无法满足分组校验的需求,那么有什么办法可以解决这个问题呢?有以下两种方案:
1.将DTO拆分,不同的DTO对应不同的数据操作(增删改查),沿用上面的方法完成校验。
2.创建新的DTO类,在类中使用集合存自定义数据,外部可以继续使用分组校验。
这里以方案二作演示,新建UserDataDTO类,其中包含一个集合对象,存储我们的UserDTO对象,需要在该字段上添加@Valid注解,除集合外,其它嵌套类型的对象需要验证时也可添加该注解,此处添加@Valid注解后,对应参数中包含基础校验注解时,将进行校验。
UserDataDTO
public class UserDataDTO{
@Valid
@NotEmpty(message="用户信息列表不能为空")
private List userDataList;
}
校验方法
此处可以在@Validated中指定分组校验的组信息。
@PostMapping("/validationInfo")
public ResultDataVO userListValidation(@RequestBody
@Validated(AddGroup.class)
@NotNull(message = "用户数据不能为空")
UserDataDTO userDataDTO){
return ResultDataVO.success();
}
请求参数
此处需要特别注意:使用JSON传入请求参数时,需要传入的对象信息名称为 userDataList,而不是当前入参userDataDTO!
{
"userDataList":[
{
"id":"1",
"name":"123"
}
]
}
默认情况下Validator校验框架会对所有的入参进行校验,而当请求中参数越来越多,某些参数的校验异常耗时,将会导致接口响应速度变慢,因此可以通过配置快速失败的方式,实现当一个参数校验不通过时立即返回,不会继续后面的校验。
创建配置类,设置failFast属性为true即可。
@Configuration
public class ValidationConfiguration {
@Bean
public Validator validator(AutowireCapableBeanFactory springFactory) {
try (ValidatorFactory factory = Validation.byProvider(HibernateValidator.class)
.configure()
// 快速失败
.failFast(true)
// 解决 SpringBoot 依赖注入问题
.constraintValidatorFactory(new SpringConstraintValidatorFactory(springFactory))
.buildValidatorFactory()) {
return factory.getValidator();
}
}
}
目前项目中对于手机号格式校验使用了@Pattern注解,通过正则表达式实现,而当校验需求增多时,需要不断CV代码,而原生的Validator中并没有提供手机号校验,因此可以通过自定义注解来实现手机号格式校验。
首先创建一个注解类型Phone,用于指定解作用的范围,实现类等基本信息
自定义注解@Phone
/*
* @Retention 指定注解保留的时期
* @Target 注解可作用的范围
* @Constraint 与注解关联的实现类
*/
@Documented
@Target({FIELD,PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
// 约束注解验证时的输出信息,默认为空
String message() default "手机号校验错误";
// 约束注解在验证时所属的组别
Class>[] groups() default {};
// 约束注解的有效负载
Class extends Payload>[] payload() default {};
}
实现类PhoneValidator
在与自定义注解关联的类中需要实现ConstraintValidator接口,并重写其isValid方法,可在方法内部编写具体的业务验证逻辑。
public class PhoneValidator
implements ConstraintValidator {
/**
* 自定义校验逻辑方法
* @param value
* @param context
* @return
*/
@Override
public boolean isValid(String value,
ConstraintValidatorContext context) {
// 手机号验证规则
String check = "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$";
Pattern regex = Pattern.compile(check);
// 空值处理
String phone = Optional.ofNullable(value).orElse("");
Matcher matcher = regex.matcher(phone);
// 返回验证结果
return matcher.matches();
}
}
使用
与基础校验注解使用方法一致,在需要校验的字段上添加注解即可。
@Phone(message = "手机号格式不正确")
private String phoneNumber;