在Spring MVC上使用Servlet 3.0的MultipartConfig


问题内容

我如何在Spring MVC应用程序中添加多部分配置,该应用程序使用带有RequestMapping注释的方法的控制器?

背景:

我想启用csrf保护,因此已在spring
config中添加了security:csrf标记。我有一个控制器类,其方法带有用于上传文件的RequestMapping注释。我还遵循有关multipart
警告说明,从而在安全性过滤器上方添加了multipart过滤器。当我在添加csrf标记后尝试上传文件时,在缺少的getParts()方法周围出现了异常。一个快速的谷歌强调这是由于使用了基于servlet
2.5规范的码头版本。我将jetty-maven-plugin升级到8.1.14.v20131031,然后尝试再次上传。导致:

org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: No multipart config for servlet
        at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:68)
        at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:58)
        at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:110)

如何将多部分配置用于xml设置?所有文档都说要在web.xml中特定servlet的servlet标记中添加multipart-
config。我的应用程序只有一个servlet。所以我添加了它,但仍然遇到相同的问题。

<servlet>
    <servlet-name>SpringDispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <multipart-config>
        <location>/tmp</location>
        <max-file-size>20848820</max-file-size>
        <max-request-size>418018841</max-request-size>
        <file-size-threshold>1048576</file-size-threshold>
    </multipart-config>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/servlet-context.xml
        </param-value>
    </init-param>
    <load-on-startup>10</load-on-startup>
</servlet>

我还更新了web.xml顶部的架构位置,以指向Servlet规范的3.0版,该规范源自http://www.mkyong.com/web-
development/the-web-xml-deployment-descriptor-examples
/。

有什么帮助吗?

编辑:为罗布添加了以下规则:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/spring/webapp.xml</param-value>
    </context-param>

    <context-param>
        <param-name>spring.profiles.default</param-name>
        <param-value>OracleDB,common</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>SpringDispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <multipart-config>
            <location>/tmp</location>
            <max-file-size>20848820</max-file-size>
            <max-request-size>418018841</max-request-size>
            <file-size-threshold>1048576</file-size-threshold>
        </multipart-config>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/servlet-context.xml
            </param-value>
        </init-param>
        <load-on-startup>10</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>SpringDispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>MultipartFilter</filter-name>
        <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>MultipartFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>XSS</filter-name>
        <filter-class>com.mycompany.CrossScriptingFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>XSS</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <session-config>
        <session-timeout>10</session-timeout>
    </session-config>

    <resource-ref>
        <description>Core Datasource</description>
        <res-ref-name>jdbc/coreDataSource</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

    <resource-ref>
        <description>Location Datasource</description>
        <res-ref-name>jdbc/locationDataSource</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

    <error-page>
        <!-- Missing login -->
        <error-code>401</error-code>
        <location>/WEB-INF/views/errorPage.jsp</location>
    </error-page>
    <error-page>
        <!-- Forbidden directory listing -->
        <error-code>403</error-code>
        <location>/WEB-INF/views/errorPage.jsp</location>
    </error-page>
    <error-page>
        <!-- Missing resource -->
        <error-code>404</error-code>
        <location>/WEB-INF/views/errorPageNotFound.jsp</location>
    </error-page>
    <error-page>
        <!-- Uncaught exception -->
        <error-code>500</error-code>
        <location>/WEB-INF/views/errorPage.jsp</location>
    </error-page>
    <error-page>
        <!-- Unsupported servlet method -->
        <error-code>503</error-code>
        <location>/WEB-INF/views/errorPage.jsp</location>
    </error-page>

</web-app>

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <mvc:annotation-driven />

    <mvc:resources mapping="/resources/**" location="/resources/" />
    <mvc:resources mapping="/images/**" location="file:${fileSystemStore.fileSystemStorageLocation}"/>

    <context:component-scan base-package="com.mycompany.console.*" />

    <mvc:interceptors>
        <bean class="com.mycompany.security.ChangePasswordInterceptor" />
    </mvc:interceptors>

    <security:global-method-security
        secured-annotations="enabled" jsr250-annotations="enabled"
        pre-post-annotations="enabled" proxy-target-class="true" />

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
        <property name="contentType" value="text/html;charset=UTF-8" />
    </bean>

    <bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="100000000"/>
    </bean>

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>classpath:language</value>
                <value>classpath:language_additions</value>
                <value>classpath:formats</value>
            </list>
        </property>
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

    <bean id="localeResolver" class="com.mycompany.locale.SessionLocaleResolver"/>

</beans>

问题答案:

我相信您在与SPR-11373相关的问题。具体来说,对于在过滤器中执行多部分解析时应如何处理,Servlet规范尚不清楚。

您是否尝试过使用commons-fileupload?这可能是您的最佳选择。首先添加以下依赖项:

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.2.2</version>
</dependency>

接下来,确保您在根应用程序上下文中具有以下bean定义。

<bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000"/>
</bean>

你可以找到一个完整的工作例如既公地上传(喜欢这个解决方案),并使用Tomcat使用allowCasualMultipartParsingSEC-2471