The Tech Series articles are aimed at anyone interested in Software development and deployment from beginners to professionals.
In this article we explore how large file uploads can be efficiently handled using the Streaming API of the Apache Commons FileUpload library. A typical use case could be to allow a user to upload a large file to your website which would then be persisted in cloud storage such as Amazon S3 Simple storage using a file stream.
Implementation
Initial project setup
The implementation is based on the Java Spring - Uploading Files - Getting Started guide and the eclipse neon 3 Java IDE.
Therefore, the first thing we need to do is to open eclipse and retrieve the code. This can be achieved by using the wizard which can be accessed by the following menu item: File > Import Spring Getting Started Content and selecting the Uploading Files guide.
Note, you need to ensure that the Spring Tool Suite (STS) is installed by using the Eclipse Marketplace (menu item: Help > Eclipse Marketplace...)
Alternatively, if you prefer you can clone the online repository by issuing the following command:
git clone https://github.com/spring-guides/gs-uploading-files.git
The next step is to build and run the project to verify a basic upload works. Visit the uploading files getting started guide page if more information is required about getting the project up and running. Once you have verified that the project is working you are ready to start making the amends necessary to incorporate the Apache Commons Streaming API to facilitate efficient handling of large file uploads.
Apache Commons FileUpload Streaming API example
In order to disable the default multi-part upload handling add the following line to src/main/resources/application.properties:
spring.http.multipart.enabled=false
Add the following dependencies to pom.xml for Apache Commons File Upload:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
Replace the handleFileUpload method with the following snippet:
@PostMapping("/")
public String handleFileUpload(final HttpServletRequest request, RedirectAttributes redirectAttributes) {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
// consider raising an error here if desired
}
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter;
InputStream fileStream = null;
String name = null;
try {
// retrieve the multi-part constituent items parsed from the request
iter = upload.getItemIterator(request);
// loop through each item
while (iter.hasNext()) {
FileItemStream item = iter.next();
name = item.getName();
fileStream = item.openStream();
// check if the item is a file
if (!item.isFormField()) {
System.out.println("File field " + name + " with file name " + item.getName() + " detected.");
break; // break here so that the input stream can be processed
}
}
} catch (FileUploadException | IOException e) {
// log / handle the error here as necessary
e.printStackTrace();
}
if (fileStream != null) {
// a file has been sent in the http request
// pass the fileStream to a method on the storageService so it can be persisted
// note the storageService will need to be modified to receive and process the fileStream
storageService.store(fileStream, name);
}
redirectAttributes.addFlashAttribute("message", "You successfully uploaded " + name + "!");
return "redirect:/";
}
Conclusion & Further Reading
We have demonstrated how the Apache Commons FileUpload Streaming API can be used to directly access the incoming file stream from a http multi-part POST request. You have control of when a file is created on the server side (if at all) so disk space and memory consumption can be minimised.
If you wish to learn more about about any of the file upload related code mentioned in this article then check out the following: