HttpMessageConverter是Spring的一个重要接口,它负责将请求信息转换为一个对象,将对象输出为响应信息。
DispatcherServlet默认已经安装了RequestMappingHandlerAdapter作为HandlerAdapter的组件实现类,HttpMessageConverter即由RequestMappingHandlerAdapter使用,将请求信息转换为对象,或将对象转换为响应信息。
HttpMessageConverter接口定义了以下几个方法。
① Boolean canRead(Class<?> clazz,MediaType mediaType):
指定转换器可以读取的媒体类型(如text/html、application/json等),MIME媒体类型在RFC2616中定义,详细可以参考:http://www.w3school.com.cn/media/media_mimeref.asp 。
② Boolean canWrite(Class<?> clazz,MediaType mediaType):
指定转换器可以将clazz类型的对象写道响应流中,响应流支持的媒体类型在mediaType中定义。
③ List<MediaType> getSupportedMediaTypes():
该转换器支持的媒体类型。
④ T read(Class<? extends T> clazz,HttpInputMessage inputMessage):
将请求信息流转换为T类型的对象。
⑤ void write(T t,MediaType contentType,HttpOutputMessage outputMessage):
将T类型的对象写到响应流中,同时指定响应的媒体类型为contentType。
1 HttpMessageConverter<T>的实现类
Spring为HttpMessageConverter提供了众多的实现类,他们组成了一个功能强大用途广泛的HttpMessageConverter家族:
RequestMappingHandlerAdapter默认已经装配了一下HttpMessageConverter:
[1] StringHttpMessageConverter。
[2] ByteArrayHttpMessageConverter。
[3] SourceHttpMessageConverter。
[4] AllEncompassingFormHttpMessageConverter。
如果需要装配其他类型的HttpMessageConverter,则可以在Spring的web容器上下文中自定义一个RequestMappingHandlerAdapter:
<!-- 定义一个RequestMappingHandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" p:messageConverters-ref="messageConverters"/>
<!-- HttpMessageConverter列表 -->
<util:list id="messageConverters">
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter"/>
</util:list>
如果在SpringWeb容器中显示定义了一个RequestMappingHandlerAdapter,则SpringMVC将使用它覆盖默认的RequestMappingHandlerAdapter。
2 使用HttpMessageConverter
如何使用HttpMessageConverter将请求信息转换并绑定到处理方法的参数中呢?SpringMVC提供了两种途径
[1] 使用@RequestBody/@ResponseBody对方法进行标注。
[2] 使用HttpEntity作为处理方法的参数或返回值。
@Controller
@RequestMapping("/user")
public class UserController{
@RequestMapping(value = "/getUser")
public void getUser(@RequestBody String requestBody){
System.out.println(requestBody);
}
@ResponseBody
@RequestMapping(value = "/getUserList")
public List<Object> getUserList(){
return Lists.newArrayList();
}
}
RestTemplate是Spring的模板类,在哭护短程序中可使用该类调用Web服务器端的服务,它支持REST风格的URL。此外,它像RequestMappingHandlerAdapter一样拥有一张HttpMessageConverter的注册表,RestTemplate默认已经注册了一下HttpMessageConverter:
[1] ByteArrayHttpMessageConverter。
[2] StringHttpMessageConverter。
[3] ResourceHttpMessageConverter。
[4] SourceHttpMessageConverter。
[5] AllEncompassingFormHttpMessageConverter。
所以,在默认情况下,RestTemplate就可以利用这些HttpMessageConverter对响应数据进行相应的转换处理。可通过RestTemplate的setMessageConverters(List<HttpMessage-Converter<?>> messageConverters)方法手工注册HttpMessageConverter。
和@RequestBody/@ResponseBody类似,HttpEntity不但可以访问请求和响应报文体的数据,还可以访问请求和响应报文头的数据。SpringMVC根据HttpEntity的泛型类型查找对应的HttpMessageConverter。
@RequestMapping(value = "/query")
public void query(HttpEntity<String> httpEntity){
System.out.println(httpEntity);
}
@RequestMapping(value = "/image")
public ResponseEntity<byte[]> image() throws IOException {
Resource resource = new ClassPathResource("/image.jpg");
byte[] file = FileCopyUtils.copyToByteArray(resource.getInputStream());
return new ResponseEntity<byte[]>(file, HttpStatus.OK);
}
通过上面两个方法可以得出以下几条结论:
① 当控制器处理方法使用@RequestBody/@ResponseBody或HttpEntity/ResponseEntity时,Spring首先根据请求头或响应头的Accept属性选择匹配的HttpMessageConverter,然后根据参数类型或反省类型的过滤得到匹配的HttpMessageConverter,如果找不到可用的HttpMessageConverter则报错。
② 当控制器处理方法使用@RequestBody/@ResponseBody或HttpEntity/ResponseEntity时,Spring首先根据请求头或响应头的Accept属性选择匹配的HttpMessageConverter,然后根据参数类型或反省类型的过滤得到匹配的HttpMessageConverter,如果找不到可用的HttpMessageConverter则报错。
③ @RequestBody和@ResponseBody不需要成对出现。如果方法参数使用了@RequestBody,则SpringMVC选择匹配的HttpMessageConverter将请求消息转换并绑定到该参数中。如果处理方法标注了@ResponseBody,则SpringMVC选择匹配的HttpMessageConverter将方法返回值转换并输出响应消息。
④ HttpEntity/ResponseEntity的功能和@RequestBody/@ResponseBody相似。
3 处理XML和JSON
SpringMVC提供了几个处理XML和JSON格式的请求/响应消息的HttpMessageConverter。
[1] MarshallingHttpMessageConverter:处理XML格式的请求或响应消息。
[2]Jaxb2RootElementHttpMessageConverter:同上,底层使用JAXB。
[3] MappingJackson2HttpMessageConverter:处理JSON格式的请求或响应消息。
因此,只要在Spring Web容器中为RequestMappingHandlerAdapter装配好响应的处理XML和JSON格式的请求/响应消息的HttpMessageConverter,并在交互中通过请求的Accept指定MIME类型,SpringMVC就可使服务器端的处理方法和客户端透明的通过XML或JSON格式的消息进行通信,开发者几乎无需关心通信层数据格式的问题,可以将精力集中到业务层的处理上。单就这一点而言,其他MVC框架就无法和SpringMVC相比。
感觉这个特性虽然很强大,但是还没遇到过类似需要的应用场景,所以demo就不写啦。