Do Games Download Faster In Rest Mode
Treatment uploading and downloading files are very common jobs in about of the web applications. Spring Boot provides the MultipartFile interface to handle HTTP multi-role requests for uploading files.
In this tutorial, nosotros will learn the post-obit:
- Create a Spring Boot spider web application that allows file uploads
- Upload single and multiple files using RESTful web services
- Download file using RESTful web service
- Listing all files uploaded on the server
- A simple Thymeleaf & HTML web interface to upload file(southward) from browser
Tools you need to complete this tutorial:
- Java viii+
- JDK i.8+
- Spring Boot
- Thymeleaf
- Gradle iv+
- Postman (optional for testing RESTful APIs)
Note: This article uses RESTful web services to upload and download files in Jump Boot. If you are using Thymeleaf and want to upload a file, check out this guide.
Project Dependencies
We only demand spring-boot-starter-web and spring-kick-starter-thymeleaf starter dependencies for our case Spring Kicking projection. We do not need whatever actress dependency for file upload. Hither is how our build.gradle file looks like:
build.gradle
plugins { id 'org.springframework.boot' version '2.1.three.RELEASE' id 'coffee' } apply plugin: 'io.leap.dependency-management' grouping = 'com.attacomsian' version = '0.0.i-SNAPSHOT' sourceCompatibility = 'ane.8' repositories { mavenCentral ( ) } dependencies { implementation 'org.springframework.kicking:bound-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' } I used Bound Initializr to generate the above Gradle configuration file. It is an easier and quicker way to create a Spring Boot application.
Configure Properties
Before nosotros start the bodily work, let'due south first configure the location on the server where all the uploaded files will be stored. We'll too configure the maximum file size that can be uploaded in a single HTTP multi-part request. Bound Boot automatically enables multipart/form-information requests, so nosotros practise non need to do anything.
awarding.properties
# max file size jump.servlet.multipart.max-file-size = 10MB # max request size spring.servlet.multipart.max-request-size = 10MB # files storage location (stores all files uploaded via Balance API) storage.location = ./uploads In above properties file, we have ii multi-part settings:
-
jump.servlet.multipart.max-file-sizeis set to 10MB, which ways total files size cannot exceed 10MB. -
spring.servlet.multipart.max-asking-sizesets the maximummultipart/course-datarequest size to 10MB.
In simple words, we cannot upload files greater than 10MB in size given the above configuration.
Enable Configuration Properties
In our application.properties file, nosotros define the storage location. Now permit's create a POJO course called StorageProperties and annotate information technology with @ConfigurationProperties to automatically bind the properties defined in application.properties file.
StorageProperties.java
packet com.attacomsian.uploadfiles.storage ; import org.springframework.boot.context.properties. ConfigurationProperties ; @ConfigurationProperties (prefix = "storage" ) public class StorageProperties { individual String location; public Cord getLocation ( ) { return location; } public void setLocation ( String location) { this .location = location; } } Notice the prefix= "storage" attribute in the above annotation. It instructs @ConfigurationProperties to bind all the properties that start with storage prefix to their corresponding attributes of POJO class when the application is started.
The adjacent pace is to enable the ConfigurationProperties feature past adding @EnableConfigurationProperties notation to our master configuration class.
Application.java
package com.attacomsian.uploadfiles ; import com.attacomsian.uploadfiles.storage. StorageProperties ; import org.springframework.boot. SpringApplication ; import org.springframework.boot.autoconfigure. SpringBootApplication ; import org.springframework.boot.context.backdrop. EnableConfigurationProperties ; @SpringBootApplication @EnableConfigurationProperties ( StorageProperties . class ) public class Application { public static void master ( String [ ] args) { SpringApplication . run ( Application . class , args) ; } } Files Upload Controller
Let's at present create a controller course called FileController for treatment uploading and downloading files via RESTful web services. It likewise defines a road to list all the uploaded files.
FileController.coffee
package com.attacomsian.uploadfiles.controllers ; import com.attacomsian.uploadfiles.commons. FileResponse ; import com.attacomsian.uploadfiles.storage. StorageService ; import org.springframework.core.io. Resource ; import org.springframework.http. HttpHeaders ; import org.springframework.http. ResponseEntity ; import org.springframework.stereotype. Controller ; import org.springframework.ui. Model ; import org.springframework.spider web.demark.note. * ; import org.springframework.web.multipart. MultipartFile ; import org.springframework.web.servlet.support. ServletUriComponentsBuilder ; import java.util. Arrays ; import coffee.util. List ; import java.util.stream. Collectors ; @Controller public form FileController { private StorageService storageService; public FileController ( StorageService storageService) { this .storageService = storageService; } @GetMapping ( "/" ) public String listAllFiles ( Model model) { model. addAttribute ( "files" , storageService. loadAll ( ) . map ( path -> ServletUriComponentsBuilder . fromCurrentContextPath ( ) . path ( "/download/" ) . path (path. getFileName ( ) . toString ( ) ) . toUriString ( ) ) . collect ( Collectors . toList ( ) ) ) ; return "listFiles" ; } @GetMapping ( "/download/{filename:.+}" ) @ResponseBody public ResponseEntity < Resource > downloadFile ( @PathVariable String filename) { Resource resource = storageService. loadAsResource (filename) ; return ResponseEntity . ok ( ) . header ( HttpHeaders .CONTENT_DISPOSITION, "zipper; filename=\"" + resource. getFilename ( ) + "\"" ) . body (resource) ; } @PostMapping ( "/upload-file" ) @ResponseBody public FileResponse uploadFile ( @RequestParam ( "file" ) MultipartFile file) { String name = storageService. store (file) ; String uri = ServletUriComponentsBuilder . fromCurrentContextPath ( ) . path ( "/download/" ) . path (name) . toUriString ( ) ; return new FileResponse (name, uri, file. getContentType ( ) , file. getSize ( ) ) ; } @PostMapping ( "/upload-multiple-files" ) @ResponseBody public List < FileResponse > uploadMultipleFiles ( @RequestParam ( "files" ) MultipartFile [ ] files) { render Arrays . stream (files) . map (file -> uploadFile (file) ) . collect ( Collectors . toList ( ) ) ; } } As ever, our controller course is annotated with @Controller to let the Bound MVC pick it upward for routes. Each method is decorated with @GetMapping or @PostMapping to demark the path and the HTTP action with that particular method.
- Become
/loads the current list of uploaded files and renders information technology into a Thymeleaf template calledlistFiles.html. - POST
/download/{filename}resolves the resource if it exists, and sends it to the browser for download.HttpHeaders.CONTENT_DISPOSITIONadds the"Content-Disposition"response header to indicate file attachment. - POST
/upload-file&/upload-multiple-filesroutes handle HTTP multi-part requests and useStorageServicefor saving files on the server. Both these methods render an object ofFileResponseafterward the upload is finished.
The FileResponse course is used to return a JSON response for RESTful web services.
FileResponse.java
bundle com.attacomsian.uploadfiles.eatables ; public class FileResponse { private String name; private Cord uri; private String type; private long size; public FileResponse ( String name, String uri, String type, long size) { this .name = proper noun; this .uri = uri; this .type = type; this .size = size; } // getters and setters removed for the sake of brevity } The FileController form uses the StorageService interface for storing and resolving files in the file system. It is the about important course for handling files in our instance. We'll define these classes in the next section.
In production, information technology's not advised to store the uploaded files in your application file organisation. Y'all might lose all files if your awarding server is damaged. It also makes very difficult to move the awarding from ane server to some other. Therefore, information technology is a skilful practise to apply external storage like AWS S3 for storing all the uploaded files. I'll write near this topic in the future.
Storage Service
Finally, it is fourth dimension to create a storage service called StorageService for our controller to connect with a storage layer (eastward.g. file system in our case). This task involves several classes. Nosotros'll define these classes one-past-one.
The kickoff pace is to ascertain an interface called StorageService as shown below:
StorageService.java
packet com.attacomsian.uploadfiles.storage ; import org.springframework.core.io. Resource ; import org.springframework.web.multipart. MultipartFile ; import java.nio.file. Path ; import java.util.stream. Stream ; public interface StorageService { void init ( ) ; Cord shop ( MultipartFile file) ; Stream < Path > loadAll ( ) ; Path load ( Cord filename) ; Resource loadAsResource ( String filename) ; void deleteAll ( ) ; } The above interface declares several abstract methods for initializing, storing, removing and retrieving files. It but lists possible storage operations without their implementation. Now, it is up to y'all to decide how you want to implement them. In this example, nosotros will use our file system for handling files. Information technology can as well be implemented to store the files on any external location.
Let's create a concrete class FileSystemStorageService that implements the StorageService interface.
FileSystemStorageService.java
bundle com.attacomsian.uploadfiles.storage ; import org.springframework.beans.factory.note. Autowired ; import org.springframework.core.io. Resource ; import org.springframework.cadre.io. UrlResource ; import org.springframework.stereotype. Service ; import org.springframework.util. FileSystemUtils ; import org.springframework.util. StringUtils ; import org.springframework.spider web.multipart. MultipartFile ; import javax.annotation. PostConstruct ; import java.io. IOException ; import java.io. InputStream ; import java.net. MalformedURLException ; import java.nio.file. Files ; import java.nio.file. Path ; import coffee.nio.file. Paths ; import coffee.nio.file. StandardCopyOption ; import coffee.util.stream. Stream ; @Service public class FileSystemStorageService implements StorageService { private last Path rootLocation; @Autowired public FileSystemStorageService ( StorageProperties properties) { this .rootLocation = Paths . get (backdrop. getLocation ( ) ) ; } @Override @PostConstruct public void init ( ) { try { Files . createDirectories (rootLocation) ; } catch ( IOException eastward) { throw new StorageException ( "Could non initialize storage location" , eastward) ; } } @Override public Cord shop ( MultipartFile file) { Cord filename = StringUtils . cleanPath (file. getOriginalFilename ( ) ) ; try { if (file. isEmpty ( ) ) { throw new StorageException ( "Failed to store empty file " + filename) ; } if (filename. contains ( ".." ) ) { // This is a security check throw new StorageException ( "Cannot store file with relative path outside current directory " + filename) ; } try ( InputStream inputStream = file. getInputStream ( ) ) { Files . copy (inputStream, this .rootLocation. resolve (filename) , StandardCopyOption .REPLACE_EXISTING) ; } } take hold of ( IOException due east) { throw new StorageException ( "Failed to store file " + filename, due east) ; } return filename; } @Override public Stream < Path > loadAll ( ) { try { render Files . walk ( this .rootLocation, i ) . filter (path -> !path. equals ( this .rootLocation) ) . map ( this .rootLocation:: relativize ) ; } take hold of ( IOException east) { throw new StorageException ( "Failed to read stored files" , e) ; } } @Override public Path load ( String filename) { return rootLocation. resolve (filename) ; } @Override public Resource loadAsResource ( String filename) { endeavor { Path file = load (filename) ; Resource resources = new UrlResource (file. toUri ( ) ) ; if (resource. exists ( ) || resource. isReadable ( ) ) { render resource; } else { throw new FileNotFoundException ( "Could not read file: " + filename) ; } } catch ( MalformedURLException e) { throw new FileNotFoundException ( "Could non read file: " + filename, e) ; } } @Override public void deleteAll ( ) { FileSystemUtils . deleteRecursively (rootLocation. toFile ( ) ) ; } } The to a higher place implementation class is taken from Jump Kicking official files uploading example with few modifications done by me. The of import change I made is the improver of @PostConstruct note on the init() method. It guarantees that the init() method is just called once the bean is fully initialized with all the dependencies injected.
The FileSystemStorageService form throws exceptions in example of unexpected scenarios, for example, the file requested by the user might not exist.
The offset exception is StorageException which is thrown when we are unable to create the storage directory or the uploaded file is empty etc.
StorageException.java
packet com.attacomsian.uploadfiles.storage ; public class StorageException extends RuntimeException { public StorageException ( String message) { super (message) ; } public StorageException ( String message, Throwable cause) { super (message, cause) ; } } The FileNotFoundException exception is thrown when a file is requested by the user but it does not exist on the server.
FileNotFoundException.java
package com.attacomsian.uploadfiles.storage ; import org.springframework.http. HttpStatus ; import org.springframework.web.demark.annotation. ResponseStatus ; @ResponseStatus ( HttpStatus .NOT_FOUND) public form FileNotFoundException extends StorageException { public FileNotFoundException ( String bulletin) { super (message) ; } public FileNotFoundException ( Cord message, Throwable cause) { super (bulletin, cause) ; } } Notice the @ResponseStatus(HttpStatus.NOT_FOUND) annotation in a higher place. This note ensures that Bound Kick responds with a 404 (Not Found) HTTP condition instead of 501 (Internal Server Fault) when the exception is thrown.
Running & Testing the Awarding
We are almost washed with our backend development. Since we created RESTful APIs for uploading and downloading files, nosotros tin can test them via Postman. Let's run the application by typing the following command in your terminal from the root directory of the project:
$ ./gradlew bootRun In one case the awarding is started, you can access it at http://localhost:8080.
1. Upload Single File
2. Upload Multiple Files
iii. Download File
HTML Web Grade
Nosotros have tested our RESTful APIs and they are working fine. Now it is time to create a simple forepart-end interface using HTML & Thymeleaf that lists all the files uploaded so far. It will as well permit users to upload files directly from the browser.
listFiles.html
<! doctype html > <html lang = "en" xmlns:thursday = "http://www.thymeleaf.org" > <body > <h1 > Bound Boot File Upload Example </h1 > <60 minutes /> <h4 > Upload Single File: </h4 > <form method = "Post" enctype = "multipart/form-information" th:activeness = "@{/upload-file}" > <input type = "file" proper noun = "file" > <br /> <br /> <push button blazon = "submit" > Submit </push > </form > <hr /> <h4 > Upload Multiple Files: </h4 > <form method = "Postal service" enctype = "multipart/form-data" th:action = "@{/upload-multiple-files}" > <input type = "file" name = "files" multiple > <br /> <br /> <push button blazon = "submit" > Submit </button > </course > <hr /> <h2 > All Uploaded Files: </h2 > <ul > <li th:each = "file : ${files}" > <a th:href = "${file}" target = "_blank" th:text = "${file}" > </a > </li > </ul > </body > </html > The higher up template has two forms that enable users to upload a single file every bit well as multiple files. At the bottom, it also shows a list of currently uploaded files on the server. Here is how it looks like:
Source code: Download the complete source lawmaking from GitHub available nether MIT license.
Conclusion
That's all folks for uploading and downloading files in Bound Boot. We discussed strategies for handling single also as multiple files via RESTful web services. We tested our REST APIs via Postman to confirm that they are working every bit expected. Finally, nosotros created the simplest web interface in HTML and Thymeleaf for showing a list of all the uploaded files.
In the end, I really appreciate that yous read this article and hope that you'd take learned how to handle files in Jump Boot today. If yous have any questions or feedback, delight experience free to transport me a tweet.
Happy learning Spring Boot 😍
Recommended for Yous ✌️
how to use Ajax to upload a file in Spring Kicking.
Uploading Files in Node.js and Limited
Uploading and Parsing CSV File using Spring Kick
✌️ Like this article? Follow me on Twitter and LinkedIn. You lot can also subscribe to RSS Feed.
Source: https://attacomsian.com/blog/uploading-files-spring-boot
Posted by: baileysitted.blogspot.com

0 Response to "Do Games Download Faster In Rest Mode"
Post a Comment