springMVC:爲MultipartFilte配置了上傳文件解析器,報錯或不能使用

1、問題描述
爲支持restful風格請求,而且應對可能上傳文件的狀況,須要在配置hiddenHttpMethodFilter過濾器以前配置MultipartFilter。目的是讓MultipartFilter過濾器先將帶文件上傳的請求,進行解析。以便hiddenHttpMethodFilter能夠取到」_method」參數,轉化爲相應的http動做。
既然multipartFilter要進行上傳文件的解析,那麼必然須要MutipartResolver,那麼問題發生了!前端

2、報錯:Unable to process parts as no multi-part configuration has been provided
配置以下web

web.xmlspring

<filter>
        <filter-name>MultipartFilter</filter-name>
        <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
        <init-param>
            <param-name>multipartResolverBeanName</param-name>
            <param-value>multipartResolver</param-value>
        </init-param>
</filter>

springmvc.xml DispatcherServlert的上下文文件 
咱們使用了commons-fileupload-1.3.1.jar提供的CommonsMultipartResolver解析器restful

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
       <property name="maxUploadSize" value="20000000"/>
       <property name="defaultEncoding" value="utf-8"></property>
 </bean>

另外,還有一個multipartResolver須要介紹:
org.springframework.web.multipart.support.StandardServletMultipartResolvermvc

CommonsMultipartResolver:使用commons Fileupload來處理multipart請求,使用時需導入jar包。
StandardServletMultipartResolver:是基於Servlet3.0來處理multipart請求的,因此不須要引用其餘jar包,可是必須使用支持Servlet3.0的容器才能夠.app

緣由:
若是你配置的multipartFilter的multipartResolver是CommonsMultipartResolver,即如上面springmvc.xml,
web.xml的配置,報這個錯誤的話,說明你配置的上傳文件的解析器(CommonsMultipartResolver)根本,沒有用到,而是使用這個上傳文件的解析器(StandardServletMultipartResolver),而你又沒有對這個解析器提供必要的配置信息,因此報錯。less

