Spring Boot File Upload Download
Spring Boot File Upload Download
Java
Golang
Kotlin
Spring Boot
Node.js
JavaFX
System Design
DevOps
About
Spring Boot File Upload / Download Rest API Example
Spring Boot � Apr 12, 2018 � 11 mins read
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
boot web service.
We�ll first build the REST APIs for uploading and downloading files, and then test
those APIs using Postman. We�ll also write front-end code in javascript to upload
files.
Spring Boot File Upload and Download AJAX Rest API Web Service
All right! Let�s get started.
Open http://start.spring.io
Enter file-demo in the �Artifact� field.
Add Web in the dependencies section.
Click Generate Project to download the application.
That�s it! You may now unzip the downloaded application archive and import it into
your favorite IDE.
package com.example.filedemo.property;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "file")
public class FileStorageProperties {
private String uploadDir;
If you define additional file properties in future, you may simply add a
corresponding field in the above class, and spring boot will automatically bind the
field with the property value.
package com.example.filedemo;
import com.example.filedemo.property.FileStorageProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties({
FileStorageProperties.class
})
public class FileDemoApplication {
package com.example.filedemo.controller;
import com.example.filedemo.payload.UploadFileResponse;
import com.example.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.bind.annotation.*;
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 java.util.stream.Collectors;
@RestController
public class FileController {
@Autowired
private FileStorageService fileStorageService;
@PostMapping("/uploadFile")
public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file) {
String fileName = fileStorageService.storeFile(file);
@PostMapping("/uploadMultipleFiles")
public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files")
MultipartFile[] files) {
return Arrays.asList(files)
.stream()
.map(file -> uploadFile(file))
.collect(Collectors.toList());
}
@GetMapping("/downloadFile/{fileName:.+}")
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName,
HttpServletRequest request) {
// Load file as Resource
Resource resource = fileStorageService.loadFileAsResource(fileName);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" +
resource.getFilename() + "\"")
.body(resource);
}
}
The FileController class uses FileStorageService for storing files in the file
system and retrieving them. It returns a payload of type UploadFileResponse after
the upload is completed. Let�s define these classes one by one.
UploadFileResponse
As the name suggests, this class is used to return the response from the
/uploadFile and /uploadMultipleFiles APIs.
package com.example.filedemo.payload;
package com.example.filedemo.service;
import com.example.filedemo.exception.FileStorageException;
import com.example.filedemo.exception.MyFileNotFoundException;
import com.example.filedemo.property.FileStorageProperties;
import org.springframework.beans.factory.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 {
@Autowired
public FileStorageService(FileStorageProperties fileStorageProperties) {
this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
.toAbsolutePath().normalize();
try {
Files.createDirectories(this.fileStorageLocation);
} catch (Exception ex) {
throw new FileStorageException("Could not create the directory where the uploaded
files will be stored.", ex);
}
}
try {
// Check 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 name)
Path targetLocation = this.fileStorageLocation.resolve(fileName);
Files.copy(file.getInputStream(), targetLocation,
StandardCopyOption.REPLACE_EXISTING);
return fileName;
} catch (IOException ex) {
throw new FileStorageException("Could not store file " + fileName + ". Please try
again!", ex);
}
}
1. FileStorageException
It�s thrown when an unexpected situation occurs while storing a file in the file
system -
package com.example.filedemo.exception;
package 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(String message) {
super(message);
}
mvn spring-boot:run
Once started, the application can be accessed at http://localhost:8080.
1. Upload File
Spring Boot File Upload Rest API Example
2. Upload Multiple Files
Spring Boot Upload Multiple Files Rest API Example
3. Download File
Spring Boot Download File Rest API Example
Developing the Front End
Our backend APIs are working fine. Let�s now write the front end code to let users
upload and download files from our web app.
All the front end files will go inside src/main/resources/static folder. Following
is the directory structure of our front-end code -
static
+-- css
+-- main.css
+-- js
+-- main.js
+-- index.html
A bit of HTML
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-
scale=1.0">
<title>Spring Boot File Upload / Download Rest API Example</title>
<link rel="stylesheet" href="/css/main.css" />
</head>
<body>
<noscript>
<h2>Sorry! Your browser doesn't support Javascript</h2>
</noscript>
<div class="upload-container">
<div class="upload-header">
<h2>Spring Boot File Upload / Download Rest API Example</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" name="file" class="file-input"
required />
<button type="submit" class="primary 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>
<form id="multipleUploadForm" name="multipleUploadForm">
<input id="multipleFileUploadInput" type="file" name="files" class="file-input"
multiple required />
<button type="submit" class="primary submit-btn">Submit</button>
</form>
<div class="upload-response">
<div id="multipleFileUploadError"></div>
<div id="multipleFileUploadSuccess"></div>
</div>
</div>
</div>
</div>
<script src="/js/main.js" ></script>
</body>
</html>
Some Javascript
'use strict';
function uploadSingleFile(file) {
var formData = new FormData();
formData.append("file", file);
xhr.onload = function() {
console.log(xhr.responseText);
var response = JSON.parse(xhr.responseText);
if(xhr.status == 200) {
singleFileUploadError.style.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.style.display = "none";
singleFileUploadError.innerHTML = (response && response.message) || "Some Error
Occurred";
}
}
xhr.send(formData);
}
function uploadMultipleFiles(files) {
var formData = new FormData();
for(var index = 0; index < files.length; index++) {
formData.append("files", files[index]);
}
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.style.display = "block";
} else {
multipleFileUploadSuccess.style.display = "none";
multipleFileUploadError.innerHTML = (response && response.message) || "Some Error
Occurred";
}
}
xhr.send(formData);
}
singleUploadForm.addEventListener('submit', function(event){
var files = singleFileUploadInput.files;
if(files.length === 0) {
singleFileUploadError.innerHTML = "Please select a file";
singleFileUploadError.style.display = "block";
}
uploadSingleFile(files[0]);
event.preventDefault();
}, true);
multipleUploadForm.addEventListener('submit', function(event){
var files = multipleFileUploadInput.files;
if(files.length === 0) {
multipleFileUploadError.innerHTML = "Please select at least one file";
multipleFileUploadError.style.display = "block";
}
uploadMultipleFiles(files);
event.preventDefault();
}, true);
The above code is self explanatory. I�m using XMLHttpRequest along with FormData
object to upload file(s) as multipart/form-data.
body {
margin: 0;
padding: 0;
font-weight: 400;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 1rem;
line-height: 1.58;
color: #333;
background-color: #f4f4f4;
}
body:before {
height: 50%;
width: 100%;
position: absolute;
top: 0;
left: 0;
background: #128ff2;
content: "";
z-index: 0;
}
.clearfix:after {
display: block;
content: "";
clear: both;
}
h1 {
font-size: 1.7em;
}
a {
color: #128ff2;
}
button {
box-shadow: none;
border: 1px solid transparent;
font-size: 14px;
outline: none;
line-height: 100%;
white-space: nowrap;
vertical-align: middle;
padding: 0.6rem 1rem;
border-radius: 2px;
transition: all 0.2s ease-in-out;
cursor: pointer;
min-height: 38px;
}
button.primary {
background-color: #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;
}
.submit-btn {
display: inline-block;
margin-top: 0;
margin-left: 10px;
}
}
.upload-container {
max-width: 700px;
margin-left: auto;
margin-right: auto;
background-color: #fff;
box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);
margin-top: 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-bottom: 20px;
border-bottom: 1px solid #e8e8e8;
}
.upload-response {
overflow-x: hidden;
word-break: break-all;
}
If you use JQuery
If you prefer using jQuery instead of vanilla javascript, then you can upload files
using jQuery.ajax() method like so -
$('#singleUploadForm').submit(function(event) {
var formElement = this;
// You can directly create form data from the form element
// (Or you could get the files from input element and append them to FormData as we
did in vanilla javascript)
var formData = new FormData(formElement);
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/uploadFile",
data: formData,
processData: false,
contentType: false,
success: function (response) {
console.log(response);
// process response
},
error: function (error) {
console.log(error);
// process error
}
});
event.preventDefault();
});
https://github.com/�/spring-boot-file-upload-download-rest-