HttpMessageConverter<T>是Spring3.0新添加的一个重要接口,它负责将请求信息转换为一个对象(类型为T),将对象(类型为T)输出为响应信息。
DispatcherServlet默认已安装了AnnotationMethodHandlerAdapter作为HandlerAdapter的组件实现类,HttpMessageConverter即由AnnotationMethodHandlerAdapter使用,将请求信息转换为对象,或将对象转换为相应信息。(处理器适配器使用HttpMessageConverter将请求信息转换为对象,或将对象转换为相应信息)
HttpMessageConverter<T>接口定义以下几个方法:
1.Boolean canRead(Class<?> clazz,MediaType mediaType):指定转换器可以读取的对象类型,即转换器可将请求信息转换为clazz类型的对象,同时指定支持MIME类型(text/html,applaiction/json等),MIME媒体类型在RFC2616中定义
2.Boolean canWrite(Class<?> clazz,MediaType mediaType):指定转换器可以将clazz类型的对象写到响应流中,响应流支持的媒体类型在MediaType中定义。
3.LIst<MediaType> getSupportMediaTypes():该转换器支持的媒体类型。
4.T read(Class<? extends T> clazz,HttpInputMessage inputMessage):将请求信息流转换为T类型的对象。
5.void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage):将T类型的对象写到响应流中,同时指定相应的媒体类型为contentType。AnnotationMethodHandlerAdapter默认已经注册了以下HttpMessageConverter:
public AnnotationMethodHandlerAdapter() { // no restriction of HTTP methods by default super(false); // See SPR-7316 StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); stringHttpMessageConverter.setWriteAcceptCharset(false); this.messageConverters = new HttpMessageConverter<?>[] { new ByteArrayHttpMessageConverter(), stringHttpMessageConverter, new SourceHttpMessageConverter<Source>(), new org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter() }; }
如果需要装配其他类型的HttpMessageConverter,可以在Spring的web容器(Spring子容器)上下文中自行定义一个AnnotationMethodHandlerAdapter,注册若干HttpMessageConverter
<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <util:list id="beanList"> <ref bean="stringHttpMessageConverter" /> <ref bean="jsonHttpMessageConverter" /> <ref bean="marshallingHttpMessageConverter" /> </util:list> </property> </bean> <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter" /> <bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /> <bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"> <property name="marshaller" ref="castorMarshaller" /> <property name="unmarshaller" ref="castorMarshaller" /> </bean> <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
如果在Spring web容器中显示定义了一个AnnotationMethodHandlerAdapter,则Spring MVC将使用它覆盖默认的AnnotationMethodHandlerAdapter
如何使用 HttpMessageConverter<T> 将请求信息转换并绑定到处理方法的入参中或将响应结果转为对应类型的响应信息,Spring MVC提供了两种途径:
1. 使用@RequestBody/@ResponseBody 对处理方法进行标注
2. 使用HttpEntity<T>/ResponseEntity<T> 作为处理方法的入参或返回值
示例1:
@RequestMapping(value = "/handle41") public String handle41(@RequestBody String requestBody){ //将请求-报文体-转换为字符串绑定到requestBody入参中 } @ResponseBody @RequestMapping("/handle42") public byte[] handle42(){ // }
handle41()处Spring MVC将根据requestBody的类型查找匹配的HttpMessageConverter,由于StringHttpMessageConverter的泛型类型对应String,所以StringHttpMessageConverter将会被Spring MVC选中,用它将请求体信息进行转换并且将结果绑定到requestBody入参上!
handle42()处,由于方法的返回值类型为byte[],所以Spring MVC根据类型匹配的查找规则将使用ByteArrayHttpMessageConverter对返回值进行处理。
和@RequestBody/@ResponseBody类似,HttpEntity<?>不但可以访问请求和响应报文头的数据,还可以访问请求和响应报文体的数据(也就是HttpEntity中不但有头数据还有体数据),Spring MVC根据HttpEntity的泛型类型查找对应的HttpMessageConverter。
在接收到一个http请求的时候,处理方法如何知道请求消息的格式,在处理完成之后又根据什么确定响应消息的格式?答案很简单,根据请求消息头的"Content-Type"及Accept属性确定。
例如:
@ResponseBody @RequestMapping( "/getEmployeesForJson") public Collection<Employee> getEmployees() { return employeeDao .getAll(); }
请求时的目标类型:
方法的实际返回值为:Employee 的集合
SpringMVC 发现需要返回的是 JSON 类型,但实际返回的是 Employee 的集合。此时 @ResponseBody 查找有没有把结果转为 JSON
的 HttpMessageConverter,如果有,则调用其对应的方法,把结果转为 JSON 类型。
结论:
1.只有当处理器方法使用到 @RequestBody/@ResponseBody 或HttpEntity<T>/ResponseEntity<T> 时,SpringMVC才使用注册的HttpMessageConverter 对请求响应消息进行处理。
2.当控制器处理方法使用到 @RequestBody/@ResponseBody 或HttpEntity<T>/ResponseEntity<T> 时,Spring 首先根据请求头或响应头的 Accept 属性选择匹配的 HttpMessageConverter, 然后根据参数类型或泛型类型的过滤得到匹配的 HttpMessageConverter, 若找不到可用的 HttpMessageConverter 将报错
[email protected] 和 @ResponseBody 不需要成对出现。如果方法入参使用到了@RequestBody,SpringMVC将会选择匹配的HttpMessageConverter 将请求信息转换并绑定到该入参中。如果处理方法标注了@ResponseBody,SpringMVC选择匹配的HttpMessageConverter 将方法返回值转换并输出响应消息。