5

I'm trying to upload a multipart file using Ajax, Spring MVC 3.2.0, Tomcat 8.0.9, but can't get it work. I read a lot of blogs and similar posting here on stackoverflow (Spring upload file problems, MultipartConfig with Servlet 3.0 on Spring MVC, …) which seem to have similar causes but couldn't figure out how to solve it. The weird thing is that the upload works when the file is smaller than 1MB, but when ever the recorded video exceeds that size, the following error is raised:

org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. null
org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:163)
org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:139)
org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:110)

In the following you can see all the configurations I made:

  1. The AJAX POST-Request:

    var videoBlob = e.data;
    var pathArray = window.location.pathname.split( '/' );
    var userID;
    
    for (i = 0; i < pathArray.length; i++) {
        if (pathArray[i].toString() == "edit"){
            userID = pathArray[i+1];
        }
    }
    
    var fd = new FormData();
    fd.append('fname', 'video');
    fd.append('data', videoBlob);
    
    $.ajax({
        url: '/user/edit/uploadVideo/' + userID,
        data: fd,
        processData: false,
        contentType: false,
        type: 'POST',
        success: function(data)
        {
            $('#result').html(data + "uploaded by FormData!");
        }
    });
    
  2. The web.xml

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:root-context.xml</param-value>
    </context-param>
    
    <context-param>
        <param-name>spring.profiles.default</param-name>
        <param-value>common</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <filter>
        <display-name>springMultipartFilter</display-name>
        <filter-name>springMultipartFilter</filter-name>
        <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>springMultipartFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
  3. The servlet-context.xml

    <mvc:annotation-driven />
    <mvc:resources mapping="/**" location="/resources/" />
    
    <context:component-scan base-package="de.talentwuerfel"/>
    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/" />
    <property name="suffix" value=".jsp" />
    </bean>
    
    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/schema"/>
    <property name="username" value="root"/>
    <property name="password" value=""/>
    <property name="validationQuery" value="SELECT 1"/>
    </bean>
    
    <bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource"/>
    <property name="packagesToScan">
        <array>
            <value>de.talentwuerfel</value>
        </array>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
    </bean>
    
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="mySessionFactory"/>
    </bean>
    
    <bean id="persistenceExceptionTranslationPostProcessor"
      class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
    
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
  4. The root-context.xml where I defined the MultipartResolver

    <bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize"   value="100000000"/>
        <property name="maxInMemorySize" value="4096"/>
    </bean>
    
  5. The Java-Controller

    @RequestMapping(value = "/edit/uploadVideo/{id}", method = RequestMethod.POST)
    public @ResponseBody String uploadVideo(@PathVariable long id, MultipartHttpServletRequest request, HttpServletResponse response) throws IOException {
          //.... file handling
    }
    

How can I solve this problem?

EDIT:

I tried the suggested approach and used the Servlet implementation to manage my video-file upload. The following adjustments have been made, but it's still resulting in a similar error:

  1. Adjusted @Controller:

    @RequestMapping(value = "/edit/uploadVideo/{id}", method = RequestMethod.POST)
    public String uploadVideo(@PathVariable long id, @RequestParam("data") Part file) {
    
    //...
    }
    
  2. The root-controller has been deleted and I added the multipartResolver to the servlet-context.xml

    <bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
    </bean>
    
  3. The tag was in the web.xml has been extended by the following Multipart-Configuration:

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <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>
    </servlet>
    

However, I'm still getting an exception and can't upload a blob file larger than 1MB:

Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. null
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:927)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:822)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:725) 

I implemented a similar file upload where a single file was simply picked and it totally worked to send large files while using the same configuration. So I believe it has rather something to do with the Ajax POST or the attached blob file?!

2
  • Have you trieg modifying the maxUploadSize parameter (in your filterMultipartResolver) to a value superior to 100000000 ? Like 200000000 for example. - EDIT : sorry, I thought it was related but the size in in byte, so you would have a max file size of 100MB which is enough... docs.oracle.com/javaee/6/tutorial/doc/gmhal.html Commented Aug 17, 2014 at 14:54
  • Tried that already but didn't help. Here is the request header that is created by the AJAX-request: Accept / Accept-Encoding gzip, deflate Accept-Language en-US,en;q=0.5 Content-Length 1422427 Content-Type multipart/form-data; boundary=---------------------------16605868027849048022050447340 Cookie JSESSIONID=D3611B0B660302FF7A6A2D2BD57ADEDD Host localhost:8080 Referer localhost:8080/user/edit/2 User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:31.0) Gecko/20100101 Firefox/31.0 X-Requested-With XMLHttpRequest Commented Aug 17, 2014 at 14:57

2 Answers 2

1

you can add this in you application to active Servlet3.0 MultiParsing:

 @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultiPartConfigFactory factory = new MultiPartConfigFactory();
        factory.setMaxFileSize("128KB");
        factory.setMaxRequestSize("128KB");
        return factory.createMultipartConfig();
    }

or do it in XML.

Sign up to request clarification or add additional context in comments.

1 Comment

If you're using Spring Boot 1.5.x then the class name is org.springframework.boot.web.servlet.MultipartConfigFactory (attention to lowercase "P")
0

Not really an answer to your exact question, just my 2 cents. There are basically 2 ways of uploading files with the help of Spring MVC :

  • using Jakarta Commons FileUpload, the only way (aside from implementing one yourself) before the appearance of the servlet 3.0 API
  • using the Servlet implementation of your server (only if servlet impl version >= 3.0)

Since you are using Tomcat 8.0.9, the Servet 3.0 option is available to you which I definitely recommend since it doesn't introduce yet another external dependency in your project. Also, since it follows the Servlet 3.0 spec, the configuration of such upload mechanism is now java standard which is nice in case you decide to move from Spring MVC to another MVC framework (your configuration values would remain the same).

In case you can't figure out your IOFileUploadException, I think you should give it a try.

10 Comments

Thanks for the tip, servlet impl version is 3.0 and I'll give it a try!
Let us know how it goes. I suggested this solution also because I worked with the Servlet 3.0 way more than with the Commons FileUpload one so I could be of more help if you were to encounter any issue using the Servlet 3.0 way.
I tried the Servlet 3.0 implementation but still can't send the desired files. Please have a look at the edited question where I attached the new code/configuration.
I find it weird that you're still getting a stack containing "org.apache.tomcat.util.http.fileupload", did you properly removed the Commons FileUpload dependency from your project ? If yes, it must indeed be something about the AJAX request.
Also, could you please try with org.springframework.web.multipart.MultipartFile in your controller's method signature (this -> @RequestParam("data") MultipartFile file instead of this -> @RequestParam("data") Part file). And even try with an empty signature... because apart from the request being "corrupted" from a java standpoint, I don't understand why the server-side request processing fail this early (FrameworkServlet.processRequest(FrameworkServlet.java:927)).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.