- Spring Boot upload file to filesystem
- 2. Application Rest uploading API
- 3. Project structure
- 4. Setup Spring Boot application
- 5. Project classes
- 5.1. Create FileService for managing files
- 5.2. Create Model classes: FileData and UploadResponseMessage
- 5.3. Create FilesController main Rest controller for handing uploading and downloading files
- 5.4. Handle upload file exceptions
- 5.5. Create application.properties
- 6. Test Spring Boot upload file application
- 6.1. Uploding file
- 6.2. Get file list
- 6.3. Delete all files
- 6.4. Empty list after deleting all files
- 7. Conclusion
Spring Boot upload file to filesystem
In this article, we will show how to upload a file with Spring Boot to a folder located in the filesystem. We will use Spring MultipartFile interface to handle multi-part requests to our Rest API.
2. Application Rest uploading API
Spring Boot application server will provide API with the following endpoints:
URL | Method | Action |
/files | GET | Get list of uploaded files |
/files | POST | Upload a single file |
/files | DELETE | Delete all uploaded files |
/files/ | GET | Download specific file |
Files will be uploaded into the specific static folder which will be configured in the application.properties .
3. Project structure
The following presents a Maven project structure of the upload file application:
├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── frontbackend │ │ │ └── springboot │ │ │ ├── Application.java │ │ │ ├── controller │ │ │ │ └── FilesController.java │ │ │ ├── exceptions │ │ │ │ └── RestExceptionHandler.java │ │ │ ├── model │ │ │ │ ├── FileData.java │ │ │ │ └── UploadResponseMessage.java │ │ │ └── service │ │ │ └── FileService.java │ │ └── resources │ │ └── application.properties
In this structure the following elements can be distinguished:
- pom.xml is a Maven configuration file with all necessary dependencies,
- Application — the main Spring Boot class that starts the application server,
- FilesController — class that handle HTTP requests,
- FileService — service class responsible for saving uploaded file in the filesystem and retrieving uploaded files,
- RestExceptionHandler — handles MaxUploadSizeExceededException when processing file (could be extended with other exceptions as well),
- FileData — contains information about the uploaded file like name, size, location,
- application.properties — Spring Boot application properties with a path for uploaded files.
4. Setup Spring Boot application
To create a Spring Boot project from scratch we could use Initializer or other development tools available in Eclipse or IntelliJ.
The pom.xml has the following structure:
4.0.0 com.frontbackend.springboot upload-file-into-filesystem 0.0.1-SNAPSHOT org.springframework.boot spring-boot-starter-parent 2.1.5.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-maven-plugin
We added spring-boot-starter-web dependency and used spring-boot-maven-plugin plugin to create a jar executable file in /target folder.
5. Project classes
5.1. Create FileService for managing files
The FileService will be responsible for saving and downloading files from the path provided in application.properties . We used a method annotated with @PostConstruct that will create an empty directory (if it does not exist already) at the start of the Spring Boot server.
package com.frontbackend.springboot.service; import java.io.IOException; import java.net.MalformedURLException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.util.FileSystemUtils; import org.springframework.web.multipart.MultipartFile; @Service public class FileService < @Value("$") private String uploadPath; @PostConstruct public void init() < try < Files.createDirectories(Paths.get(uploadPath)); >catch (IOException e) < throw new RuntimeException("Could not create upload folder!"); >> public void save(MultipartFile file) < try < Path root = Paths.get(uploadPath); if (!Files.exists(root)) < init(); >Files.copy(file.getInputStream(), root.resolve(file.getOriginalFilename())); > catch (Exception e) < throw new RuntimeException("Could not store the file. Error: " + e.getMessage()); >> public Resource load(String filename) < try < Path file = Paths.get(uploadPath) .resolve(filename); Resource resource = new UrlResource(file.toUri()); if (resource.exists() || resource.isReadable()) < return resource; >else < throw new RuntimeException("Could not read the file!"); >> catch (MalformedURLException e) < throw new RuntimeException("Error: " + e.getMessage()); >> public void deleteAll() < FileSystemUtils.deleteRecursively(Paths.get(uploadPath) .toFile()); >public List loadAll() < try < Path root = Paths.get(uploadPath); if (Files.exists(root)) < return Files.walk(root, 1) .filter(path ->!path.equals(root)) .collect(Collectors.toList()); > return Collections.emptyList(); > catch (IOException e) < throw new RuntimeException("Could not list the files!"); >> >
5.2. Create Model classes: FileData and UploadResponseMessage
The model layer will contain:
- FileData — object with field like filename, url(to download file) and size,
- UploadResponseMessage — will be used to return information about how uploading process ran.
package com.frontbackend.springboot.model; public class FileData < private String filename; private String url; private Long size; public String getFilename() < return filename; >public void setFilename(String filename) < this.filename = filename; >public String getUrl() < return url; >public void setUrl(String url) < this.url = url; >public Long getSize() < return size; >public void setSize(Long size) < this.size = size; >>
The UploadResponseMessage class will be used in FilesController and RestExceptionHandler .
package com.frontbackend.springboot.model; public class UploadResponseMessage < private final String responseMessage; public UploadResponseMessage(String responseMessage) < this.responseMessage = responseMessage; >public String getResponseMessage() < return responseMessage; >>
5.3. Create FilesController main Rest controller for handing uploading and downloading files
In the controller package, we created the FilesController class that will be responsible for handing all POST, GET, and DELETE requests to /files endpoint.
package com.frontbackend.springboot.controller; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import com.frontbackend.springboot.model.FileData; import com.frontbackend.springboot.model.UploadResponseMessage; import com.frontbackend.springboot.service.FileService; @RestController @RequestMapping("files") public class FilesController < private final FileService fileService; @Autowired public FilesController(FileService fileService) < this.fileService = fileService; >@PostMapping public ResponseEntity uploadFile(@RequestParam("file") MultipartFile file) < try < fileService.save(file); return ResponseEntity.status(HttpStatus.OK) .body(new UploadResponseMessage("Uploaded the file successfully: " + file.getOriginalFilename())); >catch (Exception e) < return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED) .body(new UploadResponseMessage("Could not upload the file: " + file.getOriginalFilename() + "!")); >> @GetMapping public ResponseEntity> getListFiles() < ListfileInfos = fileService.loadAll() .stream() .map(this::pathToFileData) .collect(Collectors.toList()); return ResponseEntity.status(HttpStatus.OK) .body(fileInfos); > @DeleteMapping public void delete() < fileService.deleteAll(); >private FileData pathToFileData(Path path) < FileData fileData = new FileData(); String filename = path.getFileName() .toString(); fileData.setFilename(filename); fileData.setUrl(MvcUriComponentsBuilder.fromMethodName(FilesController.class, "getFile", filename) .build() .toString()); try < fileData.setSize(Files.size(path)); >catch (IOException e) < e.printStackTrace(); throw new RuntimeException("Error: " + e.getMessage()); >return fileData; > @GetMapping("") @ResponseBody public ResponseEntity getFile(@PathVariable String filename) < Resource file = fileService.load(filename); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"") .body(file); >>
This class has some interesting annotations:
- @RestController — annotation is used to define a Rest controller,
- @GetMapping , @PostMapping and @DeleteMapping — annotation is for handing HTTP GET, POST and DELETE requests with specific class methods:
5.4. Handle upload file exceptions
The class annotated with @ControllerAdvice is responsible for handling specific exceptions that may occur during uploading/downloading files. RestExceptionHandler class beside the special annotation should also extend RestExceptionHandler . To handle the exception when uploading too large files we need to handle MaxUploadSizeExceededException like in the following:
package com.frontbackend.springboot.exceptions; import com.frontbackend.springboot.model.UploadResponseMessage; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.multipart.MaxUploadSizeExceededException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; @ControllerAdvice public class RestExceptionHandler extends ResponseEntityExceptionHandler < @ExceptionHandler(MaxUploadSizeExceededException.class) public ResponseEntityhandleMaxSizeException(MaxUploadSizeExceededException exc) < return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED) .body(new UploadResponseMessage("Unable to upload. File is too large!")); >>
Note that we could also handle other exceptions that may occur during processing requests.
5.5. Create application.properties
To define the maximum file size that could be uploaded we need to add the following entries in the application.properties :
upload.path=/uploads spring.servlet.multipart.max-file-size=700KB spring.servlet.multipart.max-request-size=700KB
spring.servlet.multipart.max-file-size — this is the maximum file size for each request, spring.servlet.multipart.max-request-size — the maximum request size for a multipart/form-data.
Additionally, we added the upload.path custom parameter to define our root folder where all the files will be uploaded. This parameter is used in the FileService class.
6. Test Spring Boot upload file application
Find upload-file-into-filesystem-0.0.1-SNAPSHOT.jar in the target folder and Start Spring Boot application by running java -jar upload-file-into-filesystem-0.0.1-SNAPSHOT.jar .
You should see a message similar to this: Started Application in 1.625 seconds (JVM running for 1.98) . That means the server started successfully.
To test our uploading/downloading API we used Postman.
6.1. Uploding file
Uploading files returns information about the wrapped in UploadResponseMessage object.
6.2. Get file list
6.3. Delete all files
Deleting files will just return HTTP 200 status when successful.
6.4. Empty list after deleting all files
When the upload folder is empty we will get an empty collection on GET request.
7. Conclusion
In this tutorial, we presented how to create a simple Spring Boot application for uploading and downloading files to/from a static folder located somewhere in the filesystem. The application provides a Rest API without any front-end, that’s why we tested how it works using Postman tool.
As usual code used in this tutorial is available on our GitHub repository.