Handling Image File Uploads to Local Storage in Spring Boot

Controller Endpoint Configuration

To begin, define a REST endpoint that accepts a MultipartFile object. The controller layer acts as the interface for the client, delegating the actual storage logic to the service layer.

@PostMapping("/api/files/upload")
public ResponseEntity<String> handleAvatarUpload(@RequestParam("imageFile") MultipartFile imageFile) {
    String relativePath = fileStorageService.storeFile(imageFile);
    return ResponseEntity.ok(relativePath);
}

Service Layer Implementation

The service layer contains the core business logic for processing the upload. This includes validating the file format, generating a unique filename to prevent overwriting exisitng files, and persisting the data to the local filesystem.

public String storeFile(MultipartFile imageFile) {
    // 1. Define permitted image formats
    Set<String> allowedExtensions = Set.of("jpg", "jpeg", "png", "gif", "bmp");

    String originalFilename = imageFile.getOriginalFilename();
    String fileExtension = extractExtension(originalFilename).toLowerCase();

    // 2. Validate file type
    if (!allowedExtensions.contains(fileExtension)) {
        log.error("Unsupported file format detected: {}", fileExtension);
        throw new UnsupportedMediaTypeException("Invalid image type");
    }

    // 3. Generate a unique identifier for the file
    String fileId = UUID.randomUUID().toString();
    String targetFilename = fileId + "." + fileExtension;

    // 4. Determine the storage directory (current working directory)
    String baseDirectory = System.getProperty("user.dir");
    String storageFolder = baseDirectory + File.separator + "user_avatars";
    File destination = new File(storageFolder, targetFilename);

    // 5. Ensure directories exist
    if (!destination.getParentFile().exists()) {
        destination.getParentFile().mkdirs();
    }

    try {
        // 6. Transfer the file stream to the destination
        imageFile.transferTo(destination);
        
        // Return the relative path for frontend consumption
        return File.separator + "user_avatars" + File.separator + targetFilename;
    } catch (IOException e) {
        log.error("File system write failure for {}", targetFilename, e);
        throw new FileStorageException("Failed to save image");
    }
}

private String extractExtension(String filename) {
    return Optional.ofNullable(filename)
            .filter(f -> f.contains("."))
            .map(f -> f.substring(filename.lastIndexOf(".") + 1))
            .orElse("");
}

While this implementation specifically targets image validation for avatar uploads, it can be adapted for generic file handling by removing the extension vaildation step.

Tags: spring-boot MultipartFile file-upload java-io

Posted on Wed, 30 Sep 2026 16:53:35 +0000 by meow