springMVC源码4:HttpMessageConverter<T>和ConversionService之间怎么关联

来源:互联网 发布:行星齿轮设计软件 编辑:程序博客网 时间:2024/04/29 07:25

1 spring数据绑定:http://jinnianshilongnian.iteye.com/blog/1723270

2 springMVC中,HttpMessageConverter<T>和ConversionService之间的区别:http://www.iteye.com/problems/98525

   ConversionService是属于spring core部分 所有spring管理的bean等等 都使用它进行类型转换,而它又需要注册一些converter 来完成类型转换。 这个可以看我博客 springmvc部分 
HttpMessageConverter 是对http请求/响应 数据进行转换的, 它可以使用ConversionService进行一些转换(HttpMessageConverter是否能转换 还需要根据如请求的contentType等决定)

3 官方文档:

    In a Spring MVC application, you may configure a custom ConversionService instance explicitly as an attribute of the annotation-driven element of 
the MVC namespace. This ConversionService will then be used anytime a type conversion is required during Controller model binding. If not configured 
explicitly, Spring MVC will automatically register default formatters and converters for common types such as numbers and dates.
翻译:
    在Spring MVC应用程序中,您可以将自定义ConversionService实例显式配置为MVC命名空间的注释驱动元素的属性。 随后在Controller模型绑定期间需要进行类型转换时,将使用此ConversionService。 如果没有明确配置,Spring MVC将自动注册默认格式化程序和转换器,用于常见类型,如数字和日期。

<mvc:annotation-driven/>
    With this one-line of configuration, default formatters for Numbers and Date types will be installed, including support for the @NumberFormat and
 @DateTimeFormat annotations. Full support for the Joda Time formatting library is also installed if Joda Time is present on the classpath.
To inject a ConversionService instance with custom formatters and converters registered, set the conversion-service attribute and then 
specify custom converters, formatters, or FormatterRegistrars as properties of the FormattingConversionServiceFactoryBean:

通过这种一行配置,将使用默认“数字和日期”的格式化方法,包括对@NumberFormat和@DateTimeFormat注释的支持。 如果Joda时间存在于类路径上,
则还将完全支持Joda Time格式化库。要注册自定义格式化程序和转换器的ConversionService实例,请设置conversion-service属性,然后将使用自定义converters,
formatters或FormatterRegistrars,作为FormattingConversionServiceFactoryBean的三个属性:

代码:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="        http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/mvc        http://www.springframework.org/schema/mvc/spring-mvc.xsd">    <mvc:annotation-driven conversion-service="conversionService"/>    <bean id="conversionService"          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">        <property name="converters">            <set>                <bean class="org.example.MyConverter"/>            </set>        </property>        <property name="formatters">            <set>                <bean class="org.example.MyFormatter"/>                <bean class="org.example.MyAnnotationFormatterFactory"/>            </set>        </property>        <property name="formatterRegistrars">            <set>                <bean class="org.example.MyFormatterRegistrar"/>            </set>        </property>    </bean></beans>


总结:
7.6.5 Configuring Formatting in Spring MVC
In a Spring MVC application, you may configure a custom ConversionService instance explicitly as an attribute of the annotation-driven element of the MVC namespace. This ConversionService will then be used anytime a type conversion is required during Controller model binding. If not configured explicitly, Spring MVC will automatically register default formatters and converters for common types such as numbers and dates.
在Spring MVC应用程序中,您可以将自定义ConversionService实例显式配置为MVC命名空间的注释驱动元素的属性。 随后在Controller模型绑定期间需要进行类型转换时,将使用此ConversionService。 如果没有明确配置,Spring MVC将自动注册默认格式化程序和转换器,用于常见类型,如数字和日期。

关键在这一句话: ConversionService实例显式配置为MVC命名空间的注释驱动元素的属性则使用ConversionService。
                              如果没有明确配置,Spring MVC将自动注册默认格式化程序和转换器,用于常见类型,如数字和日期。
Spring3引入了更加通用的类型转换系统,其定义了SPI接口(Converter等)和相应的运行时执行类型转换的API(ConversionService等):见下篇。
默认ConversionService的配置(使用的转换器是HttpMessageConverter,当然可以自定义HttpMessageConverter里的具体转换类),也可以用ConversionService实例显示配置代替原有的默认ConversionService。

