Spring MVC Multiple File Upload example

In this simple tutorial we will see how to implement multiple file upload in a Spring 3 MVC based application. The requirement is simple. We have a form which displays file input component. User selects a file and upload it. Also its possible to add more file input components using Add button. Once the files are selected and uploaded, the file names are displayed on success page.

1. Maven Dependencies / Required JAR files

If you using Maven in your project for dependency management, you’ll need to add dependencies for Apache Common File upload and Apache Common IO libraries. The spring’s CommonsMultipartResolver class internal uses these library to handle uploaded content. Add following dependencies in your maven based project to add File upload feature.

<dependencies> <!-- Spring 3 MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.1.2.RELEASE</version> </dependency> <!-- Apache Commons file upload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <!-- Apache Commons IO --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <!-- JSTL for c: tag --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies>
Code language: HTML, XML (xml)

If you have a simple web application, add following JAR files in WEB-INF/lib folder. You can download all these JARs with source code at the end of this tutorial.

2. Model – Form Object

Create a Java bean which acts as Model/Form object for our Spring application. This bean contains a List of org.springframework.web.multipart.MultipartFile objects. Spring framework provides a useful class MultipartFile which can be used to fetch the file content of uploaded file. Apart from its content, the MultipartFile object also gives you other useful information such as filename, file size etc. 

FileUploadForm.java

