目录
在pom.xml中添加spring-boot-starter-validation依赖项:
- <!-- Spring Boot Validation框架,用于检查数据格式 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-validation</artifactId>
- </dependency>
首先,在POJO参数前添加@Valid或@Validated注解,用于表示此参数是需要通过Validation框架进行检查的!
例如:
- @ApiOperation("添加相册")
- @PostMapping("/add-new")
- // ↓ 新添加的注解
- public JsonResult addNew(@Valid AlbumAddNewDTO albumAddNewDTO) {
- albumService.addNew(albumAddNewDTO);
- return JsonResult.ok();
- }
然后,在此参数的属性上添加检查注解,例如添加@NotNull注解,表示将对此属性进行检查,此属性的值不允许为null:
- @Data
- public class AlbumAddNewDTO implements Serializable {
-
- @ApiModelProperty(value = "相册名称", required = true)
- @NotNull // 新添加的注解
- private String name;
-
- // 省略后续代码
完成后,重启服务,通过API文档提交请求时,故意不提交name(将对应的输入框删除),则服务器端尝试接收的name就会是null,无法通过@NotNull的检查规则,默认将出现400错误,例如:
{
"timestamp": "2022-12-01T06:38:26.020+00:00",
"status": 400,
"error": "Bad Request",
"path": "/album/add-new"
}
并且,在服务器端的控制台会提示以下错误:
2022-12-01 14:38:26.017 WARN 10708 --- [io-9080-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'albumAddNewDTO' on field 'name': rejected value [null]; codes [NotNull.albumAddNewDTO.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [albumAddNewDTO.name,name]; arguments []; default message [name]]; default message [不能为null]]
可以看到,当检查不通过时,将出现org.springframework.validation.BindException异常!
在ServiceCode中添加新的枚举值:
- * 错误:请求参数格式有误
- */
- ERR_BAD_REQUEST(400),
在GlobalExceptionHandler中添加处理BindException异常的代码:
- @ExceptionHandler
- public JsonResult handleBindException(BindException e) {
- String message = "请求参数格式错误!";
- return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, message);
- }
所有检查注解都可以配置检查不通过后的提示文本,例如:
@NotNull(message = "必须提交相册名称")
在处理异常时,应该将此处配置的文本响应到客户端去,可以通过异常对象获取以上文本!
由于客户端提交的若干个请求参数可能有多种错误,则异常对象中可能封装了多个错误信息!如果需要显示所有错误,应该先获取全部信息,然后将这些错误信息组织起来,并响应到客户端去!
所以,处理异常的代码可以调整为:
- @ExceptionHandler
- public JsonResult handleBindException(BindException e) {
- String delimiter = ",";
- String prefix = "添加相册失败,";
- String suffix = "!";
- StringJoiner stringJoiner = new StringJoiner(delimiter, prefix, suffix);
- List<FieldError> fieldErrors = e.getFieldErrors();
- for (FieldError fieldError : fieldErrors) {
- String defaultMessage = fieldError.getDefaultMessage();
- stringJoiner.add(defaultMessage);
- }
- return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringJoiner.toString());
- }
Validation框架有快速失败的机制,默认是未开启的,当客户端提交的请求参数有多种错误时,会进行全部的检查,发现所有错误!如果开启了快速失败,当检查出第1个错误时,就会停止检查!
配置快速失败,需要创建Valiator类型的对象,通过此对象进行配置,并且,此对象必须被保存在Spring容器中,框架会自动应用它!
当需要创建某个对象并使它保存在Spring容器中,可以在配置类中添加@Bean方法,此方法返回相关对象,在启动项目时,Spring框架会自动调用此方法并将返回保存在Spring容器中。
在项目的根包下创建config.ValidationConfiguration配置类,在此配置类中通过@Bean方法返回Validator对象,并在返回之前将此对象配置为快速失败的:
- import lombok.extern.slf4j.Slf4j;
- import org.hibernate.validator.HibernateValidator;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import javax.validation.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对象
- }
-
- }
当配置了快速失败后,无论请求参数有多少种错误,都会在发现第1个错误后停止检查,所以,处理异常时,只需要直接获取错误对象即可,不必获取所有错误对象!即:
- @ExceptionHandler
- public JsonResult handleBindException(BindException e) {
- StringBuilder stringBuilder = new StringBuilder();
- String prefix = "添加相册失败,";
- String suffix = "!";
- String defaultMessage = e.getFieldError().getDefaultMessage();
- stringBuilder.append(prefix).append(defaultMessage).append(suffix);
- return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringBuilder.toString());
- }
如果某些请求的参数较少,或各参数并不相关,则不会将它们封装在一起,例如:
- // http://localhost:9080/brand/delete
- @PostMapping("/delete")
- public void delete(Long id) {
- }
当需要检查这类参数时,首先,需要在当前类上添加@Validated注解,例如:
- @RestController
- @RequestMapping("/brand")
- @Validated // 新添加的注解
- public class BrandController {
-
- // 省略其它代码
然后,在请求参数上添加检查注解,例如:
- // http://localhost:9080/brand/delete
- @PostMapping("/delete")
- // ↓ 新添加的注解
- public void delete(@Range(min = 1, max = 996) @RequestParam Long id) {
- }
**提示:**以上@RequestParam在此处并无实际意义,但是,不添加此注解的话,在线API文档的调试界面中不会出现此参数的输入框,所以暂时添加上此注解,后续将删除!
完成后,重启项目,在API文档中调整,如果提交的id参数值不在[1, 996]范围内,将出现500错误(注意:不要处理RuntimeException),则控制台会提示错误:
javax.validation.ConstraintViolationException: delete.id: 需要在1和996之间
则应该在全局异常处理器添加对以上异常的处理:
- @ExceptionHandler
- public JsonResult handleConstraintViolationException(ConstraintViolationException e) {
- Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
- String delimiter = ",";
- StringJoiner stringJoiner = new StringJoiner(delimiter);
- for (ConstraintViolation<?> constraintViolation : constraintViolations) {
- stringJoiner.add(constraintViolation.getMessage());
- }
- return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringJoiner.toString());
- }
个人主页:居然天上楼
感谢你这么可爱帅气还这么热爱学习~~
人生海海,山山而川
你的点赞👍 收藏⭐ 留言📝 加关注✅
是对我最大的支持与鞭策
