Spring MVC file upload example

Spring uses MultipartResolver interface to handle the file uploads in web application, two of the implementation :

  1. StandardServletMultipartResolver – Servlet 3.0 multipart request parsing.
  2. CommonsMultipartResolver – Classic commons-fileupload.jar

Tools used in this article :

  1. Spring 4.3.5.RELEASE
  2. Maven 3
  3. Tomcat 7 or 8, Jetty 9 or any Servlet 3.0 container

In a nutshell, this article shows you how to handle file upload in Spring MVC web application, and also how to handle the popular max exceeded file size exception.

Note
This article will focus on the Servlet 3.0 multipart request parsing.

P.S Article is updated from Spring 2.5.x to Spring 4.3.x

1. Project Structure

A standard Maven project structure.

spring-mvc-file-upload-example-directory

2. Project Dependency

Standard Spring dependencies, no need extra library for file upload.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mkyong</groupId>
    <artifactId>spring-mvc-file-upload</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Spring MVC file upload</name>

    <properties>
        <jdk.version>1.8</jdk.version>
        <spring.version>4.3.5.RELEASE</spring.version>
        <jstl.version>1.2</jstl.version>
        <servletapi.version>3.1.0</servletapi.version>
        <logback.version>1.1.3</logback.version>
        <jcl.slf4j.version>1.7.12</jcl.slf4j.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>${jstl.version}</version>
        </dependency>

        <!-- compile only, deployed container will provide this -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servletapi.version}</version>
            <scope>provided</scope>
        </dependency>

		<!-- Logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${jcl.slf4j.version}</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                </configuration>
            </plugin>

            <!-- embedded Jetty server, for testing -->
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.11.v20150529</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <webApp>
                        <contextPath>/spring4upload</contextPath>
                    </webApp>
                </configuration>
            </plugin>

            <!-- configure Eclipse workspace -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                    <wtpversion>2.0</wtpversion>
                    <wtpContextName>/spring4upload</wtpContextName>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

3. MultipartConfigElement

Create a Servlet initializer class and register a javax.servlet.MultipartConfigElement

MyWebInitializer.java

package com.mkyong;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;
import java.io.File;

public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    private int maxUploadSizeInMb = 5 * 1024 * 1024; // 5 MB

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringWebMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {

        // upload temp file will put here
        File uploadDirectory = new File(System.getProperty("java.io.tmpdir"));

        // register a MultipartConfigElement
        MultipartConfigElement multipartConfigElement =
                new MultipartConfigElement(uploadDirectory.getAbsolutePath(),
                        maxUploadSizeInMb, maxUploadSizeInMb * 2, maxUploadSizeInMb / 2);

        registration.setMultipartConfig(multipartConfigElement);

    }

}

Review the MultipartConfigElement method signature.


public MultipartConfigElement(java.lang.String location,
                              long maxFileSize,
                              long maxRequestSize,
                              int fileSizeThreshold)

4. Spring Configuration

Register a multipartResolver bean, and returns StandardServletMultipartResolver

SpringWebMvcConfig.java

package com.mkyong;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc
@Configuration
@ComponentScan({"com.mkyong"})
public class SpringWebMvcConfig extends WebMvcConfigurerAdapter {

	// Bean name must be "multipartResolver", by default Spring uses method name as bean name.
    @Bean
    public MultipartResolver multipartResolver() {
        return new StandardServletMultipartResolver();
    }

	/*
	// if the method name is different, you must define the bean name manually like this :
	@Bean(name = "multipartResolver")
    public MultipartResolver createMultipartResolver() {
        return new StandardServletMultipartResolver();
    }*/

    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/jsp/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

}

At this stage, the Servlet 3.0 multipart request parsing is configured properly, and you can start uploading file.

4. Single File Upload

4.1 Normal HTML form tag.

upload.jsp

<html>

<body>
<h1>Spring MVC file upload example</h1>

<form method="POST" action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data">
    <input type="file" name="file" /><br/>
    <input type="submit" value="Submit" />
</form>

</body>
</html>

4.2 Another page to show the upload status.

uploadStatus.jsp

<html>
<body>
<h1>Upload Status</h1>
<h2>Message : ${message}</h2>
</body>
</html>

4.3 In the Controller, map the uploaded file to MultipartFile

UploadController.java

package com.mkyong.controller;

import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.StringJoiner;

@Controller
public class UploadController {

	//Save the uploaded file to this folder
    private static String UPLOADED_FOLDER = "F://temp//";

    @GetMapping("/")
    public String index() {
        return "upload";
    }

