Spring:深入分析SpringMVC之HttpMessageConverter类

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就不写啦。

猜你喜欢

转载自blog.csdn.net/yongqi_wang/article/details/87165241