This guide walks you through the process of creating a server application that can receive HTTP multi-part file uploads.
You will create a Spring Boot web application that accepts file uploads. You will also build a simple HTML interface to upload a test file.
You can use this pre-initialized project and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.
To manually initialize the project:
-
Navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you.
-
Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java.
-
Click Dependencies and select Spring Web and Thymeleaf.
-
Click Generate.
-
Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.
Note
|
If your IDE has the Spring Initializr integration, you can complete this process from your IDE. |
Note
|
You can also fork the project from Github and open it in your IDE or other editor. |
To start a Spring Boot MVC application, you first need a starter. In this sample,
spring-boot-starter-thymeleaf
and spring-boot-starter-web
are already added as
dependencies. To upload files with Servlet containers, you need to register a
MultipartConfigElement
class (which would be <multipart-config>
in web.xml). Thanks to
Spring Boot, everything is auto-configured for you!
All you need to get started with this application is the following
UploadingFilesApplication
class (from
src/main/java/com/example/uploadingfiles/UploadingFilesApplication.java
):
link:initial/src/main/java/com/example/uploadingfiles/UploadingFilesApplication.java[role=include]
As part of auto-configuring Spring MVC, Spring Boot will create a MultipartConfigElement
bean and make itself ready for file uploads.
The initial application already contains a few classes to deal with storing and loading
the uploaded files on disk. They are all located in the
com.example.uploadingfiles.storage
package. You will use those in your new
FileUploadController
. The following listing (from
src/main/java/com/example/uploadingfiles/FileUploadController.java
) shows the file
upload controller:
link:complete/src/main/java/com/example/uploadingfiles/FileUploadController.java[role=include]
The FileUploadController
class is annotated with @Controller
so that Spring MVC can
pick it up and look for routes. Each method is tagged with @GetMapping
or @PostMapping
to tie the path and the HTTP action to a particular controller action.
In this case:
-
GET /
: Looks up the current list of uploaded files from theStorageService
and loads it into a Thymeleaf template. It calculates a link to the actual resource by usingMvcUriComponentsBuilder
. -
GET /files/{filename}
: Loads the resource (if it exists) and sends it to the browser to download by using aContent-Disposition
response header. -
POST /
: Handles a multi-part messagefile
and gives it to theStorageService
for saving.
Note
|
In a production scenario, you more likely would store the files in a temporary location, a database, or perhaps a NoSQL store (such as Mongo’s GridFS). It is best to NOT load up the file system of your application with content. |
You will need to provide a StorageService
so that the controller can interact with a
storage layer (such as a file system). The following listing (from
src/main/java/com/example/uploadingfiles/storage/StorageService.java
) shows that
interface:
link:complete/src/main/java/com/example/uploadingfiles//storage/StorageService.java[role=include]
You also need four classes to support the storage service:
link:complete/src/main/java/com/example/uploadingfiles//storage/StorageProperties.java[role=include]
link:complete/src/main/java/com/example/uploadingfiles//storage/StorageException.java[role=include]
link:complete/src/main/java/com/example/uploadingfiles//storage/StorageFileNotFoundException.java[role=include]
link:complete/src/main/java/com/example/uploadingfiles//storage/FileSystemStorageService.java[role=include]
The following Thymeleaf template (from src/main/resources/templates/uploadForm.html
)
shows an example of how to upload files and show what has been uploaded:
link:complete/src/main/resources/templates/uploadForm.html[role=include]
This template has three parts:
-
An optional message at the top where Spring MVC writes a flash-scoped message.
-
A form that lets the user upload files.
-
A list of files supplied from the backend.
When configuring file uploads, it is often useful to set limits on the size of files.
Imagine trying to handle a 5GB file upload! With Spring Boot, we can tune its
auto-configured MultipartConfigElement
with some property settings.
Add the following properties to your existing properties settings (in
src/main/resources/application.properties
):
link:complete/src/main/resources/application.properties[role=include]
The multipart settings are constrained as follows:
-
spring.servlet.multipart.max-file-size
is set to 128KB, meaning total file size cannot exceed 128KB. -
spring.servlet.multipart.max-request-size
is set to 128KB, meaning total request size for amultipart/form-data
cannot exceed 128KB.
You want a target folder to which to upload files, so you need to enhance the basic
UploadingFilesApplication
class that Spring Initializr created and add a Boot
CommandLineRunner
to delete and re-create that folder at startup. The following listing
(from src/main/java/com/example/uploadingfiles/UploadingFilesApplication.java
) shows how
to do so:
link:complete/src/main/java/com/example/uploadingfiles/UploadingFilesApplication.java[role=include]
https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_an_executable_jar_subhead.adoc https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_an_executable_jar_with_both.adoc
That runs the server-side piece that receives file uploads. Logging output is displayed. The service should be up and running within a few seconds.
With the server running, you need to open a browser and visit http://localhost:8080/
to
see the upload form. Pick a (small) file and press Upload. You should see the success
page from the controller. If you choose a file that is too large, you will get an ugly
error page.
You should then see a line resembling the following in your browser window:
“You successfully uploaded <name of your file>!”
There are multiple ways to test this particular feature in our application. The following
listing (from src/test/java/com/example/uploadingfiles/FileUploadTests.java
) shows one
example that uses MockMvc
so that it does not require starting the servlet container:
link:complete/src/test/java/com/example/uploadingfiles/FileUploadTests.java[role=include]
In those tests, you use various mocks to set up the interactions with your controller and
the StorageService
but also with the Servlet container itself by using
MockMultipartFile
.
For an example of an integration test, see the FileUploadIntegrationTests
class (which
is in src/test/java/com/example/uploadingfiles
).
Congratulations! You have just written a web application that uses Spring to handle file uploads.