🏠Spring BootSpring Boot file Upload with Examples

Spring Boot file Upload with Examples

Spring Boot

In this post we will see how to upload single or multiple files in Spring Boot using MVC features of the WEB starter.

What is a multipart File Upload request?

There are three types of payloads in POST request.

  1. The Request Body is a bunch of URL-encoded parameters
  2. The Request Body is RAW/Binary content. (Example JSON)
  3. The Request Body is a mixture of parameters and RAW content. (Multipart Form Data)

For this post, I’ll be concentrating more towards the 3rd type. A post request will be called multipart request if its body content is split using a specific boundary or delimiter. These delimiter will mark where a single parameter start and end.

For example Take a look at this below form.

If this form was submitted, then the server would receive the HTTP request in the form below.

POST /v3/ed8d9ae2-7d0d-4411-8b8c-66106d8a2721 HTTP/1.1 Host: run.mocky.io Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW Cache-Control: no-cache Postman-Token: 55480fab-4fc3-26e2-fde0-19cc88f8d73e ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="hello" world ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="hotel" trivago ------WebKitFormBoundary7MA4YWxkTrZu0gW--
Code language: HTTP (http)

Now try to fit the exact values in the request and the above screenshot. The first thing to give attention to here is the Content-Type header. It marks the request as multipart and the boundary between each parameter is ----WebKitFormBoundary7MA4YWxkTrZu0gW. When the server receives this information, it can easily split the body of the request and will get the name of each parameter and their appropriate values.

With this setup, If one parameter is a file itself, we can simply encode it within a boundary. If I add a file parameter to the above request, then the request body would look like this.

POST /v3/ed8d9ae2-7d0d-4411-8b8c-66106d8a2721 HTTP/1.1 Host: run.mocky.io Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW Cache-Control: no-cache Postman-Token: e139ea1a-1f88-ae45-72c6-867ab4a12209 ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="hello" world ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="hotel" trivago ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="myfile"; filename="hello-world.txt" Content-Type: text/plain Hello world from a file ------WebKitFormBoundary7MA4YWxkTrZu0gW--
Code language: HTTP (http)

Notice how there is a new Part in the request along with the content of the file added to the body. With this knowledge let’s write some code.

Uploading Single file

Let’s say we have a parameter in our request that we want to use in our controller method. For example, a request contains a parameter called count and it is an integer. So the controller method parameter will be @RequestParam("count") Integer count. In this example, Integer is the appropriate type for storing the parameter count.

Similarly, Spring MVC provides a MultipartFile to hold the content of the file. So here is my simple example that takes file as the parameter.

@RequestMapping(value = "/file-upload", method = RequestMethod.POST) @ResponseBody public String uploadFile(@RequestParam("myFile") MultipartFile multipartFile) throws IOException { multipartFile.transferTo(new File("C:\\data\\test\\" + multipartFile.getOriginalFilename())); return "success"; }
Code language: Java (java)

In this example, the parameter name itself is myFile. Also, I am writing the file content to my local disk. It is up to you what you want to do with the MultipartFile object. These are the methods available part of the multipart file if you are interested.

helpful Methods from MultipartFile class

Uploading two files

This is easy. Just add another parameter with different @RequestParam.

@RequestMapping(value = "/two-file-upload", method = RequestMethod.POST) @ResponseBody public String uploadTwoFile(@RequestParam("myFile") MultipartFile multipartFile, @RequestParam("myOtherFile") MultipartFile otherMultipartFile) throws IOException { multipartFile.transferTo(new File("C:\\data\\test\\" + multipartFile.getOriginalFilename())); otherMultipartFile.transferTo(new File("C:\\data\\test\\" + otherMultipartFile.getOriginalFilename())); return "success"; }
Code language: Java (java)

Multiple files upload In Spring Boot

Spring MVC processes same parameter with different values into an array or collection. This is true for multipart file parameters as well. If you have to upload countably many number of files without hard coding each file parameter name, this is the way to go.

@RequestMapping(value = "/multiple-file-upload", method = RequestMethod.POST) @ResponseBody public String uploadMultipleFiles(@RequestParam("myFiles") MultipartFile[] multipartFiles) throws IOException { for (MultipartFile multipartFile : multipartFiles) { multipartFile.transferTo(new File("C:\\data\\test\\" + multipartFile.getOriginalFilename())); } return "success"; }
Code language: Java (java)

Limit multipart file size

Yes. You can limit the maximum file size that can be uploaded to your system. For this we don’t even have to write any piece of code. The following property will let the client upload files of size below 5KB.

spring.servlet.multipart.max-file-size=5KB
Code language: Properties (properties)

Any request with files above 5KB will get a 500 internal server error with a org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException as shown below.

2020-11-14 00:31:14.227 ERROR 16596 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field myFiles exceeds its maximum permitted size of 5120 bytes.] with root cause org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field myFiles exceeds its maximum permitted size of 5120 bytes. at org.apache.tomcat.util.http.fileupload.impl.FileItemStreamImpl$1.raiseError(FileItemStreamImpl.java:114) ~[tomcat-embed-core-9.0.39.jar:9.0.39] at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.checkLimit(LimitedInputStream.java:76) ~[tomcat-embed-core-9.0.39.jar:9.0.39] at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:135) ~[tomcat-embed-core-9.0.39.jar:9.0.39] at java.io.FilterInputStream.read(FilterInputStream.java:107) ~[na:1.8.0_221]
Code language: Java (java)

Note that the default value for this configuration is 1MB

Unlimited Upload Size

Even though it is a generally a bad idea, You can set the upload size to unlimited by setting the max-file-size to -1.

spring.servlet.multipart.max-file-size=-1 spring.servlet.multipart.max-request-size=-1
Code language: Properties (properties)

if you are still using spring boot version 1.x, you should use spring.http instead of spring.servlet for these properties.

Consider using lazy parsing

Spring MVC parses all multipart requests immediately. If the parsed files may or may not be used further, it is better to defer the parsing only if the file is actually being used. This way we can save CPU usage. For this behaviour, you need to add the following configuration to the application properties.

spring.servlet.multipart.resolve-lazily=true
Code language: Properties (properties)

The source code for all the above examples is available in the GitHub link below. Please feel free to drop a comment below if you want to add something to this topic or if you have any questions.

Conclusion

To wrap it up, we learned various ways you can provide an endpoint to upload files in spring boot applications. If you liked this topic, you may also like the following ones.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *