参数解析
说到参数解析,springmvc中处理参数的是HandlerMethodArgumentResolver接口
1 | public interface HandlerMethodArgumentResolver { |
其有一个抽象实现类AbstractNamedValueMethodArgumentResolver,有很多有用的子类
MapMethodProcessor
这个用来处理 Map/ModelMap 类型的参数,解析完成后返回 model。
PathVariableMethodArgumentResolver
这个用来处理使用了
@PathVariable
注解并且参数类型不为 Map 的参数,参数类型为 Map 则使用PathVariableMapMethodArgumentResolver
来处理。PathVariableMapMethodArgumentResolver
见上。
ErrorsMethodArgumentResolver
这个用来处理 Error 参数,例如我们做参数校验时的 BindingResult。
AbstractNamedValueMethodArgumentResolver
这个用来处理 key/value 类型的参数,如请求头参数、使用了
@PathVariable
注解的参数以及 Cookie 等。RequestHeaderMethodArgumentResolver
这个用来处理使用了
@RequestHeader
注解,并且参数类型不是 Map 的参数(参数类型是 Map 的使用RequestHeaderMapMethodArgumentResolver
)。RequestHeaderMapMethodArgumentResolver
见上。
RequestAttributeMethodArgumentResolver
这个用来处理使用了
@RequestAttribute
注解的参数。RequestParamMethodArgumentResolver
这个功能就比较广了。使用了
@RequestParam
注解的参数、文件上传的类型 MultipartFile、或者一些没有使用任何注解的基本类型(Long、Integer)以及 String 等,都使用该参数解析器处理。需要注意的是,如果@RequestParam
注解的参数类型是 Map,则该注解必须有 name 值,否则解析将由RequestParamMapMethodArgumentResolver
完成。RequestParamMapMethodArgumentResolver
见上。
AbstractCookieValueMethodArgumentResolver
这个是一个父类,处理使用了
@CookieValue
注解的参数。ServletCookieValueMethodArgumentResolver
这个处理使用了
@CookieValue
注解的参数。MatrixVariableMethodArgumentResolver
这个处理使用了
@MatrixVariable
注解并且参数类型不是 Map 的参数,如果参数类型是 Map,则使用MatrixVariableMapMethodArgumentResolver
来处理。MatrixVariableMapMethodArgumentResolver
见上。
SessionAttributeMethodArgumentResolver
这个用来处理使用了
@SessionAttribute
注解的参数。ExpressionValueMethodArgumentResolver
这个用来处理使用了
@Value
注解的参数。ServletResponseMethodArgumentResolver
这个用来处理 ServletResponse、OutputStream 以及 Writer 类型的参数。
ModelMethodProcessor
这个用来处理 Model 类型参数,并返回 model。
ModelAttributeMethodProcessor
这个用来处理使用了
@ModelAttribute
注解的参数。SessionStatusMethodArgumentResolver
这个用来处理 SessionStatus 类型的参数。
PrincipalMethodArgumentResolver
这个用来处理 Principal 类型参数
AbstractMessageConverterMethodArgumentResolver
这是一个父类,当使用 HttpMessageConverter 解析 requestbody 类型参数时,相关的处理类都会继承自它。
RequestPartMethodArgumentResolver
这个用来处理使用了
@RequestPart
注解、MultipartFile 以及 Part 类型的参数。RequestResponseBodyMethodProcessor
这个用来处理添加了
@RequestBody
注解的参数。HttpEntityMethodProcessor
这个用来处理 HttpEntity 和 RequestEntity 类型的参数。
ServletWebArgumentResolverAdapter
这个给父类提供 request。
UriComponentsBuilderMethodArgumentResolver
这个用来处理 UriComponentsBuilder 类型的参数。
ServletRequestMethodArgumentResolver
这个用来处理 WebRequest、ServletRequest、MultipartRequest、HttpSession、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId 类型的参数。
HandlerMethodArgumentResolverComposite
这个看名字就知道是一个组合解析器,它是一个代理,具体代理其他干活的那些参数解析器。
RedirectAttributesMethodArgumentResolver
这个用来处理 RedirectAttributes 类型的参数
这些解析器是在执行
1 | // Actually invoke the handler. |
执行对应的Controller方法前来进行参数解析时调用的org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
1 | if (this.argumentResolvers.supportsParameter(parameter)) { |
RequestResponseBodyMethodProcessor调用消息解析器
我之前只知道解析@RequestBody需要使用消息解析器HttpMessageConverter,但是没有深究是从哪调用的。突然看到消息解析我才知道原来是RequestResponseBodyMethodProcessor调用的。org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#resolveArgument来进行参数解析
遍历消息解析器找到可以进行解析该类型的消息解析器
1 | for (HttpMessageConverter<?> converter : this.messageConverters) { |
对于简单的参数会以简单的转换器进行转换,而这些简单的转换器是Spring MVC自身已经提供了的,但是如果是转换HTTP请求体,会调用HttpMessageConverter接口的方法对请求体的信息进行转换
1 | public interface HttpMessageConverter<T> { |
HttpMessageConverter接口是将HTTP请求体转换为对应的java对象,对于HTTP参数和其他内容需要使用参数转换规则
参数转换
Spring MVC中,是通过WebDataBinder机制来获取参数的,它的主要作用是解析HTTP请求的上下文,然后在控制器的调用之前转换参数并且提供验证的功能,为调用控制器方法做准备。处理器会从HTTP请求中读取数据,然后通过三种接口进行各类参数转换(Converter、Formatter、GenericConverter)。
Converter接口
Converter接口是一个普通的转换器
1 | public interface Converter<S, T> { |
可以将某个类型转换为另一个类型
Formatter接口
Formatter接口是一个格式化转换器,如将日期字符串格式化
1 | public interface Formatter<T> extends Printer<T>, Parser<T> { |
GenericConverter接口
GenericConverter接口是将HTTP参数转换为数组
1 | public interface GenericConverter { |
ConversionService接口
1 | public interface ConversionService { |
数据验证
Validator接口用于数据验证
1 | public interface Validator { |
WebDataBinder还可以进行验证,使用@InitBinder注解可以允许在进入控制器方法之前修改WebDataBinder机制,可以来设置验证器
通过WebDataBinder#setValidator来添加验证器