前言
在我们进行业务开发有一部分很重要的工作的进行数据验证,由于业务的一致性要求,我们往往需要对某些BO或者VO的一些字段进行如同非空,非0校验。这些工作如果要我们手写则太麻烦且太不优雅了。而实际上springboot自身是已经实现一套数据检验方法,我们是可以做到开箱即用的。
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
根据网上的资料,springboot的validation模块本身是集成在标准starter里面的,但是应该是2.X的版本开始被切割出来了,反正我现在用的2.7.12是已经不包含这个模块了。如果要使用的话需要引入这个pom。
使用
其实使用很简单,我们只需要在对应的bean部分增加@NotNull之类的检验标签即可
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层代码省略)
{
"age":10,
"score":100
}
会得到以下返回
消息中我们可以看到数据确实没有进到controller的处理,但是如果我们这样返回给前端的话估计前端要原地爆炸。因此我们得加入我们的自定义处理方法来处理。
直接来看代码
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());
}
}
经过这个配置类返回的结果
可以看到已经成为自定义的返回值了,这样前端老哥也不会瞬间爆炸了。
解析
在上面我们可以看到,使用validation模块进行数据话校验的话,其校验动作是发生在controller运行内部逻辑之前的,因此我们要用@ControllerAdvice注解家族来对controller进行增强。这个注解可以在controller运行之前的模块执行我们想要的逻辑,在这里我们直接捕获了MethodArgumentNotValidException这个异常,并给前端返回对应的处理模块。也正是由于这个特性,其实validation这个方法更适合用于对全局适用的一些数据校验方法。如果你的校验方法是有一些独特的业务操作的话就不适合放在validation进行控制了。