Get the File Path of Upload File
ane. Introduction
In this article, we will show how to upload a file with Spring Boot to a binder located in the filesystem. Nosotros will use Spring MultipartFile
interface to handle multi-part requests to our Balance API.
2. Application Balance uploading API
Spring Boot application server will provide API with the following endpoints:
URL | Method | Activeness |
/files | GET | Get list of uploaded files |
/files | Mail service | Upload a single file |
/files | DELETE | Delete all uploaded files |
/files/{filename} | Become | Download specific file |
Files will be uploaded into the specific static binder which volition be configured in the application.properties
.
3. Projection 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.coffee │ │ │ ├── model │ │ │ │ ├── FileData.java │ │ │ │ └── UploadResponseMessage.coffee │ │ │ └── service │ │ │ └── FileService.coffee │ │ └── resources │ │ └── application.properties
In this structure the following elements can be distinguished:
-
pom.xml
is a Maven configuration file with all necessary dependencies, -
Awarding
- the main Leap 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
- handlesMaxUploadSizeExceededException
when processing file (could be extended with other exceptions as well), -
FileData
- contains information about the uploaded file like proper name, size, location, -
application.properties
- Spring Boot awarding properties with a path for uploaded files.
4. Setup Bound Boot application
To create a Leap Boot projection from scratch we could apply Initializer or other development tools available in Eclipse or IntelliJ.
The pom.xml
has the following structure:
<?xml version="one.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://world wide web.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>four.0.0</modelVersion> <groupId>com.frontbackend.springboot</groupId> <artifactId>upload-file-into-filesystem</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- Inherit defaults from Spring Boot --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>bound-kicking-starter-parent</artifactId> <version>2.1.v.RELEASE</version> </parent> <!-- Add typical dependencies for a web application --> <dependencies> <dependency> <groupId>org.springframework.kicking</groupId> <artifactId>spring-kicking-starter-web</artifactId> </dependency> </dependencies> <!-- Package as an executable jar --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-kicking-maven-plugin</artifactId> </plugin> </plugins> </build> </projection>
We added spring-boot-starter-web
dependency and used bound-boot-maven-plugin
plugin to create a jar executable file in /target
folder.
v. Project classes
v.1. Create FileService
for managing files
The FileService
will exist 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 non be already) at the start of the Jump Kick server.
package com.frontbackend.springboot.service; import coffee.io.IOException; import coffee.net.MalformedURLException; import java.nio.file.Files; import java.nio.file.Path; import coffee.nio.file.Paths; import coffee.util.Collections; import coffee.util.Listing; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.springframework.beans.mill.annotation.Value; import org.springframework.core.io.Resources; import org.springframework.cadre.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.util.FileSystemUtils; import org.springframework.web.multipart.MultipartFile; @Service public class FileService { @Value("${upload.path}") private String uploadPath; @PostConstruct public void init() { try { Files.createDirectories(Paths.get(uploadPath)); } catch (IOException e) { throw new RuntimeException("Could not create upload binder!"); } } public void save(MultipartFile file) { try { Path root = Paths.get(uploadPath); if (!Files.exists(root)) { init(); } Files.re-create(file.getInputStream(), root.resolve(file.getOriginalFilename())); } catch (Exception e) { throw new RuntimeException("Could not store the file. Error: " + eastward.getMessage()); } } public Resource load(String filename) { endeavour { Path file = Paths.go(uploadPath) .resolve(filename); Resource resources = new UrlResource(file.toUri()); if (resource.exists() || resource.isReadable()) { render resources; } else { throw new RuntimeException("Could non read the file!"); } } grab (MalformedURLException east) { throw new RuntimeException("Error: " + eastward.getMessage()); } } public void deleteAll() { FileSystemUtils.deleteRecursively(Paths.get(uploadPath) .toFile()); } public List<Path> loadAll() { effort { Path root = Paths.get(uploadPath); if (Files.exists(root)) { render Files.walk(root, 1) .filter(path -> !path.equals(root)) .collect(Collectors.toList()); } render Collections.emptyList(); } take hold of (IOException e) { throw new RuntimeException("Could non list the files!"); } } }
5.two. Create Model classes: FileData
and UploadResponseMessage
The model layer will contain:
-
FileData
- object with field like filename, url(to download file) and size, -
UploadResponseMessage
- volition be used to render information about how uploading process ran.
bundle com.frontbackend.springboot.model; public form FileData { individual 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(Cord url) { this.url = url; } public Long getSize() { return size; } public void setSize(Long size) { this.size = size; } }
The UploadResponseMessage
class volition be used in FilesController
and RestExceptionHandler
.
package com.frontbackend.springboot.model; public class UploadResponseMessage { private final Cord responseMessage; public UploadResponseMessage(Cord 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, nosotros created the FilesController
class that will be responsible for handing all POST, GET, and DELETE requests to /files
endpoint.
bundle com.frontbackend.springboot.controller; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import coffee.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.notation.Autowired; import org.springframework.core.io.Resources; 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.spider web.bind.annotation.GetMapping; import org.springframework.web.bind.notation.PathVariable; import org.springframework.spider web.demark.notation.PostMapping; import org.springframework.spider web.bind.note.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.demark.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.spider 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 { individual final FileService fileService; @Autowired public FilesController(FileService fileService) { this.fileService = fileService; } @PostMapping public ResponseEntity<UploadResponseMessage> uploadFile(@RequestParam("file") MultipartFile file) { try { fileService.save(file); return ResponseEntity.status(HttpStatus.OK) .body(new UploadResponseMessage("Uploaded the file successfully: " + file.getOriginalFilename())); } take hold of (Exception e) { return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED) .trunk(new UploadResponseMessage("Could not upload the file: " + file.getOriginalFilename() + "!")); } } @GetMapping public ResponseEntity<Listing<FileData>> getListFiles() { List<FileData> fileInfos = fileService.loadAll() .stream() .map(this::pathToFileData) .collect(Collectors.toList()); return ResponseEntity.status(HttpStatus.OK) .trunk(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.grade, "getFile", filename) .build() .toString()); attempt { fileData.setSize(Files.size(path)); } catch (IOException e) { due east.printStackTrace(); throw new RuntimeException("Error: " + e.getMessage()); } return fileData; } @GetMapping("{filename:.+}") @ResponseBody public ResponseEntity<Resource> getFile(@PathVariable String filename) { Resource file = fileService.load(filename); render ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"") .torso(file); } }
This grade has some interesting annotations:
-
@RestController
- annotation is used to ascertain a Residual controller, -
@GetMapping
,@PostMapping
and@DeleteMapping
- annotation is for handing HTTP Get, Postal service and DELETE requests with specific class methods:
HTTP Method | Endpoint | Method |
/files | uploadFile() | |
Get | /files | getListFiles() |
Go | /files/{filename:.+} | getFile() |
DELETE | /files | delete() |
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 besides extend RestExceptionHandler
. To handle the exception when uploading too big files we need to handle MaxUploadSizeExceededException
similar 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.spider web.bind.notation.ControllerAdvice; import org.springframework.web.demark.annotation.ExceptionHandler; import org.springframework.web.multipart.MaxUploadSizeExceededException; import org.springframework.web.servlet.mvc.method.notation.ResponseEntityExceptionHandler; @ControllerAdvice public class RestExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler(MaxUploadSizeExceededException.class) public ResponseEntity<UploadResponseMessage> handleMaxSizeException(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.backdrop
To ascertain the maximum file size that could exist uploaded we need to add the post-obit entries in the application.properties
:
upload.path=/uploads spring.servlet.multipart.max-file-size=700KB jump.servlet.multipart.max-asking-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 asking size for a multipart/form-data.
Additionally, nosotros 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
grade.
6. Test Leap Kick upload file application
Discover upload-file-into-filesystem-0.0.1-SNAPSHOT.jar
in the target
folder and Start Leap Kicking application by running coffee -jar upload-file-into-filesystem-0.0.i-SNAPSHOT.jar
.
Yous should come across a message like to this: Started Awarding in 1.625 seconds (JVM running for one.98)
. That ways the server started successfully.
To examination our uploading/downloading API we used Postman.
6.ane. Uploding file
Uploading files returns data well-nigh the wrapped in UploadResponseMessage
object.
six.ii. Get file listing
six.3. Delete all files
Deleting files will just render HTTP 200 status when successful.
six.4. Empty list afterward deleting all files
When the upload folder is empty nosotros will go an empty collection on Go asking.
7. Conclusion
In this tutorial, nosotros presented how to create a simple Leap Boot application for uploading and downloading files to/from a static folder located somewhere in the filesystem. The awarding provides a Residue API without any front-end, that's why we tested how information technology works using Postman tool.
As usual lawmaking used in this tutorial is available on our GitHub repository.
gentileconstainey.blogspot.com
Source: https://frontbackend.com/spring-boot/spring-boot-upload-file-to-filesystem