Spring参数校验及通用异常信息返回
技术分享|2020-10-21|最后更新: 2023-9-4
type
status
date
slug
summary
tags
category
icon
password
order
 

前言

用注解@Validated、@Valid进行参数验证,相对于以前常用的if等条件,会显得简练很多,而且显得更加优雅。
然后是他俩的区别
@Validated:用在方法入参上无法单独提供嵌套验证功能,不能用在成员属性(字段)上,也无法提示框架进行嵌套验证,能配合嵌套验证注解@Valid进行嵌套验证。
@Valid:用在方法入参上无法单独提供嵌套验证功能,能够用在成员属性(字段)上,提示验证框架进行嵌套验证,能配合嵌套验证注解@Valid进行嵌套验证。
安装Maven依赖

常用的验证注解

全局异常捕获

ControllerAdvice用于捕获全局的控制器抛出的异常,这里只列出了验证相关的异常,其他Exception或者自定义的异常,都可以在这里捕获。

如何使用

比如新建这样一个类,给对应的字段添加注解以及设置message参数,如果不设置message,会使用默认的错误消息
如果验证不符合会自动抛出异常,由上面的exceptionHandler进行捕获处理。
针对方法的普通变量参数进行验证时,@Validated需要加在控制器上,然后变量前加验证注解
这个如果自动抛出异常的话时ConstraintViolationException
用Validated或Valid注解,验证一个实体类,也就是接收json数据,这个需要将注解标注于变量前面
这个如果自动抛出异常的话时MethodArgumentNotValidException

嵌套校验

对象的嵌套校验,需要在嵌套的字段上添加@Valid注解,否则验证时会略过字段props所属类Item里字段的验证规则

分组验证

Validation的分组验证,比如添加/编辑数据时,添加是不需要验证id的,而编辑的话id是必须的,还有可能这个类被不同控制器,方法使用时需要的参数不同,这时可以指定其groups参数指定要验证的规则。

数据传递到spring中的执行过程

前端通过HTTP协议将数据传递到Spring,Spring通过HttpMessageConverter类将流数据转换成Map类型,然后通过ModelAttributeMethodProcessor类对参数进行绑定到方法对象中,并对带有@Valid或@Validated注解的参数进行参数校验,对参数进行处理和校验的方法为ModelAttributeMethodProcessor.resolveArgument(…),通过查看源码,当BindingResult中存在错误信息时,会抛出BindException异常,BindException实现了BindingResult接口(BindResult是绑定结果的通用接口, BindResult继承于Errors接口),所以该异常类拥有BindingResult所有的相关信息,因此我们可以通过捕获该异常类,对其错误结果进行分析和处理。这样,我们对是Content-Typeapplication/x-www-form-urlencoded的请求(也就是表单),的参数校验的异常处理就解决了。
对于不同的传输数据的格式spring采用不同的HttpMessageConverter(http参数转换器)来进行处理,比如JasksonHttpMessageConverter,或者使用fastjson的话,可以自定义FastJsonHttpMessageConverter

HttpMessageConverter简介

HTTP 请求和响应的传输是字节流,意味着浏览器和服务器通过字节流进行通信。但是使用Spring MVC的Controller 类中的方法都是返回String类型或其他Java对象,如何将对象转换成字节流进行传输?这时就需要一个消息转化器。
在报文到达Spring MVC和从Spring MVC出去,都存在一个字节流到Java对象的转换问题。在Spring MVC中,它是由HttpMessageConverter来处理的。
当请求报文来到java中,它会被封装成为一个ServletInputStream的输入流,供我们读取报文。响应报文则是通过一个ServletOutputStream的输出流,来输出响应报文。
针对不同的数据格式,Spring MVC会采用不同的消息转换器进行处理,当使用json作为传输格式时,Spring MVC会采用MappingJacksonHttpMessageConverter消息转换器, 而且底层在对参数进行校验错误时,抛出的是MethodArgumentNotValidException异常,因此我们需要对BindException和MethodArgumentNotValidException进行统一异常管理,最终代码演示如上所示。
优雅的拷贝不同层的对象(VO,DO等)git 修改之前记录的作者和邮箱