Storing Files

Building on our previous work with the StorageService interface, we'll now create a concrete implementation that stores files on disk for our restaurant review platform.

Creating the Service Implementation

The implementation of file storage requires a dedicated service class to handle the file operations effectively.

First, let's create a new package com.devtiro.restaurant.services.impl to house our service implementations.

Within this package, we'll create the FileSystemStorageService class that implements our StorageService interface:

@Service @Slf4j public class FileSystemStorageService implements StorageService { @Value("${app.storage.location:uploads}") private String storageLocation; private Path rootLocation; }

The @Value annotation lets us configure the storage location through application properties, with a default value of "uploads" if not specified.

Initializing Storage Location

Before we can store files, we need to ensure our storage directory exists.

We'll use the @PostConstruct annotation to initialize our storage location after the bean is created:

@PostConstruct public void init() { rootLocation = Paths.get(storageLocation); try { Files.createDirectories(rootLocation); } catch (IOException e) { throw new StorageException("Could not initialize storage location", e); } }

We use @PostConstruct instead of the constructor because we need to ensure all properties are injected before initialization.

Implementing File Storage

The store method handles the actual file storage operation:

@Override public String store(MultipartFile file, String filename) { try { // Check for empty files if (file.isEmpty()) { throw new StorageException("Failed to store empty file"); } // Create final filename with extension String extension = StringUtils.getFilenameExtension(file.getOriginalFilename()); String finalFilename = filename + "." + extension; // Resolve and normalize the destination path Path destinationFile = this.rootLocation.resolve(Paths.get(finalFilename)) .normalize().toAbsolutePath(); // Security check to prevent directory traversal if (!destinationFile.getParent().equals(this.rootLocation.toAbsolutePath())) { throw new StorageException("Cannot store file outside current directory"); } // Copy the file to the destination try (InputStream inputStream = file.getInputStream()) { Files.copy(inputStream, destinationFile, StandardCopyOption.REPLACE_EXISTING); } return finalFilename; } catch (IOException e) { throw new StorageException("Failed to store file", e); } }

This implementation includes several safety checks and uses our previously created StorageException for error handling.

Security and Management Considerations

While our implementation focuses on basic functionality, there are several important considerations for production environments:

  • Files should be scanned for malware before storage
  • File sizes should be limited to prevent disk space issues
  • File types should be validated to prevent security vulnerabilities
  • Proper file permissions should be set to protect stored data

Summary

  • Implemented FileSystemStorageService to store files on disk
  • Used @Value annotation to configure storage location path
  • Initialized storage directory with @PostConstruct
  • Implemented secure file storage with path validation
  • Added error handling using StorageException
© 2026 Devtiro Ltd. All rights reserved