-----------------------------------------------分割线---下面的不用看了-------------------------------------------------




4 HttpMessageConverter<T>和ConversionService之间怎么关联: http://starscream.iteye.com/blog/1072179 正确性存疑

对于requestBody或httpEntity中数据的类型转换 
Spring MVC中对于requestBody中发送的数据转换不是通过databind来实现,而是使用HttpMessageConverter来实现具体的类型转换。 

例如,之前提到的json格式的输入,在将json格式的输入转换为具体的model的过程中,spring mvc首先找出request header中的contenttype,再遍历当前所注册的所有的HttpMessageConverter子类, 根据子类中的canRead()方法来决定调用哪个具体的子类来实现对requestBody中的数据的解析。如果当前所注册的httpMessageConverter中都无法解析对应contexttype类型,则抛出HttpMediaTypeNotSupportedException (http 415错误)。 
那么需要如何注册自定义的messageConverter呢,很不幸,在spring 3.0.5中如果使用annotation-driven的配置方式的话,无法实现自定义的messageConverter的配置,必须老老实实的自己定义AnnotationMethodHandlerAdapter的bean定义,再设置其messageConverters以注册自定义的messageConverter。 
在3.1版本中,将增加annotation-driven对自定义的messageConverter的支持 (SPR-7504),具体格式如下 

<mvc:annotation-driven>      <mvc:message-converters>          <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>          <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>          <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>      </mvc:message-converters>  </mvc:annotation-driven>  

Servlet中的输入参数为都是string类型,而spring mvc通过data bind机制将这些string 类型的输入参数转换为相应的command object(根据view和controller之间传输数据的具体逻辑,也可称为model attributes, domain model objects)。在这个转换过程中,spring实际是先利用java.beans.PropertyEditor中的 setAdText方法来把string格式的输入转换为bean属性, 
亦可通过继承java.beans.PropertyEditorSupport来实现自定义的PropertyEditors,具体实现方式可参考spring reference 3.0.5 第 5.4节中的 Registering additional custom PropertyEditors部分。 
自定义完毕propertyEditor后,有以下几种方式来注册自定义的customer propertyEditor. 
1:直接将自定义的propertyEditor放到需要处理的java bean相同的目录下 
名称和java Bean相同但后面带Editor后缀。 
例如需要转换的java bean 名为User,则在相同的包中存在UserEditor类可实现customer propertyEditor的自动注册。 
2:利用@InitBinder来注册customer propertyEditor 
这个在之前的笔记中已经介绍过了,即在controller类中增加一个使用@InitBinder标注的方法,在其中注册customer Editor 

Java代码  收藏代码
  1. @InitBinder  
  2. public void initBinder(WebDataBinder binder) {  
  3.     SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  
  4.     dateFormat.setLenient(false);  
  5.     binder.registerCustomEditor(Date.classnew CustomDateEditor(  
  6.             dateFormat, false));  
  7. }  

