概述
SpringBoot validation是对Hibernate Validator二次封装的验证框架;
使用一些注解(@Valid,@Max,@Min等)对请求参数校验,优雅且大大减少代码量;
通过@RestControllerAdvice和@ExceptionHandler实现全局异常处理;
针对MethodArgumentNotValidException和BindException异常处理
(具体用法,可自行百度)
问题
常用注解在javax.validation.constraints包下
单独使用注解没任何问题,当多个注解修饰一个对象属性时,会存在问题;
validation默认会按照注解顺序依次校验,每个注解的校验方法在org.hibernate.validator.internal.constraintvalidators包下;
例如:
@NotNull
@Max(20)
private String addressLength;
先判断是否为null,然后校验长度不超过20;
如果入参为null,则会有两个报错,null和超过20,关键代码在org.hibernate.validator.internal.constraintvalidators.bv.number.bound.MaxValidatorForCharSequence#compare方法,因为入参是null,无法转成数字,validation将这种情况视为校验失败,因此做出提示;
出现这种情况,归根结底是因为没有配置【快速失败】,即,当出现校验失败时,立即结束校验,第一个判断为null则结束并抛出对应异常;
所以,我们的关键点就是开启【快速失败】;
解决办法
参考源码
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration
@Configuration(proxyBeanMethods = false)
public class ValidatorConfiguration {
@Bean
@ConditionalOnMissingBean(Validator.class)
public LocalValidatorFactoryBean validator(AutowireCapableBeanFactory springFactory) {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
// 快速失败
factoryBean.getValidationPropertyMap().put(BaseHibernateValidatorConfiguration.FAIL_FAST, Boolean.TRUE.toString());
return factoryBean;
}
}
环境
继承maven
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
</parent>
maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
没有找到通过修改配置参数或配置文件的方式实现【快速失败】;
欢迎提出更优方案