Spring and Apache FileUpload

1. Overview

The Apache Commons File Upload Library helps us upload large files over the HTTP protocol using the multipart/form-data content type.

In this quick tutorial, we’re going to take a look at how to integrate it with Spring.

2. Maven Dependencies

To use the library, we’ll need the commons-fileupload artifact:

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

The latest version can be found on Maven Central.

3. Transfering All at Once

For demonstration purposes, we’re going to create a Controller processing requests with a file payload:

@PostMapping("/upload")
public String handleUpload(HttpServletRequest request) throws Exception {
    boolean isMultipart = ServletFileUpload.isMultipartContent(request);

    DiskFileItemFactory factory = new DiskFileItemFactory();
    factory.setRepository(
      new File(System.getProperty("java.io.tmpdir")));
    factory.setSizeThreshold(
      DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD);
    factory.setFileCleaningTracker(null);

    ServletFileUpload upload = new ServletFileUpload(factory);

    List items = upload.parseRequest(request);

    Iterator iter = items.iterator();
    while (iter.hasNext()) {
        FileItem item = iter.next();

        if (!item.isFormField()) {
            try (
              InputStream uploadedStream = item.getInputStream();
              OutputStream out = new FileOutputStream("file.mov");) {

                IOUtils.copy(uploadedStream, out);
            }
        }
    }
    return "success!";
}

In the beginning, we need to check if the request contains a multipart content using the isMultipartContent method found in the ServletFileUpload class from the library.

By default, Spring features a MultipartResolver that we’ll need to disable to use this library. Otherwise, it’ll read the content of the request before it reaches our Controller.

We can achieve this by including this configuration in our application.properties file:

spring.http.multipart.enabled=false

Now, we can set the directory where our files are going to be saved, the threshold in which the library decides to write to disk and if files should be deleted after the request ends.

The library provides a DiskFileItemFactory class that _ takes the responsibility of the configuration for the file saving and cleaning. The _setRepository method sets the target directory, with the default being shown in the example.

Next, the setSizeThreshold sets a maximum file size.

Then, we have the setFileCleaningTracker method that, when set to null, leaves the temporary files untouched. By default, it deletes them after the request has finished.

Now we can continue to the actual file handling.

First, we create our ServletFileUpload by including our previously created factory; then we proceed to parse the request and generate a list of FileItem which are the main abstraction of the library for the form fields.

Now if we know it isn’t a normal form field, then we proceed to extract the InputStream and to call the useful copy method from IOUtils (for more options you can have a look at this tutorial).

Now we have our file stored in the necessary folder. This is usually a more convenient way to handle this situation as it allows easy access to the files, but also time/memory efficiency isn’t optimal.

In the next section, we’re going to take a look at the streaming API.

4. Streaming API

The streaming API is easy to use, making it a great way to process large files simply by not copying to a temporary location:

ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iterStream = upload.getItemIterator(request);
while (iterStream.hasNext()) {
    FileItemStream item = iterStream.next();
    String name = item.getFieldName();
    InputStream stream = item.openStream();
    if (!item.isFormField()) {
        // Process the InputStream
    } else {
        String formFieldValue = Streams.asString(stream);
    }
}

We can see in the previous code snippet that we no longer include a DiskFileItemFactory. This is because, when using the streaming API, we don’t need it.

Next, to process fields, the library provides a FileItemIterator, which doesn’t read anything until we extract them from the request with the next method.

Finally, we can see how to obtain the values of the other form fields.

5. Conclusion

In this article, we’ve reviewed how we can use the Apache Commons File Upload Library with Spring to upload and process large files.

As always the full source code can be found over at GitHub.

Leave a Reply

Your email address will not be published.