前言

在我们进行业务开发有一部分很重要的工作的进行数据验证,由于业务的一致性要求,我们往往需要对某些BO或者VO的一些字段进行如同非空,非0校验。这些工作如果要我们手写则太麻烦且太不优雅了。而实际上springboot自身是已经实现一套数据检验方法,我们是可以做到开箱即用的。

依赖

  • 01
  • 02
  • 03
  • 04
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>

根据网上的资料,springboot的validation模块本身是集成在标准starter里面的,但是应该是2.X的版本开始被切割出来了,反正我现在用的2.7.12是已经不包含这个模块了。如果要使用的话需要引入这个pom。

使用

其实使用很简单,我们只需要在对应的bean部分增加@NotNull之类的检验标签即可

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
package com.buba.springcloud.pojo; import lombok.Data; import org.springframework.validation.annotation.Validated; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @Data @Validated public class Student { @NotNull private String name; @NotNull private String gender; private int age; private int score; }

然后我们简单的造一个数(controller层代码省略)

  • 01
  • 02
  • 03
  • 04
{ "age":10, "score":100 }

会得到以下返回Snipaste_2024-01-28_21-42-57

Snipaste_2024-01-28_21-42-57


消息中我们可以看到数据确实没有进到controller的处理,但是如果我们这样返回给前端的话估计前端要原地爆炸。因此我们得加入我们的自定义处理方法来处理。
直接来看代码

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
package com.study.springcloud.ExceptionHandler; import com.buba.springcloud.pojo.CommonResult; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; @Slf4j @RestControllerAdvice public class ControllerExceptionHandler extends Exception { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @ExceptionHandler(value = {MethodArgumentNotValidException.class}) public CommonResult exceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e) throws Exception { logger.error("Request URl : {}, Exception : {}",request.getRequestURI(),e); StringBuilder sb = new StringBuilder(); for(FieldError fe : e.getFieldErrors()){ sb.append(fe.getField()).append(" ").append(fe.getDefaultMessage()).append(" "); } // 如果定制了http状态码那么抛出异常 return new CommonResult(400,"error",sb.toString()); } }

经过这个配置类返回的结果
Snipaste_2024-01-28_21-59-14

Snipaste_2024-01-28_21-59-14


可以看到已经成为自定义的返回值了,这样前端老哥也不会瞬间爆炸了。

解析

在上面我们可以看到,使用validation模块进行数据话校验的话,其校验动作是发生在controller运行内部逻辑之前的,因此我们要用@ControllerAdvice注解家族来对controller进行增强。这个注解可以在controller运行之前的模块执行我们想要的逻辑,在这里我们直接捕获了MethodArgumentNotValidException这个异常,并给前端返回对应的处理模块。也正是由于这个特性,其实validation这个方法更适合用于对全局适用的一些数据校验方法。如果你的校验方法是有一些独特的业务操作的话就不适合放在validation进行控制了。