3:继承 WebBindingInitializer 接口来实现全局注册 
使用@InitBinder只能对特定的controller类生效,为注册一个全局的customer Editor,可以实现接口WebBindingInitializer 。 
Java代码  收藏代码
  1. public class CustomerBinding implements WebBindingInitializer {  
  2.     @Override  
  3.     public void initBinder(WebDataBinder binder, WebRequest request) {  
  4.         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  
  5.         dateFormat.setLenient(false);  
  6.         binder.registerCustomEditor(Date.classnew CustomDateEditor(  
  7.                 dateFormat, false));  
  8.   
  9.     }  

并修改 servlet context xml配置文件 
Xml代码  收藏代码
  1. <bean  
  2.         class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
  3.         <property name="webBindingInitializer">  
  4.             <bean  
  5.                 class="net.zhepu.web.customerBinding.CustomerBinding" />  
  6.         </property>  
  7.     </bean>  

但这样一来就无法使用mvc:annotation-driven  了。 

使用conversion-service来注册自定义的converter 

DataBinder实现了PropertyEditorRegistry, TypeConverter这两个interface,而在spring mvc实际处理时,返回值都是return binder.convertIfNecessary(见HandlerMethodInvoker中的具体处理逻辑)。因此可以使用customer conversionService来实现自定义的类型转换。 

Xml代码  收藏代码
  1. <bean id="conversionService"  
  2. class="org.springframework.format.support.FormattingConversionServiceFactoryBean">  
  3.   
  4. <property name="converters">  
  5.     <list>  
  6.         <bean class="net.zhepu.web.customerBinding.CustomerConverter" />  
  7.     </list>  
  8. </property>  
  9.   
  10. lt;/bean>  


需要修改spring service context xml配置文件中的annotation-driven,增加属性conversion-service指向新增的conversionService bean。 

Xml代码  收藏代码
  1. <mvc:annotation-driven validator="validator"  conversion-service="conversionService" />  


实际自定义的converter如下。 
Java代码  收藏代码
  1. public class CustomerConverter implements Converter<String, Date> {  
  2. @Override  
  3. public Date convert(String source) {  
  4.     SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  
  5.     dateFormat.setLenient(false);  
  6.     try {  
  7.         return dateFormat.parse(source);  
  8.     } catch (ParseException e) {  
  9.         // TODO Auto-generated catch block  
  10.         e.printStackTrace();  
  11.     }         
  12.     return null;  
  13. }  



4 Spring Mvc 3.1 之后如何配置messageConverters

阅读文档发现Spring提供了基于<mvc:annotation-driven />自定义messageConverters的方法,

如下所示:(conversion-service="conversionService")

[html] view plain copy
 print?
  1. <mvc:annotation-driven conversion-service="conversionService">  
  2.     <mvc:message-converters>  
  3.         <bean class="org.example.MyHttpMessageConverter"/>  
  4.         <bean class="org.example.MyOtherHttpMessageConverter"/>  
  5.     </mvc:message-converters>  
  6. </mvc:annotation-driven>  


<mvc:annotation-driven /> 是一种简写形式,完全可以手动配置替代这种简写形式,简写形式可以让初学都快速应用默认配置方案。<mvc:annotation-driven /> 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的。

这句话我在很多帖子都看到过,我自己的项目本身使用的Spring MVC 3.2,实际上在3.1之后,<mvc:annotation-driven />注册的类发生了变化

Spring Framework 3.1 introduces a new set of support classes for processing requests with annotated controllers:

  • RequestMappingHandlerMapping

  • RequestMappingHandlerAdapter

  • ExceptionHandlerExceptionResolver

These classes are a replacement for the existing:

  • DefaultAnnotationHandlerMapping

  • AnnotationMethodHandlerAdapter

  • AnnotationMethodHandlerExceptionResolver

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:mvc="http://www.springframework.org/schema/mvc"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xsi:schemaLocation="  
  6.         http://www.springframework.org/schema/beans  
  7.         http://www.springframework.org/schema/beans/spring-beans.xsd  
  8.         http://www.springframework.org/schema/mvc  
  9.         http://www.springframework.org/schema/mvc/spring-mvc.xsd">  
  10.   
  11.     <mvc:annotation-driven />  
  12.   
  13. </beans>  



The above registers a RequestMappingHandlerMapping, a RequestMappingHandlerAdapter, and an ExceptionHandlerExceptionResolver (among others) in support of processing requests with annotated controller methods using annotations such as @RequestMapping @ExceptionHandler, and others.

It also enables the following:

  1. Spring 3 style type conversion through a ConversionService instance in addition to the JavaBeans PropertyEditors used for Data Binding.

  2. Support for formatting Number fields using the @NumberFormat annotation through the ConversionService.

  3. Support for formatting Date, Calendar, Long, and Joda Time fields using the @DateTimeFormat annotation.

  4. Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath.

  5. HttpMessageConverter support for @RequestBody method parameters and @ResponseBody method return values from @RequestMapping or @ExceptionHandler methods.

    This is the complete list of HttpMessageConverters set up by mvc:annotation-driven:

    • ByteArrayHttpMessageConverter converts byte arrays.

    • StringHttpMessageConverter converts strings.

    • ResourceHttpMessageConverter converts to/from org.springframework.core.io.Resource for all media types.

    • SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.

    • FormHttpMessageConverter converts form data to/from a MultiValueMap<String, String>.

    • Jaxb2RootElementHttpMessageConverter converts Java objects to/from XML — added if JAXB2 is present on the classpath.

    • MappingJackson2HttpMessageConverter (or MappingJacksonHttpMessageConverter) converts to/from JSON — added if Jackson 2 (or Jackson) is present on the classpath.

    • AtomFeedHttpMessageConverter converts Atom feeds — added if Rome is present on the classpath.

    • RssChannelHttpMessageConverter converts RSS feeds — added if Rome is present on the classpath.

这是摘取的官方文档,可以看出,注册的类已经变成了RequestMappingHandlerMapping和 RequestMappingHandlerAdapter。

我之前在不知道的时候,使用AnnotationMethodHandlerAdapter 进行配置,结果在有<mvc:annotation-driven />存在的情况下,我自己配置的AnnotationMethodHandlerAdapter 怎么都不起作用,于是去掉了<mvc:annotation-driven />标签,手动注册了AnnotationMethodHandlerAdapter ,和DefaultAnnotationHandlerMapping。结果引发了其他问题,比如文件无法上传的问题。


阅读文档发现Spring提供了基于<mvc:annotation-driven />自定义messageConverters的方法,如下所示:

[html] view plain copy
 print?
  1. <mvc:annotation-driven conversion-service="conversionService">  
  2.     <mvc:message-converters>  
  3.         <bean class="org.example.MyHttpMessageConverter"/>  
  4.         <bean class="org.example.MyOtherHttpMessageConverter"/>  
  5.     </mvc:message-converters>  
  6. </mvc:annotation-driven>  

下面展示我自己的配置

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
  4.     xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"  
  5.     xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:mvc="http://www.springframework.org/schema/mvc"  
  6.     xmlns:util="http://www.springframework.org/schema/util"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  8.                      http://www.springframework.org/schema/beans/spring-beans.xsd  
  9.                      http://www.springframework.org/schema/tx  
  10.                      http://www.springframework.org/schema/tx/spring-tx.xsd  
  11.                      http://www.springframework.org/schema/context   
  12.                      http://www.springframework.org/schema/context/spring-context.xsd  
  13.                      http://www.springframework.org/schema/aop  
  14.                      http://www.springframework.org/schema/aop/spring-aop.xsd  
  15.                      http://www.springframework.org/schema/jdbc  
  16.                      http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd  
  17.                      http://www.springframework.org/schema/util        
  18.                      http://www.springframework.org/schema/util/spring-util-3.2.xsd  
  19.                      http://www.springframework.org/schema/mvc   
  20.                      http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">  
  21.   
  22.     <!-- spring自动扫描注解的组件 -->  
  23.     <context:component-scan base-package="cn.xx.xx"  
  24.         use-default-filters="false">  
  25.         <context:include-filter expression="org.springframework.stereotype.Controller"  
  26.             type="annotation" />  
  27.     </context:component-scan>  
  28.   
  29.     <mvc:annotation-driven>  
  30.         <mvc:message-converters>  
  31.             <ref bean="stringHttpMessageConverter" />  
  32.             <ref bean="fastJsonHttpMessageConverter" />  
  33.             <ref bean="marshallingHttpMessageConverter" />  
  34.         </mvc:message-converters>  
  35.     </mvc:annotation-driven>  
  36.   
  37.     <bean id="stringHttpMessageConverter"  
  38.         class="org.springframework.http.converter.StringHttpMessageConverter">  
  39.         <constructor-arg value="UTF-8" index="0"></constructor-arg><!--  
  40.             避免出现乱码 -->  
  41.         <property name="supportedMediaTypes">  
  42.             <list>  
  43.                 <value>text/plain;charset=UTF-8</value>  
  44.             </list>  
  45.         </property>  
  46.     </bean>  
  47.     <bean id="fastJsonHttpMessageConverter"  
  48.         class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">  
  49.   
  50.         <property name="supportedMediaTypes">  
  51.             <list>  
  52.                 <value>application/json;charset=UTF-8</value>  
  53.                 <value>text/html;charset=UTF-8</value><!-- 避免IE出现下载JSON文件的情况 -->  
  54.             </list>  
  55.         </property>  
  56.         <property name="features">  
  57.             <util:list>  
  58.                 <!-- <value>WriteMapNullValue</value> -->  
  59.                 <value>QuoteFieldNames</value>  
  60.                 <value>WriteDateUseDateFormat</value>  
  61.             </util:list>  
  62.         </property>  
  63.     </bean>  
  64.       
  65.     <bean id="marshallingHttpMessageConverter"  
  66.         class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">  
  67.         <property name="marshaller" ref="castorMarshaller" />  
  68.         <property name="unmarshaller" ref="castorMarshaller" />  
  69.         <property name="supportedMediaTypes">  
  70.             <list>  
  71.                 <value>text/xml;charset=UTF-8</value>  
  72.                 <value>application/xml;charset=UTF-8</value>  
  73.             </list>  
  74.         </property>  
  75.     </bean>  
  76.   
  77.     <!-- 返回类型定义 -->  
  78.     <util:list id="messageConverters">  
  79.         <ref bean="stringHttpMessageConverter" />  
  80.         <ref bean="fastJsonHttpMessageConverter" />  
  81.         <ref bean="marshallingHttpMessageConverter" />  
  82.     </util:list>  
  83.   
  84.     <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />  
  85.   
  86.     <!-- AOP自动注解功能 -->  
  87.     <aop:aspectj-autoproxy />  
  88.   
  89.     <!-- 不进行拦截的 -->  
  90.     <mvc:resources location="/" mapping="/**/*.html" order="0" />  
  91.     <mvc:resources location="/images/" mapping="/images/**" />  
  92.     <mvc:resources location="/img/" mapping="/img/**" />  
  93.     <mvc:resources location="/download/" mapping="/download/**" />  
  94.   
  95.     <mvc:resources location="/js/" mapping="/js/**" />  
  96.     <mvc:resources location="/css/" mapping="/css/**" />  
  97.     <mvc:resources location="/plugin/" mapping="/plugin/**" />  
  98.     <mvc:resources location="/WEB-INF/pages/" mapping="/pages/**" />  
  99.   
  100.     <bean id="messageSource"  
  101.         class="org.springframework.context.support.ResourceBundleMessageSource">  
  102.         <property name="basename" value="messages"></property>  
  103.     </bean>  
  104.   
  105.     <bean  
  106.         class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
  107.         <property name="prefix" value="/WEB-INF/pages/" />  
  108.         <property name="suffix" value=".jsp" />  
  109.   
  110.     </bean>  
  111.   
  112.     <!-- 支持上传文件 -->  
  113.     <bean id="multipartResolver"  
  114.         class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />  
  115.   
  116.     <!-- restTemplate -->  
  117.     <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">  
  118.         <property name="messageConverters" ref="messageConverters">  
  119.         </property>  
  120.     </bean>  
  121. </beans>  

每到对一个定义不清晰的时候,就要去官网了:
7.6.5 Configuring Formatting in Spring MVC
In a Spring MVC application, you may configure a custom ConversionService instance explicitly as an attribute of the annotation-driven element of the MVC namespace. This ConversionService will then be used anytime a type conversion is required during Controller model binding. If not configured explicitly, Spring MVC will automatically register default formatters and converters for common types such as numbers and dates.
在Spring MVC应用程序中,您可以将自定义ConversionService实例显式配置为MVC命名空间的注释驱动元素的属性。 随后在Controller模型绑定期间需要进行类型转换时,将使用此ConversionService。 如果没有明确配置,Spring MVC将自动注册默认格式化程序和转换器,用于常见类型,如数字和日期。
关键在这一句话: ConversionService实例显式配置为MVC命名空间的注释驱动元素的属性则使用ConversionService。
                              如果没有明确配置,Spring MVC将自动注册默认格式化程序和转换器,用于常见类型,如数字和日期。
阅读全文
0 0
原创粉丝点击