🏠 ❯ Spring Boot ❯ Spring Boot file Upload with Examples

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.

  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 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.

A simple demonstration of a multipart form data request

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.

Useful methods from uploaded multipart files in Spring Boot
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 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=5KBCode 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=-1Code 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=trueCode 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 *

2 Comments

  1. 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?

    1. 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.