3、解決問題
一、解決報錯
給StandardServletMultipartResolver提供配置信息便可,(注:爲什麼這樣配置,緣由見https://blog.csdn.net/gao_zhennan/article/details/81327268)
web.xmlwebapp

<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/applicationContext-web.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>

<!--    StandardServletMultipartResolvershu屬性配置  -->
    <multipart-config>
        <max-file-size>20848820</max-file-size>
        <max-request-size>418018841</max-request-size>
        <file-size-threshold>1048576</file-size-threshold>
    </multipart-config> 
  </servlet>

至此、報錯的問題已經解決。可是爲何咱們配置的上傳文件的解析器沒有用到呢?說來話長,咱們源碼中見。ide

2,解決未使用咱們本身配置的上傳文件的解析器(CommonsMultipartResolver) 
MultipartFilter關鍵源碼this

public class MultipartFilter extends OncePerRequestFilter {
    public static final String DEFAULT_MULTIPART_RESOLVER_BEAN_NAME = "filterMultipartResolver";
    private String multipartResolverBeanName = DEFAULT_MULTIPART_RESOLVER_BEAN_NAME;
    private final MultipartResolver defaultMultipartResolver = new 
      StandardServletMultipartResolver();

    //將web.xml文件中爲multipartFilter設置的參數(init-param)的屬性值(param-value),
    //經過調用set方法設置進來,此時multipartResolverBeanName=multipartResolver

    public void setMultipartResolverBeanName(String multipartResolverBeanName) {
        this.multipartResolverBeanName = multipartResolverBeanName;
    }

    protected String getMultipartResolverBeanName() {
        return this.multipartResolverBeanName;
    }


    protected MultipartResolver lookupMultipartResolver() {//關鍵方法:用來查找上傳文件的解析器

        WebApplicationContext wac = WebApplicationContextUtils.
        getWebApplicationContext(getServletContext());
        // 1.WebApplicationContext 是spring的上下文對象,在ContextLoaderListener加載spring的配置文件後,將生成的對應的WebApplicationContext,先放在了web.xml的上下文對象中ServletContext

        String beanName = getMultipartResolverBeanName();
        // 2.上面有這個方法,返回值爲this.multipartResolverBeanName,即"multipartResolver"
        if (wac != null && wac.containsBean(beanName)) {
            // 3.1只要監聽器ContextLoaderListener,加載了spirng的配置文件wac 就不會是null,
            // 如今關鍵的是:ContextLoaderListener加載的配置文件中是否配置了這個bean(id="multipartResolver")
            return wac.getBean(beanName, MultipartResolver.class);
        }
        else {
            //3.2如過ContextLoaderListener加載的配置文件中沒有這個bean,則與之
            //對應的WebApplicationContext對象中也不包含這個bean,
            //因而wac.containsBean(beanName) 爲false。
            //返回默認的解析器"StandardServletMultipartResolver"
            return this.defaultMultipartResolver;
        }
    }

有點抽象,說的再多不如去作下。在前端頁面發送了一個帶文件上傳控件的表單,看MutilFilter是否使用我配置的文件上傳的解析器(CommonsMultipartResolver)。 

 

wac.containsBean(beanName) beanName=」multipartResolver」 爲false。說明你在spring的上下文中沒有配置id=」multipartResolver」。奇怪了,我明明在springmvc.xml中配置了id=」multipartResolver」.爲何在spring對應的上下文對象中找不到呢?這裏就要牽扯到新的概念了。

springmvc.xml是由DispatcherServlet加載的,而後生成了springmvc的上下文對象,稱爲子容器。 ContextLoaderListener加載的配置文件,生成的spring的上下文對象,稱爲父容器。 子容器可使用父容器中定義的bean,反之則不行。 如上multipartResovler配置在springmvc.xnl中,即對應的bean在子容器中,而WebApplicationContext.containsBean()在父容器中是查找不到這個bean的
問題解決
1.新建一個applicationContext.xml(名字任意取),
2.將multipartResovler配置在其中。
3.重要的是要經過ContextLoaderListener來加載此文件,這樣這個bean就在spring的容器裏了,而後WebApplicationContext.containsBean()爲true,就會使用你配置的解析器,而不是使用默認的了。
最後放張圖

 

spring和spirngmvc父子容器介紹
(轉發自https://blog.csdn.net/jml1437710575/article/details/52020936)
在百度中別人的帖子中看到一段應該是官方的原文解釋,我摘抄過來並粗糙的直譯一下:

Spring lets you define multiple contexts in a parent-child hierarchy.
spring容許你定義多個上下文在父子繼承關係中

The applicationContext.xml defines the beans for the 「root webapp context」, i.e. the context associated with the webapp.
applicationContext.xml文件是爲了」根webapp應用上下文」定義bean, 也就是說它的上下文是和webapp想關聯的

The spring-servlet.xml (or whatever else you call it) defines the beans for one servlet’s app context. There can be many of these in a webapp,
spring-servlet.xml文件(或是其餘的你習慣的稱呼)是爲了一個servlet應用上下文呢定義bean. 在一個webapp中能夠有多個此配置文件,

one per Spring servlet (e.g. spring1-servlet.xml for servlet spring1, spring2-servlet.xml for servlet spring2).
每個spring的servlelt(例如: 名爲spring1的servlet擁有配置文件spring1-servlet.xml, 名爲spring2的servlet擁有配置文件spring2-servlet.xml).

Beans in spring-servlet.xml can reference beans in applicationContext.xml, but not vice versa.
在spring-servlet.xml中定義的bean能夠直接引用在applicationContext.xml中定義的bean, 可是反過來不能夠.

All Spring MVC controllers must go in the spring-servlet.xml context.
全部springmvc的Controller必須在spring-servlet.xml對應的上下文中運行.

In most simple cases, the applicationContext.xml context is unnecessary. It is generally used to contain beans that are shared between all servlets
在大多數簡單的狀況下, applicationContext.xml對應的上下文並沒必要須. 它一般用來包含那些bean用來在webapp中全部servlet之間共享.

in a webapp. If you only have one servlet, then there’s not really much point, unless you have a specific use for it.
若是你只有一個servlet, 那麼實際沒有什麼必要定義applicationContext.xml, 除非你有特別應用.

本文轉自:http://www.javashuo.com/article/p-cqramtzw-mo.html

相關文章
相關標籤/搜索