前言
目录
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实现异常捕获并更改格式。
public class GlobalExceptionHandler { private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 请求参数校验未通过 */ 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(); }