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格式 | |
@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; } }
其他
官方文档…
参考: