Let’s Develop File Upload Service From Scratch Using Java and Spring Boot

nilmadhabmondal

Nil Madhab

Posted on January 13, 2021

Let’s Develop File Upload Service From Scratch Using Java and Spring Boot

We will develop a file upload service, which will be used for image upload in our e-Commerce App using Java Spring Boot

Image for post

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);
    }

}
Enter fullscreen mode Exit fullscreen mode

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());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

That’s it, files will be now renamed with a unique name saved into **_UPLOAD_FILE_DIR_** directory*.*

[

Image for post

Image for post

Upload a file

Get all the files

Image for post

Image for post

get all the uploaded files

Download a single file by name

Image for post

Next step

We will build an Android Application, which will use the APIs. The final result will look something like this.

IMAGE ALT TEXT HERE

💖 💪 🙅 🚩
nilmadhabmondal
Nil Madhab

Posted on January 13, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related