    //@RequestMapping(value = "/upload", method = RequestMethod.POST)
    @PostMapping("/upload") // //new annotation since 4.3
    public String singleFileUpload(@RequestParam("file") MultipartFile file,
                                   RedirectAttributes redirectAttributes) {

        if (file.isEmpty()) {
            redirectAttributes.addFlashAttribute("message", "Please select a file to upload");
            return "redirect:uploadStatus";
        }

        try {

            // Get the file and save it somewhere
            byte[] bytes = file.getBytes();
            Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
            Files.write(path, bytes);

            redirectAttributes.addFlashAttribute("message", 
                        "You successfully uploaded '" + file.getOriginalFilename() + "'");

        } catch (IOException e) {
            e.printStackTrace();
        }

        return "redirect:/uploadStatus";
    }

    @GetMapping("/uploadStatus")
    public String uploadStatus() {
        return "uploadStatus";
    }

}

5. Multiple File Upload

5.1 Just add more file input.

uploadMulti.jsp

<html>

<body>
<h1>Spring MVC multi files upload example</h1>

<form method="POST" action="${pageContext.request.contextPath}/uploadMulti" enctype="multipart/form-data">
    <input type="file" name="files" /><br/>
    <input type="file" name="files" /><br/>
    <input type="file" name="files" /><br/>
    <input type="submit" value="Submit" />
</form>

</body>
</html>

5.2 In Spring Controller, maps the multiple uploaded files to MultipartFile []

UploadController.java

    //...
	
    @PostMapping("/uploadMulti")
    public String multiFileUpload(@RequestParam("files") MultipartFile[] files,
                                  RedirectAttributes redirectAttributes) {

        StringJoiner sj = new StringJoiner(" , ");

        for (MultipartFile file : files) {

            if (file.isEmpty()) {
                continue; //next pls
            }

            try {

                byte[] bytes = file.getBytes();
                Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
                Files.write(path, bytes);

                sj.add(file.getOriginalFilename());

            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        String uploadedFileName = sj.toString();
        if (StringUtils.isEmpty(uploadedFileName)) {
            redirectAttributes.addFlashAttribute("message", 
                        "Please select a file to upload");
        } else {
            redirectAttributes.addFlashAttribute("message", 
                        "You successfully uploaded '" + uploadedFileName + "'");
        }

        return "redirect:/uploadStatus";

    }

    @GetMapping("/uploadMultiPage")
    public String uploadMultiPage() {
        return "uploadMulti";
    }
    //...

6. Handle Max upload size exceeded

To handle the popular max upload size exceeded exception, declares a @ControllerAdvice and catch the MultipartException

GlobalExceptionHandler.java

package com.mkyong.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MultipartException.class)
    public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {

        redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
        return "redirect:/uploadStatus";

    }

	// For commons-fileupload solution
    /*@ExceptionHandler(MaxUploadSizeExceededException.class)
    public String handleError2(MaxUploadSizeExceededException e, RedirectAttributes redirectAttributes) {

        redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
        return "redirect:/uploadStatus";

    }*/
}
Tomcat Connection Reset
If you deployed to Tomcat, and unable to catch the file size exceeded exception, this may cause by the Tomcat maxSwallowSize setting. Read this – Spring file upload and connection reset issue

7. DEMO

Get the source code below and test with the embedded Jetty server mvn jetty:run.

7.1 Review the pom.xml above, the embedded Jetty will deploy the web application on this /spring4upload context.

Terminal

project $ mvn jetty:run
//...
[INFO] Started o.e.j.m.p.JettyWebAppContext@341672e{/spring4upload,
	file:/SpringMVCUploadExample/src/main/webapp/,AVAILABLE}{file:/SpringMVCUploadExample/src/main/webapp/}
[WARNING] !RequestLog
[INFO] Started ServerConnector@3ba1308d{HTTP/1.1}{0.0.0.0:8080}
[INFO] Started @3743ms
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds.

7.2 Access http://localhost:8080/spring4upload

spring-mvc-file-upload-example1

7.3 Select a file ‘MyFirstExcel.xml‘ and upload it.

spring-mvc-file-upload-example2

7.4 Access http://localhost:8080/spring4upload/uploadMultiPage

spring-mvc-file-upload-example3

7.5 Select few files and upload it.

spring-mvc-file-upload-example4

7.6 Select a file larger than 5mb, you will visit this page.

spring-mvc-file-upload-max-size-exceed

8. Download Source Code

Download – spring-mvc-file-upload-example.zip (10 KB)

P.S For Spring 2.5.x, try this Spring.2.5-file-upload-example.zip (10KB)

References

  1. Spring Uploading Files
  2. Spring’s multipart (file upload) support

