java参数校验方式,利用@Valid注解对其参数错误异

2019-10-14 15:17栏目:编程

在我们使用springboot作为微服务框架进行敏捷开发的时候,为了保证传递数据的安全性,需要对传递的数据进行校验,但是在以往的开发中,开发人员花费大量的时间在繁琐的if else 等判断语句来对参数进行校验,这种方式不但降低了我们的开发速度,而且写出来的代码中带有很多冗余代码,使得编写的代码不够优雅,为了将参数的验证逻辑和代码的业务逻辑进行解耦,Java给我们提供了@Valid注解,用来帮助我们进行参数的校验,实现了将业务逻辑和参数校验逻辑在一定程度上的解耦,增加了代码的简洁性和可读性。springboot中自带了spring validation参数校验框架,其使用上和@valid差不多,在这里就不累述了,本文主要讲解@valid的使用对其参数校验失败后的错误一样的统一处理。
首先,简介对微服务开发中异常的统一处理,spring中的@RestControllerAdvice注解可以获取带有@controller注解类的异常,通过@ExceptionHandler(MyException.class)注解来共同完成对异常进行处理。示例如下:
通过注解@RestControllerAdvice和注解@ExceptionHandler的联合使用来实现对异常的统一处理,然后在前端以友好的方式显示。
使用@Valid注解的示例如下:
java参数校验框架
@Valid注解确实将我们原来的参数校验的问题进行了简化,但是,如果我们有多个handler需要处理,那我们岂不是每次都要写这样的冗余代码。通过查看@valid的实现机制(这里就不描述了),当参数校验失败的时候,会抛出MethodArgumentNotValidException异常(当用{@code @Valid}注释的参数在验证失败时,将引发该异常):
java批量参数校验
按照我们的预想,我们只需要在原来定义的统一异常处理类中,捕获MethodArgumentNotValidException异常,然后对其错误信息进行分析和处理即可实现通用,代码如下:
Java数据校验方式
但是经过测试,会发现对该异常进行捕获然后处理是没有效果的,这可能是我,也是大家遇到的问题之一,经过对@Valid的执行过程的源码进行分析,数据传递到spring中的执行过程大致为:前端通过http协议将数据传递到spring,spring通过HttpMessageConverter类将流数据转换成Map类型,然后通过ModelAttributeMethodProcessor类对参数进行绑定到方法对象中,并对带有@Valid或@Validated注解的参数进行参数校验,对参数进行处理和校验的方法为ModelAttributeMethodProcessor.resolveArgument(...),部分源代码如下所示:

通过查看源码,当BindingResult中存在错误信息时,会抛出BindException异常,查看BindException源代码如下:
我们发现BindException实现了BindingResult接口(BindResult是绑定结果的通用接口, BindResult继承于Errors接口),所以该异常类拥有BindingResult所有的相关信息,因此我们可以通过捕获该异常类,对其错误结果进行分析和处理。代码如下:
这样,我们对是content-type类型为form(表单)类型的请求的参数校验的异常处理就解决了,对于MethodArgumentNotValidException异常不起作用的原因主要是因为跟请求发起的数据格式(content-type)有关系,对于不同的传输数据的格式spring采用不同的HttpMessageConverter(http参数转换器)来进行处理.以下是对HttpMessageConverter进行简介:
HTTP 请求和响应的传输是字节流,意味着浏览器和服务器通过字节流进行通信。但是,使用 Spring,controller 类中的方法返回纯 String 类型或其他 Java 内建对象。如何将对象转换成字节流进行传输?
在报文到达SpringMVC和从SpringMVC出去,都存在一个字节流到java对象的转换问题。在SpringMVC中,它是由HttpMessageConverter来处理的。
当请求报文来到java中,它会被封装成为一个ServletInputStream的输入流,供我们读取报文。响应报文则是通过一个ServletOutputStream的输出流,来输出响应报文。http请求与相应的处理过程如下:
针对不同的数据格式,springmvc会采用不同的消息转换器进行处理,以下是springmvc的内置消息转换器:
由此我们可以看出,当使用json作为传输格式时,springmvc会采用MappingJacksonHttpMessageConverter消息转换器,?而且底层在对参数进行校验错误时,抛出的是MethodArgumentNotValidException异常,因此我们需要对BindException和MethodArgumentNotValidException进行统一异常管理,最终代码演示如下所示:
自定义注解校验参数
这样就完美解决了我们对参数校验异常的统一处理。在这里我仅仅是针对参数校验的异常进行了统一处理,也就是返回给前端的响应码是400(参数格式错误),对于自定义异常或者其他的异常都可以采用这种方式来对异常进行统一处理,如果大家遇到什么问题,可以在通过留言板块,大家一起解决,共同进步。

本文来自网络,不代表山斋月平台立场,转载请注明出处: https://www.shanzhaiyue.top