Let’s Develop File Upload Service From Scratch Using Java and Spring Boot
Nil Madhab
Posted on January 13, 2021
We will develop a file upload service, which will be used for image upload in our e-Commerce App using Java Spring Boot
Photo by Drew Coffman on Unsplash
We needed an image upload functionality for our E-Commerce App, as we need to upload images for products and categories. We will build this function as a standalone service, which can be reused later. You can use this source code for uploading and displaying images for any of your products.
First, we will build the backend in Java and Spring, then integrate it with a Web client and Android Client in other tutorials
Backend Demo
You can test the file upload demo here
Find the complete code here
Backend Design
We will have 3 APIs
1. Upload image
2. Get an image by its name
3. Get all images
Let’s have a look at FileUploadController
Java class which describe above 3 APIs
package com.webtutsplus.ecommerce.controller;
import com.webtutsplus.ecommerce.model.FileInfo;
import com.webtutsplus.ecommerce.service.FIleStoreService;
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.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@RestController
@RequestMapping("/fileUpload")
public class FileUploadController {
@Autowired
FIleStoreService fileStoreService;
//upload a file
@PostMapping("/")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
return fileStoreService.store(file);
}
// get all the files
@GetMapping("/")
public ResponseEntity<List<FileInfo>> getListFiles() {
// first get a stream of all file path present in root file directory
Stream<Path> pathStream = fileStoreService.loadAll();
List<FileInfo> fileInfos = pathStream.map(path -> {
// get file name
String filename = path.getFileName().toString();
// use function to get one file to build the URL
String url = MvcUriComponentsBuilder
.fromMethodName(FileUploadController.class, "getFile", path.getFileName().toString()).build().toString();
// make a fileinfo object from filename and url
return new FileInfo(filename, url);
}).collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.OK).body(fileInfos);
}
// get file by filename
@GetMapping("/files/{filename:.+}")
public ResponseEntity<Resource> getFile(@PathVariable String filename) {
Resource file = fileStoreService.load(filename);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);
}
}
which calls the FileStoreService
which also contains 3 methods for each APIs respectively. I have added plenty of comments to the code. Please comment below if anything is not clear.
package com.webtutsplus.ecommerce.service;
import com.webtutsplus.ecommerce.constants.Constants;
import com.webtutsplus.ecommerce.exceptions.StorageException;
import org.apache.commons.io.FilenameUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.UUID;
import java.util.stream.Stream;
@Service
public class FIleStoreService {
Path rootLocation = Paths.get(Constants.UPLOAD_FILE_DIR);
public String store(MultipartFile file) {
try {
if (file.isEmpty()) {
throw new StorageException("Failed to store empty file.");
}
// find extension of the file,png or jpg
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
// generate a random unique name for the image
String uploadedFileName = UUID.randomUUID().toString() + "." + extension;
// create a path for destination file
Path destinationFile = rootLocation.resolve(Paths.get(uploadedFileName))
.normalize().toAbsolutePath();
// Copy input file to destination file path
try (InputStream inputStream = file.getInputStream()) {
Files.copy(inputStream, destinationFile,
StandardCopyOption.REPLACE_EXISTING);
final String baseUrl =
ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
//create the public Image URl where we can find the image
final StringBuilder imageStringBuilder = new StringBuilder(baseUrl);
imageStringBuilder.append("/fileUpload/files/");
imageStringBuilder.append(uploadedFileName);
return imageStringBuilder.toString();
}
}
catch (IOException e) {
throw new StorageException("Failed to store file.", e);
}
}
public Stream<Path> loadAll() {
// load all the files
try {
return Files.walk(this.rootLocation, 1)
// ignore the root path
.filter(path -> !path.equals(this.rootLocation))
.map(this.rootLocation::relativize);
}
catch (IOException e) {
throw new StorageException("Failed to read stored files", e);
}
}
public Resource load(String filename) {
try {
// read the file based on the filename
Path file = rootLocation.resolve(filename);
// get resource from path
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());
}
}
}
That’s it, files will be now renamed with a unique name saved into **_UPLOAD_FILE_DIR_**
directory*.*
[
Upload a file
Get all the files
get all the uploaded files
Download a single file by name
Next step
We will build an Android Application, which will use the APIs. The final result will look something like this.
Posted on January 13, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.