Java 8 Upload File to Directory Tutorial
Uploading and downloading files are very common tasks for which developers need to write code in their applications.
In this article, You'll learn how to upload and download files in a RESTful spring kicking web service.
We'll first build the REST APIs for uploading and downloading files, then test those APIs using Postman. We'll likewise write forepart-end lawmaking in javascript to upload files.
Following is the final version of our application -
All right! Let's get started.
Creating the Awarding
Let'due south generate our awarding using Spring Boot CLI. Fire up your terminal, and type the post-obit command to generate the app -
$ spring init --proper noun=file-demo --dependencies=web file-demo Using service at https://start.spring.io Project extracted to '/Users/rajeevkumarsingh/spring-boot/file-demo'
You may also generate the application through Spring Initializr spider web tool past post-obit the instructions below -
- Open http://first.spring.io
- Enter file-demo in the "Antiquity" field.
- Enter com.example.filedemo in the "Parcel" field.
- Add Web in the "Dependencies" department.
- Click Generate to generate and download the project.
That's it! Yous may now unzip the downloaded application archive and import information technology into your favorite IDE.
Configuring Server and File Storage Properties
Commencement affair First! Allow's configure our Bound Boot application to enable Multipart file uploads, and define the maximum file size that can exist uploaded. Nosotros'll also configure the directory into which all the uploaded files will be stored.
Open src/main/resource/application.properties
file, and add together the following properties to it -
## MULTIPART (MultipartProperties) # Enable multipart uploads spring.servlet.multipart.enabled = true # Threshold after which files are written to disk. spring.servlet.multipart.file-size-threshold = 2KB # Max file size. jump.servlet.multipart.max-file-size = 200MB # Max Asking Size spring.servlet.multipart.max-request-size = 215MB ## File Storage Properties # All files uploaded through the Residue API will exist stored in this directory file.upload-dir = /Users/callicoder/uploads
Note: Please change the
file.upload-dir
property to the path where y'all want the uploaded files to be stored.
Automatically binding properties to a POJO form
Bound Kicking has an awesome characteristic called @ConfigurationProperties
using which you can automatically bind the properties defined in the awarding.properties
file to a POJO class.
Let's define a POJO form called FileStorageProperties
inside com.example.filedemo.property
package to bind all the file storage properties -
package com.instance.filedemo.property ; import org.springframework.boot.context.properties. ConfigurationProperties ; @ConfigurationProperties (prefix = "file" ) public class FileStorageProperties { private String uploadDir; public Cord getUploadDir ( ) { render uploadDir; } public void setUploadDir ( Cord uploadDir) { this .uploadDir = uploadDir; } }
The @ConfigurationProperties(prefix = "file")
notation does its task on application startup and binds all the properties with prefix file
to the corresponding fields of the POJO class.
If you lot ascertain additional file
backdrop in time to come, y'all may simply add a respective field in the above class, and spring boot will automatically demark the field with the property value.
Enable Configuration Properties
Now, To enable the ConfigurationProperties
feature, you demand to add @EnableConfigurationProperties
annotation to any configuration form.
Open the main grade src/master/java/com/instance/filedemo/FileDemoApplication.java
, and add the @EnableConfigurationProperties
note to it like and so -
package com.example.filedemo ; import com.example.filedemo.property. FileStorageProperties ; import org.springframework.boot. SpringApplication ; import org.springframework.boot.autoconfigure. SpringBootApplication ; import org.springframework.kick.context.properties. EnableConfigurationProperties ; @SpringBootApplication @EnableConfigurationProperties ( { FileStorageProperties . class } ) public course FileDemoApplication { public static void principal ( Cord [ ] args) { SpringApplication . run ( FileDemoApplication . class , args) ; } }
Writing APIs for File Upload and Download
Permit's now write the Rest APIs for uploading and downloading files. Create a new controller class called FileController
within com.example.filedemo.controller
package.
Here is the complete code for FileController
-
package com.example.filedemo.controller ; import com.example.filedemo.payload. UploadFileResponse ; import com.instance.filedemo.service. FileStorageService ; import org.slf4j. Logger ; import org.slf4j. LoggerFactory ; import org.springframework.beans.factory.annotation. Autowired ; import org.springframework.core.io. Resource ; import org.springframework.http. HttpHeaders ; import org.springframework.http. MediaType ; import org.springframework.http. ResponseEntity ; import org.springframework.web.demark.note. * ; import org.springframework.web.multipart. MultipartFile ; import org.springframework.web.servlet.support. ServletUriComponentsBuilder ; import javax.servlet.http. HttpServletRequest ; import java.io. IOException ; import java.util. Arrays ; import java.util. List ; import coffee.util.stream. Collectors ; @RestController public class FileController { private static concluding Logger logger = LoggerFactory . getLogger ( FileController . course ) ; @Autowired private FileStorageService fileStorageService; @PostMapping ( "/uploadFile" ) public UploadFileResponse uploadFile ( @RequestParam ( "file" ) MultipartFile file) { String fileName = fileStorageService. storeFile (file) ; String fileDownloadUri = ServletUriComponentsBuilder . fromCurrentContextPath ( ) . path ( "/downloadFile/" ) . path (fileName) . toUriString ( ) ; render new UploadFileResponse (fileName, fileDownloadUri, file. getContentType ( ) , file. getSize ( ) ) ; } @PostMapping ( "/uploadMultipleFiles" ) public List < UploadFileResponse > uploadMultipleFiles ( @RequestParam ( "files" ) MultipartFile [ ] files) { render Arrays . asList (files) . stream ( ) . map (file -> uploadFile (file) ) . collect ( Collectors . toList ( ) ) ; } @GetMapping ( "/downloadFile/{fileName:.+}" ) public ResponseEntity < Resources > downloadFile ( @PathVariable String fileName, HttpServletRequest asking) { // Load file every bit Resource Resource resource = fileStorageService. loadFileAsResource (fileName) ; // Try to make up one's mind file'south content type Cord contentType = nil ; try { contentType = request. getServletContext ( ) . getMimeType (resource. getFile ( ) . getAbsolutePath ( ) ) ; } catch ( IOException ex) { logger. info ( "Could not determine file type." ) ; } // Fallback to the default content type if type could not be determined if (contentType == null ) { contentType = "awarding/octet-stream" ; } return ResponseEntity . ok ( ) . contentType ( MediaType . parseMediaType (contentType) ) . header ( HttpHeaders .CONTENT_DISPOSITION, "attachment; filename=\"" + resources. getFilename ( ) + "\"" ) . torso (resource) ; } }
The FileController
form uses FileStorageService
for storing files in the file system and retrieving them. It returns a payload of blazon UploadFileResponse
later the upload is completed. Let'due south define these classes one past one.
UploadFileResponse
Equally the name suggests, this class is used to return the response from the /uploadFile
and /uploadMultipleFiles
APIs.
Create UploadFileResponse
grade inside com.case.filedemo.payload
packet with the post-obit contents -
package com.example.filedemo.payload ; public grade UploadFileResponse { private Cord fileName; individual String fileDownloadUri; individual Cord fileType; private long size; public UploadFileResponse ( String fileName, String fileDownloadUri, String fileType, long size) { this .fileName = fileName; this .fileDownloadUri = fileDownloadUri; this .fileType = fileType; this .size = size; } // Getters and Setters (Omitted for brevity) }
Service for Storing Files in the FileSystem and retrieving them
Let's now write the service for storing files in the file system and retrieving them. Create a new class called FileStorageService.java
inside com.instance.filedemo.service
package with the following contents -
package com.example.filedemo.service ; import com.example.filedemo.exception. FileStorageException ; import com.instance.filedemo.exception. MyFileNotFoundException ; import com.example.filedemo.belongings. FileStorageProperties ; import org.springframework.beans.mill.annotation. Autowired ; import org.springframework.core.io. Resource ; import org.springframework.core.io. UrlResource ; import org.springframework.stereotype. Service ; import org.springframework.util. StringUtils ; import org.springframework.web.multipart. MultipartFile ; 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.nio.file. StandardCopyOption ; @Service public class FileStorageService { private final Path fileStorageLocation; @Autowired public FileStorageService ( FileStorageProperties fileStorageProperties) { this .fileStorageLocation = Paths . get (fileStorageProperties. getUploadDir ( ) ) . toAbsolutePath ( ) . normalize ( ) ; effort { Files . createDirectories ( this .fileStorageLocation) ; } grab ( Exception ex) { throw new FileStorageException ( "Could non create the directory where the uploaded files volition be stored." , ex) ; } } public String storeFile ( MultipartFile file) { // Normalize file proper noun String fileName = StringUtils . cleanPath (file. getOriginalFilename ( ) ) ; try { // Cheque if the file's name contains invalid characters if (fileName. contains ( ".." ) ) { throw new FileStorageException ( "Sorry! Filename contains invalid path sequence " + fileName) ; } // Copy file to the target location (Replacing existing file with the same proper name) Path targetLocation = this .fileStorageLocation. resolve (fileName) ; Files . copy (file. getInputStream ( ) , targetLocation, StandardCopyOption .REPLACE_EXISTING) ; return fileName; } take hold of ( IOException ex) { throw new FileStorageException ( "Could not store file " + fileName + ". Delight attempt over again!" , ex) ; } } public Resources loadFileAsResource ( String fileName) { try { Path filePath = this .fileStorageLocation. resolve (fileName) . normalize ( ) ; Resources resource = new UrlResource (filePath. toUri ( ) ) ; if (resource. exists ( ) ) { return resource; } else { throw new MyFileNotFoundException ( "File not institute " + fileName) ; } } catch ( MalformedURLException ex) { throw new MyFileNotFoundException ( "File not found " + fileName, ex) ; } } }
Exception Classes
The FileStorageService
form throws some exceptions in example of unexpected situations. Following are the definitions of those exception classes (All the exception classes go within the package com.example.filedemo.exception
).
one. FileStorageException
It's thrown when an unexpected state of affairs occurs while storing a file in the file organisation -
package com.instance.filedemo.exception ; public form FileStorageException extends RuntimeException { public FileStorageException ( Cord bulletin) { super (message) ; } public FileStorageException ( Cord message, Throwable cause) { super (bulletin, cause) ; } }
ii. MyFileNotFoundException
Information technology's thrown when a file that the user is trying to download is non found.
packet com.example.filedemo.exception ; import org.springframework.http. HttpStatus ; import org.springframework.web.bind.annotation. ResponseStatus ; @ResponseStatus ( HttpStatus .NOT_FOUND) public class MyFileNotFoundException extends RuntimeException { public MyFileNotFoundException ( Cord bulletin) { super (bulletin) ; } public MyFileNotFoundException ( String bulletin, Throwable cause) { super (message, crusade) ; } }
Note that, we've annotated the above exception class with @ResponseStatus(HttpStatus.NOT_FOUND)
. This ensures that Leap boot responds with a 404 Non Plant
status when this exception is thrown.
Running the Awarding and Testing the APIs via Postman
We're done developing our backend APIs. Allow'south run the awarding and test the APIs via Postman. Type the following command from the root directory of the project to run the awarding -
One time started, the application tin can be accessed at http://localhost:8080
.
1. Upload File
2. Upload Multiple Files
3. Download File
Developing the Front End
Our backend APIs are working fine. Permit's at present write the front end code to let users upload and download files from our web app.
All the front end files volition go inside src/principal/resources/static
binder. Following is the directory structure of our front-end code -
static └── css └── chief.css └── js └── principal.js └── index.html
A flake of HTML
<! DOCTYPE html > <html > <head > <meta proper noun = "viewport" content = "width=device-width, initial-scale=1.0, minimum-scale=ane.0" > <title > Leap Boot File Upload / Download Balance API Example </title > <link rel = "stylesheet" href = "/css/main.css" /> </caput > <body > <noscript > <h2 > Sorry! Your browser doesn't support Javascript </h2 > </noscript > <div class = "upload-container" > <div class = "upload-header" > <h2 > Leap Boot File Upload / Download Residual API Instance </h2 > </div > <div class = "upload-content" > <div class = "single-upload" > <h3 > Upload Single File </h3 > <form id = "singleUploadForm" name = "singleUploadForm" > <input id = "singleFileUploadInput" type = "file" proper noun = "file" class = "file-input" required /> <button blazon = "submit" course = "principal submit-btn" > Submit </button > </form > <div class = "upload-response" > <div id = "singleFileUploadError" > </div > <div id = "singleFileUploadSuccess" > </div > </div > </div > <div class = "multiple-upload" > <h3 > Upload Multiple Files </h3 > <grade id = "multipleUploadForm" proper name = "multipleUploadForm" > <input id = "multipleFileUploadInput" type = "file" proper name = "files" class = "file-input" multiple required /> <push type = "submit" course = "primary submit-btn" > Submit </button > </course > <div grade = "upload-response" > <div id = "multipleFileUploadError" > </div > <div id = "multipleFileUploadSuccess" > </div > </div > </div > </div > </div > <script src = "/js/main.js" > </script > </torso > </html >
Some Javascript
'employ strict' ; var singleUploadForm = certificate. querySelector ( '#singleUploadForm' ) ; var singleFileUploadInput = document. querySelector ( '#singleFileUploadInput' ) ; var singleFileUploadError = document. querySelector ( '#singleFileUploadError' ) ; var singleFileUploadSuccess = document. querySelector ( '#singleFileUploadSuccess' ) ; var multipleUploadForm = certificate. querySelector ( '#multipleUploadForm' ) ; var multipleFileUploadInput = document. querySelector ( '#multipleFileUploadInput' ) ; var multipleFileUploadError = document. querySelector ( '#multipleFileUploadError' ) ; var multipleFileUploadSuccess = certificate. querySelector ( '#multipleFileUploadSuccess' ) ; part uploadSingleFile ( file ) { var formData = new FormData ( ) ; formData. suspend ( "file" , file) ; var xhr = new XMLHttpRequest ( ) ; xhr. open ( "POST" , "/uploadFile" ) ; xhr. onload = function ( ) { console. log (xhr.responseText) ; var response = JSON . parse (xhr.responseText) ; if (xhr.status == 200 ) { singleFileUploadError.fashion.display = "none" ; singleFileUploadSuccess.innerHTML = "<p>File Uploaded Successfully.</p><p>DownloadUrl : <a href='" + response.fileDownloadUri + "' target='_blank'>" + response.fileDownloadUri + "</a></p>" ; singleFileUploadSuccess.style.display = "block" ; } else { singleFileUploadSuccess.way.display = "none" ; singleFileUploadError.innerHTML = (response && response.bulletin) || "Some Error Occurred" ; } } xhr. transport (formData) ; } function uploadMultipleFiles ( files ) { var formData = new FormData ( ) ; for ( var index = 0 ; alphabetize < files.length; index++ ) { formData. append ( "files" , files[index] ) ; } var xhr = new XMLHttpRequest ( ) ; xhr. open ( "POST" , "/uploadMultipleFiles" ) ; xhr. onload = function ( ) { console. log (xhr.responseText) ; var response = JSON . parse (xhr.responseText) ; if (xhr.status == 200 ) { multipleFileUploadError.style.display = "none" ; var content = "<p>All Files Uploaded Successfully</p>" ; for ( var i = 0 ; i < response.length; i++ ) { content += "<p>DownloadUrl : <a href='" + response[i] .fileDownloadUri + "' target='_blank'>" + response[i] .fileDownloadUri + "</a></p>" ; } multipleFileUploadSuccess.innerHTML = content; multipleFileUploadSuccess.mode.display = "cake" ; } else { multipleFileUploadSuccess.way.display = "none" ; multipleFileUploadError.innerHTML = (response && response.message) || "Some Error Occurred" ; } } xhr. send (formData) ; } singleUploadForm. addEventListener ( 'submit' , function ( upshot ) { var files = singleFileUploadInput.files; if (files.length === 0 ) { singleFileUploadError.innerHTML = "Please select a file" ; singleFileUploadError.mode.display = "block" ; } uploadSingleFile (files[ 0 ] ) ; event. preventDefault ( ) ; } , true ) ; multipleUploadForm. addEventListener ( 'submit' , part ( event ) { var files = multipleFileUploadInput.files; if (files.length === 0 ) { multipleFileUploadError.innerHTML = "Please select at to the lowest degree one file" ; multipleFileUploadError.style.brandish = "block" ; } uploadMultipleFiles (files) ; outcome. preventDefault ( ) ; } , true ) ;
The in a higher place code is self explanatory. I'g using XMLHttpRequest
forth with FormData
object to upload file(s) equally multipart/form-data
.
And some CSS
* { -webkit-box-sizing : border-box; -moz-box-sizing : border-box; box-sizing : border-box; } trunk { margin : 0; padding : 0; font-weight : 400; font-family : "Helvetica Neue" , Helvetica, Arial, sans-serif; font-size : 1rem; line-summit : 1.58; color : #333; background-color : #f4f4f4; } torso:before { height : 50%; width : 100%; position : accented; top : 0; left : 0; groundwork : #128ff2; content : "" ; z-index : 0; } .clearfix:later on { display : block; content : "" ; clear : both; } h1, h2, h3, h4, h5, h6 { margin-meridian : 20px; margin-lesser : 20px; } h1 { font-size : 1.7em; } a { color : #128ff2; } button { box-shadow : none; border : 1px solid transparent; font-size : 14px; outline : none; line-top : 100%; white-infinite : nowrap; vertical-align : heart; padding : 0.6rem 1rem; border-radius : 2px; transition : all 0.2s ease-in-out; cursor : pointer; min-superlative : 38px; } button.principal { background-colour : #128ff2; box-shadow : 0 2px 2px 0 rgba (0, 0, 0, 0.12) ; color : #fff; } input { font-size : 1rem; } input[type="file"] { border : 1px solid #128ff2; padding : 6px; max-width : 100%; } .file-input { width : 100%; } .submit-btn { display : block; margin-top : 15px; min-width : 100px; } @media screen and ( min-width : 500px) { .file-input { width : calc (100% - 115px) ; } .submit-btn { display : inline-block; margin-top : 0; margin-left : 10px; } } .upload-container { max-width : 700px; margin-left : car; margin-right : auto; background-color : #fff; box-shadow : 0 1px 11px rgba (0, 0, 0, 0.27) ; margin-acme : 60px; min-height : 400px; position : relative; padding : 20px; } .upload-header { border-bottom : 1px solid #ececec; } .upload-header h2 { font-weight : 500; } .single-upload { padding-bottom : 20px; margin-lesser : 20px; border-bottom : 1px solid #e8e8e8; } .upload-response { overflow-ten : hidden; discussion-break : break-all; }
If you lot employ JQuery
If you adopt using jQuery instead of vanilla javascript, then you can upload files using jQuery.ajax()
method similar and then -
$ ( '#singleUploadForm' ) . submit ( part ( event ) { var formElement = this ; // You can directly create form data from the form element // (Or you lot could get the files from input chemical element and append them to FormData as nosotros did in vanilla javascript) var formData = new FormData (formElement) ; $. ajax ( { type: "POST" , enctype: 'multipart/form-information' , url: "/uploadFile" , data: formData, processData: false , contentType: fake , success : function ( response ) { console. log (response) ; // procedure response } , fault : office ( mistake ) { console. log (error) ; // process error } } ) ; event. preventDefault ( ) ; } ) ;
Conclusion
All right folks! In this article, we learned how to upload single as well as multiple files via Remainder APIs written in Jump Boot. Nosotros besides learned how to download files in Jump Kick. Finally, nosotros wrote code to upload files past calling the APIs through javascript.
I hope the post was helpful to you. You lot can download the entire lawmaking for the project that nosotros built in this commodity from the github repository.
If you want to store files in MySQL database instead of the local file system, and so bank check out the following commodity -
Spring Boot File Upload / Download with JPA, Hibernate, and MySQL database
Give thanks you for reading! See you in the next post!
Source: https://www.callicoder.com/spring-boot-file-upload-download-rest-api-example/
0 Response to "Java 8 Upload File to Directory Tutorial"
Post a Comment