Upload files in Spring Boot application using Commons FileUpload

In our previous post, we saw how to upload a file using the Spring framework’s default implementation for MultipartFile interface. In this post, we will see how we can use the Commons FileUpload library and the wrapper implementation CommonsMultipartFile provided by the Spring framework.

Update the pom.xml

We will update the maven dependencies to include commons-io and commons-fileupload. We will use the FilenameUtils class in commons-io to normalize the file name of the uploaded file.

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

Configuring CommonsMultipartResolver

The HTML is going to be the same as shown in the post here. For the Spring framework to make use of Commons FileUpload we need to configure CommonsMultipartResolver and expose it as a @Bean as shown below:

@Value("${spring.servlet.multipart.max-file-size}") String maxFileSize;
@Value("${spring.servlet.multipart.max-request-size}") String maxRequestSize;

@Bean
public CommonsMultipartResolver commonsMultipartResolver(){
  CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
  commonsMultipartResolver.setMaxUploadSize(DataSize.parse(maxRequestSize).toBytes());
  commonsMultipartResolver.setMaxUploadSizePerFile(DataSize.parse(maxFileSize).toBytes());
  return commonsMultipartResolver;
}

We would be making use of the Spring Boot’s max file size and max request size attributes to configure the CommonsMultipartResolver.

Implement file copy using CommonsMultipart

In our FileService class we will provide a new method copyFileUsingCommons as shown below:

@Value("${app.document-root}")String documentRoot;

public void copyFileUsingCommons(List<CommonsMultipartFile> uploadedFiles) throws IOException{
  try {
    Path docRootPath = Path.of(documentRoot);
    if ( !Files.exists(docRootPath)){
      Files.createDirectory(docRootPath);
    }
    for (CommonsMultipartFile multipartFile : uploadedFiles) {
      log.debug("Multipart storage location {}", multipartFile.getStorageDescription());
      copy(multipartFile);
    }
  } catch (IOException e) {
    log.error("Error occurred while copying file", e);
    throw e;
  }
}


private void copy(MultipartFile multipartFile) throws IOException{
  String fileName = multipartFile.getOriginalFilename();
  String normalizedFileName = FilenameUtils.normalize(fileName);
  multipartFile.transferTo(Path.of(documentRoot, normalizedFileName));
}

By default commons file upload keeps the file whose size <= 10KB in memory and those > 10KB are moved to a temporary directory on the server before they are copied to the required destination. This limit can be changed while configuring the CommonsMultipartResolver.

By default the Spring’s implementation of MultipartFile writes all files to temporary directory. And this can be controlled by changing the value of the property: spring.servlet.multipart.file-size-threshold in your application.properties file

Update the file upload API

Finally we will update the file upload API to accept parameter of type List<CommonsMultipartFile> and to use the new method copyFileUsingCommons:

@PostMapping("/upload")
public ResponseEntity<?> handleFileUpload(
      @RequestParam("uploaded-file") List<CommonsMultipartFile> uploadedFiles)
  throws IOException {
  log.debug("Uploaded files size : {}", uploadedFiles.size());
  fileService.copyFileUsingCommons(uploadedFiles);
  return ResponseEntity.ok().build();
}

The StandardMultipartFile implementation uses javax.servlet.http.Part to represent the parts of the file uploaded by the user whereas CommonsMultipartFile implementation uses org.apache.commons.fileupload.FileItem to represent the parts of file uploaded by the user.

The complete code can be found in the GitHub project here.



Categories: Spring, Spring Boot

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: