前言

在我们进行业务开发有一部分很重要的工作的进行数据验证,由于业务的一致性要求,我们往往需要对某些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
}

会得到以下返回Snipaste_2024-01-28_21-42-57
消息中我们可以看到数据确实没有进到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());
    }
}

经过这个配置类返回的结果
Snipaste_2024-01-28_21-59-14
可以看到已经成为自定义的返回值了,这样前端老哥也不会瞬间爆炸了。

解析

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