68 comments on “Spring MVC file upload example

  1. @PostMapping(“/upload”) not able to find annotation in my spring4. I will go with @RequestMapping only. thanks for direction.

    Reply
  2. Hi, do you have a solution if we want to compress the image (reduce weight)

    Reply
  3. Facing Access denied issue
    You failed to upload => E:Apacheapache-tomcat-7.0.57-windows-x86apache-tomcat-7.0.57tmpFiles (Access is denied)
    Gave full permission using below command
    cacls E:Apacheapache-tomcat-7.0.57-windows-x86apache-tomcat-7.0.57tmpFiles /t /e /g Everyone:f
    processed dir: E:Apacheapache-tomcat-7.0.57-windows-x86apache-tomcat-7.0.57tmpFiles
    and also given full permission form ui .
    Still facing same issue

    Reply
  4. hi,thanks for code but how can you validate above code in java script

    Reply
  5. Hello sir,
    i want to create folder using Id. This is my task. Plz help me

    Reply
  6. Hi,thanks for your post, it was really helpfull. I have a question, where can I place the files, some permanent folder intead of a temporal. Thanks

    Reply
  7. Hello, I make all by you tutorial, but when a run jetty and trying open – http://localhost:8080/spring4upload/
    I have:
    HTTP ERROR 404
    Problem accessing /spring4upload/WEB-INF/view/jsp/upload.jsp. Reason:
    /spring4upload/WEB-INF/view/jsp/upload.jsp
    What I doing wrong?

    Reply
  8. how i Upload multiple file with single submit button????

    Reply
  9. how i Upload multiple file with single browse button.?

    Reply
  10. Hi,
    I am getting the 400 – Bad request when uploading the file more than 2Mb in size. I am using Spring with web service.
    Can you please help me out.

    Thanks,

    Reply
  11. Hey, thanks for nice code. I got it working, however i could not see where will exactly this uploaded file will be ? kindly let me know.. thanks again

    Reply
  12. I am getting Null pointer exception while uploading file.

    /uploadFile
    java.lang.NullPointerException
    at java.io.File.(File.java:312)
    at org.apache.commons.fileupload.disk.DiskFileItem.getTempFile(DiskFileItem.java:582)
    at org.apache.commons.fileupload.disk.DiskFileItem.getOutputStream(DiskFileItem.java:528)
    at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:347)
    at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:115)
    at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:159)
    at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:142)
    at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1072)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:914)

    Reply
  13. Hi MKyong,

    I am getting EVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping#0’ defined in ServletContext resource [/WEB-INF/mvc-dispatcher-servlet.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘com.mkyong.common.controller.FileUploadController#0’ defined in ServletContext resource [/WEB-INF/mvc-dispatcher-servlet.xml]: Initialization of bean failed; nested exception is java.lang.Error: Unresolved compilation problem:

    The method supports(Class) of type FileUploadValidator must override a superclass method

    Error, Could you please help me on this.

    Reply
  14. Description Resource Path Location Type
    The method supports(Class) of type FileUploadValidator must override a superclass method FileUploadValidator.java /SpringMVC Maven Webapp/src/main/java/com/mkyong/common/validator line 11 Java Problem

    Reply
  15. Hi Can you tell me, how to upload large file like 200 and 300 MB in size.

    Reply
  16. Hi yong how to do image validation in spring3.0 can u explain

    Reply
  17. Hi,
    I am getting error on image upload

    In my application image upload functionality working properly on local side. When i upload war file on server that time image not show. what cause this problem occur

    Reply
  18. Hi,
    How to restrict upload based on file content type like I will allow only png and jpeg?

    Thanks in advance.

    Reply
  19. Can not find the tag library descriptor for “http://www.springframework.org/tags/
    form”

    ????

    Reply
  20. The type javax.servlet.http.HttpServletResponse cannot be resolved. It is indirectly referenced from required .class files

    fix

    right click on project name -> Properties -> Java Build Path -> Libraries -> Add External JARs..

    (~/.m2/repository/javax/servlet/servlet-api/2.5/servlet-api-2.5.jar)

    Reply
  21. hi, need one help. i am hosting this in my pc using tomcat. how can i control the path where i want to push this uploaded files. basically i want to push files by their name. when file is uploaded i will check its name and i will push it to its corresponding directory.

    Reply
  22. There is no SimpleFormController in Spring 3.
    can you please update your tutorial?

    Reply
    1. Hi foobar
      are u got the answer for u r question
      if u know plz share answer to me also
      thank you

      Reply
  23. Hi,

    I have a jsp with file upload and form:input variable, when I click on submit I get the file object but input object are null. Can some one please give the code or suggest how to get input type text value when form enctype=”multipart/form-data”.

    Thanks..
    Dinesh

    Reply
  24. Sir,
    Am having some trouble getting this particular demo to run. I had to make one addition to the pom — that is, adding the javax.servlet/servlet/2.5 jar manually. Perhaps you could point me in the right direction? Many thanks!

    Reply
  25. Tutorial is very useful but i got this error when i submit form with out choosing any file
    No message found under code ‘required.fileUpload’ for locale ‘en_US’.

    Reply
  26. Hi,

    i am facing strange issue in Jboss 7, i am getting NoClassDef error

    java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
    	org.apache.commons.fileupload.servlet.ServletFileUpload.isMultipartContent(ServletFileUpload.java:68)
    	org.springframework.web.multipart.commons.CommonsMultipartResolver.isMultipart(CommonsMultipartResolver.java:122)
    	org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:991)
    	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:860)
    	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
    	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    	org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    
    
    Reply
    1. Adding to above, i am using Spring 3.1, with OpenJPA 2.1 . Your example works fine but issues crop up when Jboss 7 loads jars in modular way, I have created new module for openJpa 2.1 and strangely it requires commons-fileupload.jar in its dependencies, else server wont startup.

       
      <module xmlns="urn:jboss:module:1.1" name="org.apache.openjpa">
          <resources>
              <resource-root path="openjpa-all-2.2.0.jar"/>
              <resource-root path="serp-1.13.1.jar"/>
      	<resource-root path="commons-fileupload-1.2.2.jar"/> <!-- other sites say not required , but i am unable to start server without it-->
          </resources>
      
              <dependencies>
                  <module name="javax.persistence.api"/>
                  <module name="javax.transaction.api"/>
                  <module name="javax.validation.api"/>
      	     <module name="org.apache.log4j"/>
      			
              </dependencies>
      </module> 

      So i would think somewhere class loading is going wrong, or i am missing something ……

      Reply
    2. Just add the javax.servlet api spec. The pom stanza is:

      javax.servlet
      servlet-api
      2.5

      Reply
      1. Woops, it ate the XML tags… Let me try again:

        
        		<dependency>
        			<groupId>javax.servlet</groupId>
        			<artifactId>servlet-api</artifactId>
        			<version>2.5</version>
        		</dependency>
        
        Reply
  27. Thanks for the tutorial. Can you help out with server-side validation (extension and content-type) of the file being uploaded? That shall help restrict the file one tries to upload.

    Reply
  28. Where these files will be uploaded? I hope just we are getting file to controller if we want we have to write some code to store those file to DB or Server side folder.

    Reply
  29. How can I validate the size and dimension of an uploaded file.If the allowed size is suppose 400 kb and dimension is let’s say 40×20??

    Reply
  30. Short and to the point tutorial.. this is just what i needed.
    God Bless

    Reply
  31. Is there any way to restrict user to upload only files with some specific extensions?

    Reply
  32. Hello Yong
    I have implemented single file upload.
    Now i want to implement multiple file upload .
    So it there is any idea then please let me know ….

    Thanks and Regards
    Kinjan Ajudiya

    Reply
  33. All is good

    But is this work file the file-format of .jpg,.gif, .txt, .doc?

    Reply
      1. Hi! How can i restrict the file types being uploaded. e.g. if the user should upload only .pdf OR / .xls files. How to do that in the Spring MVC file Upload ? Thanks for this great example.

        Reply
        1. hi how to upload image using jqgrid with spring mvc
          means:- in jqgrid if u click the add button i want to upload the image

          please help me

          Reply
  34. hi,,
    I am getting getting this error can u please help me out

    “Error creating bean with name ‘multipartResolver’ defined in ServletContext resource [/WEB-INF/mvc-dispatcher-servlet.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.web.multipart.MultipartResolver]: Specified class is an interface”

    Reply
    1. Article is fully updated to Spring 4.3, try the new example.

      Reply
  35. this is the scenario:
    we process payments example cash, check and credit card. but through upload file.
    in that file, the creditcard number is included. what should i do/ technique to use if i want to mask the values for credit card number so that when the payments are saved in the database, the card number is not accessible.(it is required for customer’s security.)
    thanks

    Reply
  36. Once i download the zip and import the project into eclipse, how do i build it. I know eclipse builds it automatically, but here when i import it is giving errors like Can not find the tag library descriptor for “http://www.springframework.org/tags/form”. i think this has to do something with maven. So i installed the maven plugin into eclipse but still this error is present. Any clues?

    Reply

Leave a Comment

Your email address will not be published. Required fields are marked *