spring-boot-validator参数校验系列(4)--------自定义参数校验异常

前言

目录

spring-boot-validator参数校验系列(1)--------基本参数校验

spring-boot-validator参数校验系列(2)--------分组校验

spring-boot-validator参数校验系列(3)--------自定义校验注解

spring-boot-validator参数校验系列(4)--------自定义参数校验异常

一、为什么要自定义参数校验异常?

为了统一返回格式,方便前端处理并给出提示!

二、如何实现?

一般的web开发,我们都会采取统一得返回格式,让接口调用者能有效的处理。比如下面这种。

{
    "data": {
       //具体的返回内容
    },
    "rtn_flag": 9999,  //状态码
    "rtn_msg": "操作成功" //状态消息
}

如果不对参数校验进行捕获,会出现什么吗格式呢?

{
    "timestamp": "2021-09-13T09:30:28.862+00:00",
    "status": 400,
    "error": "Bad Request",
    "trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void com.tab343.myspringboot.validation.MyValidationController.custom(com.tab343.myspringboot.validation.MyPerson) with 3 errors: [Field error in object 'myPerson' on field 'mobile': rejected value [null]; codes [NotBlank.myPerson.mobile,NotBlank.mobile,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [myPerson.mobile,mobile]; arguments []; default message [mobile]]; default message [不能为空]] [Field error in object 'myPerson' on field 'sex': rejected value [3]; codes [Fixed.myPerson.sex,Fixed.sex,Fixed.java.lang.Integer,Fixed]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [myPerson.sex,sex]; arguments []; default message [sex],[Ljava.lang.String;@66923162]; default message [请输入合法值!]] [Field error in object 'myPerson' on field 'email': rejected value [null]; codes [NotBlank.myPerson.email,NotBlank.email,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [myPerson.email,email]; arguments []; default message [email]]; default message [不能为空]] \r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:141)\r\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1064)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:681)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1726)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.lang.Thread.run(Thread.java:748)\r\n",
    "message": "Validation failed for object='myPerson'. Error count: 3",
    "errors": [
        {
            "codes": [
                "Fixed.myPerson.sex",
                "Fixed.sex",
                "Fixed.java.lang.Integer",
                "Fixed"
            ],
            "arguments": [
                {
                    "codes": [
                        "myPerson.sex",
                        "sex"
                    ],
                    "arguments": null,
                    "defaultMessage": "sex",
                    "code": "sex"
                },
                [
                    "0",
                    "1"
                ]
            ],
            "defaultMessage": "请输入合法值!",
            "objectName": "myPerson",
            "field": "sex",
            "rejectedValue": 3,
            "bindingFailure": false,
            "code": "Fixed"
        },
    ],
    "path": "/validation/custom"
}

可以看到错误输出还是很详细的,但是与之前的格式不符,如果是对接的话,还需要重新写一套解析方法。这里我们可以采用@RestControllerAdvice、@ControllerAdvice实现异常捕获并更改格式。

@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 请求参数校验未通过
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public AjaxResult methodArgumentNotValidException(BindException ex){
        FieldError fe = ex.getFieldError();
        return AjaxResult.error(fe.getField().concat(fe.getDefaultMessage()));
    }
}

(1)为什么是捕获MethodArgumentNotValidException异常呢?

这里我是直接根据报错输出的json来的。

(2)而如何获取注解中提示消息(即message = "请填写id!")呢?

可以我们可以参照MethodArgumentNotValidException类的toString()方法!可以看到,此方法获取错误后,在循环中拼接错误信息,然后形成我们刚看到的错误json。

    public String getMessage() {
        StringBuilder sb = (new StringBuilder("Validation failed for argument [")).append(this.parameter.getParameterIndex()).append("] in ").append(this.parameter.getExecutable().toGenericString());
        if (this.bindingResult.getErrorCount() > 1) {
            sb.append(" with ").append(this.bindingResult.getErrorCount()).append(" errors");
        }

        sb.append(": ");
        Iterator var2 = this.bindingResult.getAllErrors().iterator();

        while(var2.hasNext()) {
            ObjectError error = (ObjectError)var2.next();
            sb.append("[").append(error).append("] ");
        }

        return sb.toString();
    }
上一篇:spring-boot-validator参数校验系列(3)--------自定义校验注解


下一篇:spring-boot-validator参数校验系列(2)--------分组校验