Spring 接口校验 统一 处理 BindingResult

Scroll Down

接口开发有一个铁律

不要相信外部的任何入参 不要相信外部的任何入参 不要相信外部的任何入参

所以,接口开发必然少不了接口校验。

一般接口简单参数校验如下,该不会还在使用 if ==null 吧!!!

@PostMapping("/auth/jwt/token")
public ReturnBo login(@RequestBody @Validated  LoginReq req, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return ReturnBo.creErrorResult(bindingResult);
    }
    // 处理
}

以上,只是对单个接口校验,如果项目中存在n个接口,则需要重复n次,效率太低;

不过Spring的强大可不是吹出来的,AOP即可搞定简单通用处理(Spring的切面真的非常非常好用),代码如下

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@RestControllerAdvice
public class BadRequestExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        ReturnBo response = ReturnBo.creErrorResult(ex.getBindingResult());
        return new ResponseEntity<>(response, headers, status);
    }
}

至此解放Controller中的BindingResult,只需要简单加上@Validated注解即可

@PostMapping("/api/auth/jwt/token")
public ReturnBo login(@RequestBody @Validated  LoginReq req) {
    // 处理
}

对比之前

@PostMapping("/auth/jwt/token")
public ReturnBo login(@RequestBody @Validated  LoginReq req, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return ReturnBo.creErrorResult(bindingResult);
    }
    // 处理
}

附上 ReturnBo.java

import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import java.io.Serializable;
import java.util.List;
import lombok.Data;

@Data
public class ReturnBo implements Serializable {
    private static final long serialVersionUID = 2454950041375201365L;
    private String resCode;
    private String msg;
    private Object obj;

    public static ReturnBo creErrorResult(BindingResult result) {
        ReturnBo returnBo = new ReturnBo();
        returnBo.setResCode(AppCode.ERROR.getResCode());
        returnBo.setMsg(processErrorMsg(result));
        return returnBo;
    }

    private static String processErrorMsg(BindingResult result) {
        List<FieldError> list = result.getFieldErrors();
        StringBuilder msg = new StringBuilder();
        for (FieldError fieldError : list) {
            msg.append("[");
            msg.append(fieldError.getField());
            msg.append(":");
            msg.append(fieldError.getDefaultMessage());
            msg.append("]");
        }
        return msg.toString();
    }
}

以上 processErrorMsg 会暴露字段名 去除fieldError.getField()即可