package net.viralpatel.spring3.form; import java.util.List; import org.springframework.web.multipart.MultipartFile; public class FileUploadForm { private List < MultipartFile > files; //Getter and setter methods }
Code language: Java (java)

3. Controller – Spring Controller

Create a Spring 3 MVC based controller which handles file upload. There are two methods in this controller:

  1. displayForm – Is a used to show input form to user. It simply forwards to the page file_upload_form.jsp
  2. save – Fetches the form using @ModelAttribute annotation and get the File content from it. It creates a list of filenames of files being uploaded and pass this list to success page.

FileUploadController.java

package net.viralpatel.spring3.controller; import java.util.ArrayList; import java.util.List; import net.viralpatel.spring3.form.FileUploadForm; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.multipart.MultipartFile; @Controller public class FileUploadController { @RequestMapping(value = "/show", method = RequestMethod.GET) public String displayForm() { return "file_upload_form"; } @RequestMapping(value = "/save", method = RequestMethod.POST) public String save( @ModelAttribute("uploadForm") FileUploadForm uploadForm, Model map) { List<MultipartFile> files = uploadForm.getFiles(); List<String> fileNames = new ArrayList<String>(); if(null != files && files.size() > 0) { for (MultipartFile multipartFile : files) { String fileName = multipartFile.getOriginalFilename(); fileNames.add(fileName); //Handle file content - multipartFile.getInputStream() } } map.addAttribute("files", fileNames); return "file_upload_success"; } }
Code language: Java (java)

4. View – JSP views

Now create the view pages for this application. We will need two JSPs, one to display file upload form and another to show result on successful upload. The file_upload_form.jsp displays a form with file input. Apart from this we have added small jquery snippet onclick of Add button. This will add a new file input component at the end of form. This allows user to upload as many files as they want (subjected to file size limit ofcourse). Note that we have set enctype=”multipart/form-data” attribute of our <form> tag. 

file_upload_form.jsp

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <html> <head> <title>Spring MVC Multiple File Upload</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script> $(document).ready(function() { //add more file components if Add is clicked $('#addFile').click(function() { var fileIndex = $('#fileTable tr').children().length - 1; $('#fileTable').append( '<tr><td>'+ ' <input type="file" name="files['+ fileIndex +']" />'+ '</td></tr>'); }); }); </script> </head> <body> <h1>Spring Multiple File Upload example</h1> <form:form method="post" action="save.html" modelAttribute="uploadForm" enctype="multipart/form-data"> <p>Select files to upload. Press Add button to add more file inputs.</p> <input id="addFile" type="button" value="Add File" /> <table id="fileTable"> <tr> <td><input name="files[0]" type="file" /></td> </tr> <tr> <td><input name="files[1]" type="file" /></td> </tr> </table> <br/><input type="submit" value="Upload" /> </form:form> </body> </html>
Code language: HTML, XML (xml)

Note that we defined the file input name as files[0], files[1] etc. This will map the submitted files to the List object correctly. I would suggest you to go through this tutorial to understand how Spring maps multiple entries from form to bean: Multiple Row Form Submit using List of Beans Second view page is to display filename of uploaded file. It simply loops through filename list and display the names. 

file_upload_success.jsp

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <html> <head> <title>Spring MVC Multiple File Upload</title> </head> <body> <h1>Spring Multiple File Upload example</h1> <p>Following files are uploaded successfully.</p> <ol> <c:forEach items="${files}" var="file"> <li>${file}</li> </c:forEach> </ol> </body> </html>
Code language: HTML, XML (xml)

5. Spring Configuration

In Spring configuration (spring-servlet.xml) we define several important configurations. Note how we defined bean multipartResolver. This will make sure Spring handles the file upload correctly using CommonsMultipartResolver class. 

spring-servlet.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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:annotation-config /> <context:component-scan base-package="net.viralpatel.spring3.controller"/> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> </beans>
Code language: HTML, XML (xml)

6. Output

Execute the project in Eclipse. Open following URL in browser to see file upload form.

URL: http://localhost:8080/Spring3MVC_Multiple_File_Upload_example/show.html

Select files through file dialog and press Upload button to upload. Following page will displayed with list of files being uploaded.

We have added a small JavaScript snippet for Add button. This will add more file upload components to the page. Use this if you want to upload more files.

Download Source Code

SpringMVC_Multi_File_Upload_example.zip (3.6 MB)

View Comments

  • Hi Viral! A great tutorial! How do we restrict the file types being uploaded. Use case being i want the user to upload only .pdf file or .xls files.

    • You can use a validator, first register your validator

      [code language="java"]
      @InitBinder("uploadItem")
      void initBinder(WebDataBinder binder) {
      binder.setValidator(new UploadValidator ());
      }

      [/code]

      Then you apply that validator to uploaded file
      [code language="java"]

      public String uploadPluginAction(@Valid @ModelAttribute("uploadItem") FileUploadBean uploadItem, BindingResult result, ModelMap modelMap,
      HttpServletRequest request, HttpServletResponse response)
      {
      logger.trace("Upload Handler");
      // Check for validation error
      if (result.hasErrors())
      {

      return "/add";
      }
      }
      [/code]

      [code language="java"]
      mport java.io.IOException;

      import org.apache.log4j.Logger;
      import org.springframework.validation.Errors;
      import org.springframework.validation.Validator;
      import org.springframework.web.multipart.MultipartFile;

      public class UploadValidator implements Validator {
      private static transient Logger logger = Logger.getLogger(UploadValidator.class);
      // Content types the user can upload
      private static final String[] ACCEPTED_CONTENT_TYPES = new String[] {
      "application/pdf",
      "application/doc",
      "application/msword",
      "application/rtf",
      "text/richtext" ,
      "text/rtf" ,
      "text/plain" ,
      "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ,
      "application/vnd.sun.xml.writer" ,
      "application/x-soffice" ,
      };

      private static final String[] ACCEPTED_EXTENSIONS = new String[] {
      "doc",
      "pdf",
      "docx",
      "rtf",
      "txt",
      };

      @Override
      public boolean supports(Class<?> clazz) {
      return FileUploadBean.class.equals(clazz);
      }

      /**
      * Validate our uploaded bean
      */
      @Override
      public void validate(Object obj, Errors errors) {
      FileUploadBean uploadItem = (FileUploadBean) obj;
      MultipartFile file = uploadItem.getFile();
      try {
      if(file == null || file.getBytes().length == 0){
      errors.reject("error.upload.null", "File name can't be empty");
      return;
      }
      } catch (IOException e) {
      logger.error(e.getMessage());
      }

      // Check content type
      boolean acceptableContentType = false;
      String incomingContentType = file.getContentType();
      logger.info("FileName = "+file.getName());
      logger.info("incomingContentType = "+incomingContentType);
      // This related to bug when on Vista and using Firefox content type is 'application/octet-stream'
      // Instead of one of the allowed ones
      if("application/octet-stream".equalsIgnoreCase(incomingContentType)){
      int index = file.getOriginalFilename().lastIndexOf('.');
      String incomingExtension = file.getOriginalFilename().substring(index + 1);
      for(String extendsion : ACCEPTED_EXTENSIONS){
      if(extendsion.equalsIgnoreCase(incomingExtension)){
      acceptableContentType = true;
      break;
      }
      }
      }else{
      for(String contentType : ACCEPTED_CONTENT_TYPES){
      logger.debug("Comparing " + incomingContentType +" to "+ contentType);
      if(contentType.equalsIgnoreCase(incomingContentType)){
      acceptableContentType = true;
      break;
      }
      }
      }
      if(!acceptableContentType){
      errors.reject("error.upload.contenttype", "Please upload a file with one of the following file types; .doc, .docx, .txt, .pdf, .rtf .");
      }
      }
      }

      [/code]

      I hope this helps

      • Hi Creg,

        In your reply said :
        First register your validator, then apply, can you please show us where to register and where to apply, and where to create the validator, do we need a configuration somewhere ?

        Thanks

  • Hello there, nice tutorial. Just one warn, when I run your example after download it from here and I get the following exception stacktrace:
    [code language="java"]
    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
    Field error in object 'uploadForm' on field 'files[0]': rejected value [[org.springframework.web.multipart.commons.CommonsMultipartFile@21e4d4, org.springframework.web.multipart.commons.CommonsMultipartFile@1363716]]; codes [typeMismatch.uploadForm.files[0],typeMismatch.uploadForm.files,typeMismatch.files[0],typeMismatch.files,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [uploadForm.files[0],files[0]]; arguments []; default message [files[0]]]; default message [Failed to convert property value of type 'java.util.LinkedList' to required type 'org.springframework.web.multipart.MultipartFile' for property 'files[0]'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.util.LinkedList] to required type [org.springframework.web.multipart.MultipartFile] for property 'files[0]': no matching editors or conversion strategy found]
    [/code]

    You shoul change the line of code:
    [code language="java"]
    var fileIndex = $('#fileTable tr').children().length - 1;
    [/code]
    for this one:
    [code language="java"]
    var fileIndex = $('#fileTable tr').children().length;
    [/code]
    doing so, it wont duplicate the same last index when select the "Add File" button

    Regards!

  • this is very good to learn java, keep exist with this site such we can to be java expert hahahahaha., thanks viralpatel.,

  • Spring Multiple File Upload example
    Following files are uploaded successfully.

    CreateDB.sql

    Where is place uploaded files ?

  • hai all
    can you help me now?
    For some of my homework (one of many problems)
    "how to uploading file xls with asp mvc 3 to database? "
    share with me please, simple sample
    programming ASP MVC3
    Database SQL SERVER
    example databases name_DB = db_school, name_table = tbl_student, Field = - id, name

  • Thanks for detailed explanation. Before visiting to this page I didn't knew anything about file upload, Now i can write file upload code easily..

    Regards
    sid

  • I was not sure where the files were uploaded...
    So,I just got your code a little modified with d help of some other example:
    And here is the full running code:
    1.Just Create D:\Test\Upload directory structure or whatever.
    2.Copy this code to FileUploadController.java
    [code language="java"]
    package net.viralpatel.spring3.controller;

    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;

    import net.viralpatel.spring3.form.FileUploadForm;

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.multipart.MultipartFile;

    @Controller
    public class FileUploadController {
    private String saveDirectory = "D:/Test/Upload/"; //Here I Added

    @RequestMapping(value = "/show", method = RequestMethod.GET)
    public String displayForm() {
    return "file_upload_form";
    }

    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public String save(
    @ModelAttribute("uploadForm") FileUploadForm uploadForm,
    Model map) throws IllegalStateException, IOException {

    List<MultipartFile> files = uploadForm.getFiles();

    List<String> fileNames = new ArrayList<String>();

    if(null != files && files.size() > 0) {
    for (MultipartFile multipartFile : files) {

    String fileName = multipartFile.getOriginalFilename();
    fileNames.add(fileName);
    //Handle file content - multipartFile.getInputStream()
    multipartFile.transferTo(new File(saveDirectory + multipartFile.getOriginalFilename())); //Here I Added
    }
    }

    map.addAttribute("files", fileNames);
    return "file_upload_success";
    }
    }

    [/code]

    • when I copied your updated controller, the file is getting uploaded into the location. But, I'm getting this error. Please clarify.

      java.io.IOException: Destination file [C:\Temp\Upload] already exists and could not be deleted
      org.springframework.web.multipart.commons.CommonsMultipartFile.transferTo(CommonsMultipartFile.java:130)

      • I got the solution for the above exception. I just added a condition like this and added the files in the last step. Please see the code below:
        [code language="java"]
        if(null != files && files.size() > 0) {
        for (MultipartFile multipartFile : files) {

        String fileName = multipartFile.getOriginalFilename();
        if(!"".equalsIgnoreCase(fileName)){
        //Handle file content - multipartFile.getInputStream()
        multipartFile.transferTo(new File(saveDirectory + fileName)); //Here I Added
        fileNames.add(fileName);
        }
        }
        [/code]

Recent Posts

  • Java

Java URL Encoder/Decoder Example

Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…

4 years ago
  • General

How to Show Multiple Examples in OpenAPI Spec

Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…

4 years ago
  • General

How to Run Local WordPress using Docker

Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…

4 years ago
  • Java

Create and Validate JWT Token in Java using JJWT

1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…

4 years ago
  • Spring Boot

Spring Boot GraphQL Subscription Realtime API

GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…

4 years ago
  • Spring Boot

Spring Boot DynamoDB Integration Test using Testcontainers

1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…

4 years ago