SpringMVC同時使用<mvc:resources … />和裝配自定義轉換器Converter時出現問題的解決方法

一、問題由來

在學習SpringMVC的過程中,對於URL的攔截,使用了RESTful形式,因爲使用了RESTful所以,在將Servlet作爲Controller中的時候,web.xml中配置攔截的url-pattern就寫成了 / ,如下所示:

<servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <!-- 此處可以可以配置成 *.do ,對應struts的後綴習慣 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

如果配置成這樣,對於靜態資源(js,css等)也會被攔截,因爲沒有Controller處理器和其對應,很顯然會報404的錯誤。

二、問題處理方式

對於此靜態資源的問題,我採用了RT所示的<mvc:resources … />這種進行處理:

<mvc:resources mapping="/css/**" location="/WEB-INF/statics/css/" />
<mvc:resources mapping="/js/**" location="/WEB-INF/statics/js/" />
<mvc:resources mapping="/images/**" location="/WEB-INF/statics/images/" />
<mvc:resources mapping="/*.html" location="/" />

項目目錄結構如下:

然而當把全局的Formatter<Date> 集成進去,想將字符串轉成Date的轉換器配置進處理器適配器時候出現問題,此時對於SpringMVC的配置是:

<mvc:annotation-driven conversion-service="conversionService" />

    <!-- 靜態資源映射 -->
    <!-- 比如${basePath}/css/ht.css 會自動請求location中的css -->
    <mvc:resources mapping="/css/**" location="/WEB-INF/statics/css/" />
    <mvc:resources mapping="/js/**" location="/WEB-INF/statics/js/" />
    <mvc:resources mapping="/images/**" location="/WEB-INF/statics/images/" />
    <mvc:resources mapping="/*.html" location="/" />

    <!-- 日期統一轉換 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatters">
            <set>
                <bean class="com.mc.bsframe.formatter.DateFormatter">
                    <constructor-arg name="datePattern" value="yyyy-MM-dd HH:ss:mm" />
                </bean>
            </set>
        </property>
    </bean>

錯誤提示主要是:
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.util.ArrayList<?>] to type [java.util.List<org.springframework.core.io.Resource>] for value '[/WEB-INF/statics/js/]'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.util.ArrayList<?>] to type [org.springframework.core.io.Resource]
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.util.ArrayList<?>] to type [org.springframework.core.io.Resource]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195)
    at org.springframework.core.convert.support.CollectionToCollectionConverter.convert(CollectionToCollectionConverter.java:87)
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:35)
    ... 36 more

錯誤提示中最核心的部分是:Failed to convert from type [java.util.ArrayList<?>] to type [java.util.List<org.springframework.core.io.Resource>] for value '[/WEB-INF/statics/js/]'翻譯出來就是:

嘗試將'[/WEB-INF/statics/js/]從java.util.ArrayList<?> 轉換到java.util.List<org.springframework.core.io.Resource>的時候失敗了。

在用Spring3.X的時候沒有這個問題出現,換成Spring4.X的時候就出現這個問題了,具體的原因不做解釋,大體上就是之前的是對於資源的存儲使用的是String[]現在改成了ArrayList<>造成的問題。

三、解決方法

  1. 要麼移除全局的Formatter。
  2. 要麼使用另外的方式進行靜態資源的映射。
  3. 更換Spring版本爲3.*

但一般都會使用第2個,因爲轉換器是必須的,而Spring版本一般不會更換,可能會使用到高版本中的一些特性或功能,具體處理步驟如下:

  1. 將會被從客戶端瀏覽器訪問的靜態資源(例如js、css、html)從WEB-INF下移動到WebApp下面。
  2. 註釋或刪除SpringMVC配置文件中的<mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>代碼
  3. 在SpringMVC的xml配置中加上,它的意思就是沒有映射到的URL交給默認的web容器中的servlet進行處理:
<mvc:default-servlet-handler />

最終的關鍵配置如下:

<mvc:annotation-driven conversion-service="conversionService" />
    <!-- 如果使用了RESTful形式的攔截,那麼對於靜態資源的處理上,就需要加上此句,靜態資源(沒有映射的)就會 -->
    <mvc:default-servlet-handler />

    <!-- 日期統一轉換 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatters">
            <set>
                <bean class="com.mc.bsframe.formatter.DateFormatter">
                    <constructor-arg name="datePattern" value="yyyy-MM-dd HH:ss:mm" />
                </bean>
            </set>
        </property>
    </bean>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章