Uploading files on filesystem spring boot

In this article, I'll show you a very simple way to upload and save your file in the filesystem rather than saving as a blob in the database.
It'll be a very flexible way to do that. We can provide a root path for a filesystem (aws or other service, or our servers file system) where it'll consider saving files.

1. Create a Pojo for keeping the file informations

public class UploadProperties {
    private String namespace;
    private String uniqueProperty;
    private String rootPath;
    private String fileName;

    public enum NameSpaces{
        USERS("users"),
        COMPANIES("companies");

        String value;

        NameSpaces(String value){
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

    public String getDirPath() {
        if (namespace == null || namespace.isEmpty()
                || uniqueProperty == null || uniqueProperty.isEmpty()
                || rootPath == null || rootPath.isEmpty())
            throw new IllegalArgumentException("Rootpath or uniqueProperty or Namespace can not be null or empty!");
        return rootPath + File.separator + "AppData" + File.separator + namespace
                + File.separator + uniqueProperty + File.separator + "images";
    }

    public String getFilePath() {
        if (fileName==null|| fileName.isEmpty())
            throw new IllegalArgumentException("Filename can not be null or empty!");
        return getDirPath() + File.separator + fileName;
    }

   // Getters and setters
}

2. Create a service to upload files

@Service
public class FileUploadServiceImpl implements FileUploadService {

    @Value("${files.upload.path}")
    private String rootPath;

    @Override
    public UploadProperties uploadFile(MultipartFile multipartFile, String namespace, String uniqueProperty) throws IOException {
        byte[] bytes = multipartFile.getBytes();

        UploadProperties uploadProperties = new UploadProperties();
        uploadProperties.setNamespace(namespace);
        uploadProperties.setUniqueProperty(uniqueProperty);
        uploadProperties.setRootPath(rootPath);

        File directory = new File(uploadProperties.getDirPath());
        if (!directory.exists()) {
            directory.mkdirs();
        }
        File imageFile = File.createTempFile("upload_", ".png", directory);
        OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(imageFile));
        outputStream.write(bytes);
        outputStream.close();

        uploadProperties.setFileName(imageFile.getName());
        return uploadProperties;
    }
}
Here, the namespace property we are taking to provide a unique path for a specific entity or module. Suppose of have two types of actors in our system, users and companies. So we can set namespace /company if we are going to save company logo or something like that. and /users for saving user informations. The main purpose if to seperate files for some high level modules.
​​uniqueProperty is to save data to a unique folder for a unique user. We can pass  username for instance, so that we can in the future, get files for that user with his/her username. they are just for the convenience, to organize in a specific manner.

3. Upload file

Create a controller to upload file and save it to filesystem using fileUploadService
@PostMapping("/{userId}/uploadPhoto")
public String uploadPhoto(@Valid @ModelAttribute("userId") Long userId, BindingResult bindingResult,
                                  @RequestParam(value = "profilePicture", required = false) MultipartFile multipartFile,
                                   ) throws IOException {

    if (bindingResult.hasErrors()) {
        System.out.println(bindingResult.toString());
    }
    // set image
    if (ImageValidator.isImageValid(multipartFile)) {
        User user = this.userService.find(userId);
        UploadProperties properties = this.fileUploadService.uploadFile(multipartFile, UploadProperties.NameSpaces.USERS.getValue(), person.getPhoneNumber());
        user.setProfilePicturePath(properties.getFilePath());
        this.userService.save(user);
    }
   return "redirect:/users/"+userId;
}

4. Downloading/Showing image/file

// returns image with that entity id
@RequestMapping(value = "/images/{personId}", method = RequestMethod.GET)
private ResponseEntity<byte[]> getImage(@PathVariable("userId") Long userId) throws IOException {
    User user = this.userService.find(userId);
    if (user == null) return ResponseEntity.ok();
    File file = new File(user.getProfilePicturePath());
    if (!file.exists()) return ResponseEntity.noContent().build();
    return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(FileUtils.readFileToByteArray(file));
}

Please let me know if you face any problem.

Comments

Popular posts from this blog

Deploy Spring Boot app in digitalocean cloud (or any cloud as long asyou have ssh access)

Upload large files : Spring Boot

User activity logging: Spring