SpringBoot Validator使用
官方文档优先: https://docs.spring.io/spring-boot/docs/2.7.6/reference/htmlsingle/
Validator注册
启动时WebMvcAutoConfiguration
将会自动获取Validator
获取Validator时,会优先获取已经注册的Validator,如果没有注册的Validator,则将自动创建Vaidator(new OptionalValidatorFactoryBean())
而自动创建的ValidatorAdapotr将没有Validator,如图:
SpringValidator.java
如果没有Validator,则在数据到达时无法进行验证
ConfigurableWebBindingInitializer.java
SpringValidatorAdapoer.java
具体为什么无法验证呢?我们在后面对此做出讲解。
所以如果想要使用Validator功能,要么使用官方依赖,要么自定义Validator。
.gradle
implementation org.springframework.boot:spring-boot-starter-validationspring-boot-starter-validation
maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Validator是如何进行验证的
- 首先DispatcherServlet.java开始处理数据
DispatcherServlet.java
- 然后开始解析参数
HandlerMethodArgumentResolverComposite.java
- 解析参数时需要创建WebDataBind进行数据解析绑定[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
- 创建完后需要初始化DataBind,而初始化时就需要设置Validator,而设置Validator的条件就是上面说过的supports函数
- 初始化完DataBind后,就需要解析参数并进行校验了
RequestReponseBodyMethodProcess.java
- 校验的过程就是先捕获所有带有Validated或Valid注解的类
AbstractMessageConverterMethodArgumentReslover.java
ValidationAnnotationUtils.java
- 再对捕获的类进行校验,校验就是通过前面所注册的Validator(自定义Validator Bean或官方
spring-boot-starter-validation
包等)进行的,这里就不多说了。
DataBinder.java
spring-boot-starter-validation 包
- Controller添加@Validated注解
- Bean 添加约束
public class AmsArticle implements Serializable {
@Size(min = 2)
private String title;
}
注解 | 功能 |
@AssertFalse | 可以为null,如果不为null的话必须为false |
@AssertTrue | 可以为null,如果不为null的话必须为true |
@DecimalMax | 设置不能超过最大值 |
@DecimalMin | 设置不能超过最小值 |
@Digits | 设置必须是数字且数字整数的位数和小数的位数必须在指定范围内 |
@Future | 日期必须在当前日期的未来 |
@Past | 日期必须在当前日期的过去 |
@Max | 最大不得超过此最大值 |
@Min | 最大不得小于此最小值 |
@NotNull | 不能为null,可以是空 |
@Null | 必须为null |
@Pattern | 必须满足指定的正则表达式 |
@Size | 集合、数组、map等的size()值必须在指定范围内 |
@Email | 必须是email格式 |
@Length | 长度必须在指定范围内 |
@NotBlank | 字符串不能为null,字符串trim()后也不能等于“” |
@NotEmpty | 不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于“” |
@Range | 值必须在指定范围内 |
@URL | 必须是一个URL |
- 全局ValidateException处理
public class GlobalExceptionHandler {
/**
* 处理Validated校验异常
* <p>
* 注: 常见的ConstraintViolationException异常, 也属于ValidationException异常
*
* @param e
* 捕获到的异常
* @return 返回给前端的data
*/
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
public Map<String, Object> handleParameterVerificationException(Exception e) {
log.error(" handleParameterVerificationException has been invoked", e);
Map<String, Object> resultMap = new HashMap<>(4);
resultMap.put("code", "100001");
String msg = null;
if (e instanceof MethodArgumentNotValidException) {
BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
// getFieldError获取的是第一个不合法的参数(P.S.如果有多个参数不合法的话)
FieldError fieldError = bindingResult.getFieldError();
if (fieldError != null) {
msg = fieldError.getDefaultMessage();
}
} else if (e instanceof BindException) {
// getFieldError获取的是第一个不合法的参数(P.S.如果有多个参数不合法的话)
FieldError fieldError = ((BindException) e).getFieldError();
if (fieldError != null) {
msg = fieldError.getDefaultMessage();
}
} else if (e instanceof ConstraintViolationException) {
/*
* ConstraintViolationException的e.getMessage()形如
* {方法名}.{参数名}: {message}
* 这里只需要取后面的message即可
*/
msg = e.getMessage();
if (msg != null) {
int lastIndex = msg.lastIndexOf(':');
if (lastIndex >= 0) {
msg = msg.substring(lastIndex + 1).trim();
}
}
/// ValidationException 的其它子类异常
} else {
msg = "处理参数时异常";
}
resultMap.put("msg", msg);
return resultMap;
}
}
其他
官方文档…
参考: