目录
关于Spring Validation
Spring Validation框架的主要作用是检查方法的参数的基本有效性。
添加依赖
此框架的依赖项的artifactId
为:spring-boot-starter-validation
。
<!-- Spring Boot支持Spring Validation用于检查方法参数的基本有效性的依赖项 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency>
检查封装的请求参数
需要先在方法的参数(封装的类型)前添加@Valid
或@Validated
注解,以表示“将检查此参数的基本有效性”,例如:
@PostMapping("/add-new")
public String addNew(@Valid AlbumAddNewParam albumAddNewParam) {
albumService.addNew(albumAddNewParam);
return "添加成功!";
}
然后,需要在封装的类型的属性上添加检查注解,以配置对应的检查规则,例如:
@Data
public class AlbumAddNewParam implements Serializable {
@NotNull
private String name;
}
经过以上配置,参数name
将不允许为null
值(空字符串不是null),如果客户端提交的请求中没有name
的值,将直接响应400
错误!
处理BindException
当检查参数的基本有效性不通过时,在服务器端的控制台会提示错误详情,例如:
2023-05-11 14:25:21.058 WARN 45924 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'albumAddNewParam' on field 'name': rejected value [null]; codes [NotNull.albumAddNewParam.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [albumAddNewParam.name,name]; arguments []; default message [name]]; default message [不能为null]]
检查注解还可以配置message
属性,用于指定检查不通过时的文本信息,例如:
@NotNull(message = "添加相册失败,必须提交相册名称!")
private String name;
经过以上配置后,如果检查失败,错误信息大致如下:
Field error in object 'albumAddNewParam' on field 'name': rejected value [null]; codes [NotNull.albumAddNewParam.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [albumAddNewParam.name,name]; arguments []; default message [name]]; default message [添加相册失败,必须提交相册名称!]
然后,需要在全局异常处理器中添加处理BindException
请求的方法:
以下当有多个检查都不通过时,解决方案1是随机显示一个不通过时的文本信息
解决方案2是拼接显示多个不通过时的文本信息
StringJoiner相当于StringBuilder,不同的是它可以加分割符,和前缀以及后缀(它有两款构造方法,一个是只加分隔符,一个是加分隔符前缀后缀)
解决方案3是通过集合得到数组形式的不通过时的文本信息
@ExceptionHandler
public String handleBindException(BindException e) {
log.warn("程序运行过程中出现了BindException,将统一处理!");
log.warn("异常信息:{}", e.getMessage());
// 【解决方案-1】使用1个字符串表示1个错误信息
String message = e.getFieldError().getDefaultMessage();
return message;
// 【解决方案-2】使用1个字符串表示错误信息
// StringJoiner stringJoiner = new StringJoiner(",", "请求参数错误,", "!");
// List<FieldError> fieldErrors = e.getFieldErrors();
// for (FieldError fieldError : fieldErrors) {
// String defaultMessage = fieldError.getDefaultMessage();
// stringJoiner.add(defaultMessage);
// }
// return stringJoiner.toString();
// 【解决方案-3】使用集合表示多个错误信息,需要将当前方法的返回值类型声明为对应的集合类型
// List<String> messageList = new ArrayList<>();
// List<FieldError> fieldErrors = e.getFieldErrors();
// for (FieldError fieldError : fieldErrors) {
// String defaultMessage = fieldError.getDefaultMessage();
// messageList.add(defaultMessage);
// }
// return messageList;
}
需要注意:Spring Validation在检查请求参数的格式时,会检查所有属性配置的规则,找出所有的错误,如果希望实现“只要发现错误,就不再向后检查”,需要将其配置为“快速失败”,配置做法是使用配置类(比如在上面选择方案一的时候就不会随机显示了):
@Slf4j
@Configuration
public class ValidationConfiguration {
public ValidationConfiguration() {
log.debug("创建配置类对象:ValidationConfiguration");
}
@Bean
public javax.validation.Validator validator() {
return Validation.byProvider(HibernateValidator.class)
.configure() // 开始配置
.failFast(true) // 配置快速失败
.buildValidatorFactory() // 构建Validator工厂
.getValidator(); // 从Validator工厂中获取Validator对象
}
}
检查未封装的请求参数
对于未封装的请求参数(例如参数列表中的`Long id`)的检查,需要先在当前方法所在的类上添加`@Validated`注解,例如:
@RestController
@RequestMapping("/album")
@Validated
public class AlbumController {
}
然后,在参数上添加对应的检查注解,例如:
min的默认最小值是0,设置为1,代表最小id值为1。最大值是默认很大不需要设置。
(这里加 @RequestParam是为了api文档有输入框,迎合它的bug,没有其他作用,以后是要去掉的)
@PostMapping("/delete")
public String delete(@Range(min = 1, message = "根据ID删除相册失败,请提交合法的ID值!")
@RequestParam Long albumId) throws Exception {
// ...
}
暂时不使用全局异常处理器,当提交的请求参数不符合以上配置的规则时,在服务器的控制台可以看到错误信息:
javax.validation.ConstraintViolationException: delete.albumId: 根据ID删除相册失败,请提交合法的ID值!
则需要在全局异常处理器中添加处理以上异常:
@ExceptionHandler
public String handleConstraintViolationException(ConstraintViolationException e) {
log.warn("程序运行过程中出现了ConstraintViolationException,将统一处理!");
log.warn("异常信息:{}", e.getMessage());
String message = null;
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
for (ConstraintViolation<?> constraintViolation : constraintViolations) {
message = constraintViolation.getMessage();
}
return message;
检查注解
在org.hibernate.validator.constraints
和javax.validation.constraints
这2个包中的都是检查注解!
常用的检查注解有:
-
@NotNull
:不允许为null
值-
可以用于任何类型
-
-
@NotEmpty
:不允许为空字符串(长度为0的字符串),并且会检查是否为null
值(为null
时报错)-
仅能用于字符串类型的参数
-
-
@NotBlank
:不允许为空白,即不允许是“仅由空格、TAB等空白值组成的字符串”-
仅能用于字符串类型的参数
-
-
@Range
:通过配置min
和max
属性来限制数值类型参数的值区间,它不会检查是否为null
(为null
并不执行任何检查,且不会报错)-
仅能用于整型参数
-
-
@Pattern
:通过配置regexp
属性来配置正则表达式-
仅能用于字符串类型的参数
-