【SpringMVC】浅谈Convert/Format机制与Ht
简介
Spring3引入了较Spring2的PropertyEditor
更加强大、通用的Convert/Format SPI
,Convert SPI
可以实现任意类型的转换;Format SPI
支持国际化,并在前者的基础上实现了String与任意类型的转换。这两类SPI属于spring-core
,被整个spring-framework
共享,是一种通用的类型转换器。
HttpMessageConverter
虽然功能上也表现为HttpMessage
与任意类型的转换,但其接口和Convert SPI
并没有继承关系。HttpMessageConverter
属于spring-web
。HttpMessage
是SpringMVC对Servlet
规范中HttpServletRequest
和HttpServletResponse
的包装,因此接受请求时需要把HttpMessage
转换成用户需要的数据,在生成响应时需要把用户生成的数据转换成HttpMessage
。如果用户在XML的<mvc:message-converters>
中没有指定register-defaults=false
,SpringMVC默认至少会注册一些自带的HttpMessageConvertor
(从先后顺序排列分别为ByteArrayHttpMessageConverter
、StringHttpMessageConverter
、ResourceHttpMessageConverter
、SourceHttpMessageConverter
、AllEncompassingFormHttpMessageConverter
)。
如果后端服务使用Restful API
的形式,一般使用JSON作为前后端通信的格式规范,由于SpringMVC自带MappingJackson2HttpMessageConverter
,在依赖中引入jackson后,容器会把该转换器自动注册到converter链的末尾。
两者的分工
Http请求中有几个常用的部分可以用来传递业务信息,以常见的Get
和Post
方法为例。
是否可用 | URL | Parameter | Header | Body |
---|---|---|---|---|
Get | 是 | 是 | 是 | 否 |
Post | 是 | 否 | 是 | 是 |
那么上述的4个部分都是用HttpMessageConverter
来进行类型转换的吗?显然不是,HttpMessageConverter
和Convert SPI
各有分工,** HttpMessageConverte
只负责解析Http包的Body体部分1,其余部分都交由相关的Convert SPI
处理2。**
是否支持 | URL | Parameter | Header | Body |
---|---|---|---|---|
HttpMessageConverter | 否 | 否 | 否 | 是 |
Convert SPI | 是 | 是 | 是 | 否 |
除上表所示之外,SpringMVC还有一些需要Convert SPI
的场景,如读取Cookie值的@CookieValue
(本质是Header),解析矩阵URL的@MatrixVariable
(本质是URL),读取本地会话的@SessionAttribute
,解析SpEL的@Value
。
Convert SPI类型转换实例
在SpringMVC中,单次请求的整个处理流程中有哪些地方需要类型转换?以Delete /ajax/shop/12345/blacklist?id=1
请求为例,后端对应的处理方法如下。
@DeleteMapping("/ajax/{shopId}/blacklist") @ResponseBody
public boolean deleteBlackItem(@RequestParam Integer id, @PathVariable Integer shopId) {
//省略
return true;
}
由于请求的URL为String类型,而接受的参数id
和shopId
都是Integer类型,因此Spring会自动查找合适的Converter
(具体实现为StringToNumberConverterFactory
的工厂产品)把字符串“12345”
和“1”
转化为数字12345
和1
,分别赋值给shopId
和id
。处理完业务逻辑后,方法返回true
,但需要将其格式化成String类型的“true”
才能输出到响应的Body中,这时Spring就会使用StringToBooleanConverter
来完成转换。如下图所示,除了上述常见的数据绑定和格式化显示功能,数据验证功能(JSR-303
)基于数据绑定也间接利用了这两套SPI。
结语
在SpringMVC处理请求时,HttpMessageConverter
和Convert SPI
分别用来反序列化请求的Body和非Body部分,即HttpMessageConverter
是一套小型、独立、额外为用户提供的专门的Body体的类型转换器;而Convert SPI
则与PropertyEditor
类似,可以处理更为通用的类型转换。