File Upload with Spring MVC

1. Overview

In previous articles, we introduced the basics of form handling and explored the form tag library in Spring MVC.

In this article, we focus on what Spring offers for multipart (file upload) support in web applications.

Spring allows us to enable this multipart support with pluggable MultipartResolver objects. The framework provides one MultipartResolver implementation for use with Commons FileUpload and another for use with Servlet 3.0 multipart request parsing.

After configuring the MultipartResolver we’ll see how to upload a single file and multiple files.

We’ll also touch on Spring Boot.

2. Commons FileUpload

To use CommonsMultipartResolver to handle the file upload, we need to add the following dependency:

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

Now we can define the CommonsMultipartResolver bean into our Spring configuration.

This MultipartResolver comes with a series of set method to define properties such as the maximum size for uploads:

@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(100000);
    return multipartResolver;
}

Here we need to control different properties of CommonsMultipartResolver in the Bean definition itself.

3. With Servlet 3.0

In order to use Servlet 3.0 multipart parsing, we need to configure a couple pieces of the application. First, we need to set a MultipartConfigElement in our DispatcherServlet registration:

public class MainWebAppInitializer implements WebApplicationInitializer {

    private String TMP_FOLDER = "/tmp"; 
    private int MAX_UPLOAD_SIZE = 5 * 1024 * 1024; 
    
    @Override
    public void onStartup(ServletContext sc) throws ServletException {
        
        ServletRegistration.Dynamic appServlet = sc.addServlet("mvc", new DispatcherServlet(
          new GenericWebApplicationContext()));

        appServlet.setLoadOnStartup(1);
        
        MultipartConfigElement multipartConfigElement = new MultipartConfigElement(TMP_FOLDER, 
          MAX_UPLOAD_SIZE, MAX_UPLOAD_SIZE * 2, MAX_UPLOAD_SIZE / 2);
        
        appServlet.setMultipartConfig(multipartConfigElement);
    }
}

In the MultipartConfigElement object, we have configured the storage location, maximum individual file size, maximum request size (in the case of multiple files in a single request), and the size at which the file upload progress is flushed to the storage location.

These settings must be applied at the servlet registration level, as Servlet 3.0 does not allow them to be registered in the MultipartResolver as is the case with CommonsMultipartResolver.

Once this is done, we can add the StandardServletMultipartResolver to our Spring configuration:

@Bean
public StandardServletMultipartResolver multipartResolver() {
    return new StandardServletMultipartResolver();
}

4. Uploading a File

To upload our file, we can build a simple form in which we use an HTML input tag with type=’file’.

Regardless of the upload handling configuration, we have chosen, we need to set the encoding attribute of the form to multipart/form-data. This lets the browser know how to encode the form:

<form:form method="POST" action="/spring-mvc-xml/uploadFile" enctype="multipart/form-data">
    <table>
        <tr>
            <td><form:label path="file">Select a file to upload</form:label></td>
            <td><input type="file" name="file" /></td>
        </tr>
        <tr>
            <td><input type="submit" value="Submit" /></td>
        </tr>
    </table>
</form>

To store the uploaded file we can use a MultipartFile variable. We can retrieve this variable from the request parameter inside our controller’s method:

@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
public String submit(@RequestParam("file") MultipartFile file, ModelMap modelMap) {
    modelMap.addAttribute("file", file);
    return "fileUploadView";
}

The MultipartFile class provides access to details about the uploaded file, including file name, file type, and so on. We can use a simple HTML page to display this information:

<h2>Submitted File</h2>
<table>
    <tr>
        <td>OriginalFileName:</td>
        <td>${file.originalFilename}</td>
    </tr>
    <tr>
        <td>Type:</td>
        <td>${file.contentType}</td>
    </tr>
</table>

5. Uploading Multiple Files

To upload multiple files in a single request, we simply put multiple input file fields inside the form:

<form:form method="POST" action="/spring-mvc-java/uploadMultiFile" enctype="multipart/form-data">
    <table>
        <tr>
            <td>Select a file to upload</td>
            <td><input type="file" name="files" /></td>
        </tr>
        <tr>
            <td>Select a file to upload</td>
            <td><input type="file" name="files" /></td>
        </tr>
        <tr>
            <td>Select a file to upload</td>
            <td><input type="file" name="files" /></td>
        </tr>
        <tr>
            <td><input type="submit" value="Submit" /></td>
        </tr>
    </table>
</form:form>

We need to take care that each input field has the same name so that it can be accessed as an array of MultipartFile:

@RequestMapping(value = "/uploadMultiFile", method = RequestMethod.POST)
public String submit(@RequestParam("files") MultipartFile[] files, ModelMap modelMap) {
    modelMap.addAttribute("files", files);
    return "fileUploadView";
}

Now, we can simply iterate over that array to display files information:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>Spring MVC File Upload</title>
    </head>
    <body>
        <h2>Submitted Files</h2>
        <table>
            <c:forEach items="${files}" var="file">    
                <tr>
                    <td>OriginalFileName:</td>
                    <td>${file.originalFilename}</td>
                </tr>
                <tr>
                    <td>Type:</td>
                    <td>${file.contentType}</td>
                </tr>
            </c:forEach>
        </table>
    </body>
</html>

6. Uploading Files With Additional Form Data

We can also send additional information to the server along with the file being uploaded. We just have to include the required fields in the form:

<form:form method="POST" 
  action="/spring-mvc-java/uploadFileWithAddtionalData"
  enctype="multipart/form-data">
    <table>
        <tr>
            <td>Name</td>
            <td><input type="text" name="name" /></td>
        </tr>
        <tr>
            <td>Email</td>
            <td><input type="text" name="email" /></td>
        </tr>
        <tr>
            <td>Select a file to upload</td>
            <td><input type="file" name="file" /></td>
        </tr>
        <tr>
            <td><input type="submit" value="Submit" /></td>
        </tr>
    </table>
</form:form>

In the controller, we can get all the form data using the @RequestParam annotation:

@PostMapping("/uploadFileWithAddtionalData")
public String submit(
  @RequestParam MultipartFile file, @RequestParam String name,
  @RequestParam String email, ModelMap modelMap) {

    modelMap.addAttribute("name", name);
    modelMap.addAttribute("email", email);
    modelMap.addAttribute("file", file);
    return "fileUploadView";
}

Similar to previous sections, we can use the HTML page with JSTL tags to display the information.

We can also encapsulate all the form fields in a model class and use @ModelAttribute annotation in the controller. This would be helpful when there’s a lot of additional fields along with the file. Let’ look at the code:

public class FormDataWithFile {

    private String name;
    private String email;
    private MultipartFile file;

    // standard getters and setters
}
@PostMapping("/uploadFileModelAttribute")
public String submit(@ModelAttribute FormDataWithFile formDataWithFile, ModelMap modelMap) {

    modelMap.addAttribute("formDataWithFile", formDataWithFile);
    return "fileUploadView";
}

7. Spring Boot File Upload

If we’re using Spring Boot, everything we’ve seen so far still applies.

However, Spring Boot makes it even easier to configure and start everything with little hassle.

In particular, it’s not necessary to configure any servlet, as Boot will register and configure it for us, provided that we include the web module in our dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.1.8.RELEASE</version>
</dependency>

We can find the latest version of spring-boot-starter-web on Maven Central.

If we want to control the maximum file upload size, we can edit our application.properties:

spring.servlet.multipart.max-file-size=128KB
spring.servlet.multipart.max-request-size=128KB

We can also control whether file uploading is enabled, and the location for file upload:

spring.servlet.multipart.enabled=true
spring.servlet.multipart.location=${java.io.tmpdir}

Note that we’ve used ${java.io.tmpdir} to define the upload location so that we can use the temporary location for different operating systems.

8. Conclusion

In this article, we looked at different ways to configure multipart support in Spring. Using these, we can support file uploads in our web applications.

The implementation of this tutorial can be found in a GitHub project. When the project runs locally, the form example can be accessed at http://localhost:8080/spring-mvc-java/fileUpload