Spring Boot file Upload with Examples
In this post, we will see how to upload single or multiple files in Spring Boot using the MVC features of the WEB starter.
What is a multipart File Upload request?
There are three types of payloads in POST requests.
- The Request Body is a bunch of
URL-encoded
parameters - The Request Body is RAW/Binary content. (Example JSON)
- The Request Body is a mixture of parameters and RAW content. (Multipart Form Data)
For this post, I’ll be concentrating more on the 3rd type. A post request will be called a multipart request if its body content is split using a specific boundary or delimiter. This delimiter will mark where a single parameter starts and ends.
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 a 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.
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 the 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 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 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 behavior, 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.
Very best. You showed how timplement SpringBoot web controller to
Upload single file
upload many file
use of transferTo() method to store the file.
use configurations to configure upload files like size alllowed to upload, lazy parsing of file and etc.
Overall it is the one the best example specific to file upload.
Thank you for the post, all nicely explained. I’d like to know how to add additional fields to the uploaded file, like a title and a description. (Like a product with an image). And return the complete object in the controller. Can you tell me how to?
As MultipartFile is part of the FormData specification, you could send more fields as form values. For example, You could use `@RequestParam(“comments”) String comments` to pass the comment to the controller. And how you want to store and send the response is up to you.