11

File Uploads and Retrieval in Spring Boot

In modern web applications, handling file uploads and downloads is a core requirement. This article explores how to implement these…

In modern web applications, handling file uploads and downloads is a core requirement. This article explores how to implement these features using Spring Boot REST controllers, following a “core-to-shell” approach by starting with fundamental Java NIO operations and building a robust solution around them.

The Core Logic: File Storage

The foundation of any file upload system is the ability to move data from an input stream to a physical location on the server. The Files.copy method from the Java NIO package is the most efficient tool for this task.

Handling Streams: to save the file data.

Files.copy(inputStream //Stream data of file
	, destination //Path of the destination
	, StandardCopyOption.REPLACE_EXISTING); //Copy option

Other kind of storage like S3 buckets can also be used, that will cover in upcoming posts.

Directory Management: Before copying, ensure the destination directory exists by using

Files.createDirectories(destination.getParent())

Implementing the Upload REST Controller

To handle uploads, we use the @PostMapping annotation and the MultipartFile interface, which allows us to intercept the file from an HTTP request.

Basic Upload with Size Validation

It is a best practice to validate file sizes before processing to prevent server strain.

@PostMapping("/upload")
public ResponseEntity<Object> upload(@RequestParam("file") MultipartFile file) {
	// Example: Restricting file size to 5MB programmatically
	if(file.getSize() < 1024 * 1024 * 5) { 
        InputStream inputStream = file.getInputStream();
        // logic to save file...
    }
}

You can also restrict file sizes globally in your application.properties using: spring.servlet.multipart.max-file-size=10MB.


Complete Implementation

Combining validation, directory creation, and error handling results in a production-ready method:

@PostMapping("/upload")
public ResponseEntity<Object> upload(@RequestParam("file") MultipartFile file) {
    if(file.getSize() < 1024 * 1024 * 5) {
        try (InputStream inputStream = file.getInputStream()) {
            Path destinationFile = Paths.get(rootPath).resolve(file.getOriginalFilename()); //rootpath from application.properties
            Files.createDirectories(destinationFile.getParent());
            Files.copy(inputStream, destinationFile, StandardCopyOption.REPLACE_EXISTING);
            log.debug("File uploaded successfully");
            return ResponseEntity.ok().build();
        } catch(IOException ex) {
            return ResponseEntity.internalServerError().body("Error uploading");
        }
    } else {
        return ResponseEntity.badRequest().body("File size limit reached: 5MB");
    }
}

Strategies for Fetching Files

Once files are stored, they need to be served back to the user. There are two primary strategies for this:

  1. Direct Path Access: Useful for publicly available locations.
  2. Binary Stream via REST: Preferred when you need to perform security checks or basic validation before serving the file.

Serving Files as a Resource

To send a file’s binary data back through a REST call, use the UrlResource class.

Resource file = new UrlResource(destination.toUri());
if (!resource.exists() && !resource.isReadable()) {
    return ResponseEntity.internalServerError().body("File not found");
}
return ResponseEntity.ok()
    .contentType(MediaType.parseMediaType("image/jpeg"))
    .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + file.getFilename() + "\"")
    .body(file);

Using Classpath Fallbacks

If a specific user-uploaded file is missing, you can serve a default fallback (like a generic profile picture) from your project’s resource folder:

Resource file = new ClassPathResource("user.jpg");

Ashish Sharma

I’ve always believed that collaboration is the engine of progress. While many say knowledge is power, I believe the true power lies in its distribution. To that end, I am building a curated knowledge base of my professional journey—refined by AI for maximum clarity and depth. Whether you’re here to master a new skill or sharpen an existing one, my goal is to provide a roadmap for your success. This collection will evolve as I do, and I welcome your insights and dialogue as we grow together.

Leave a Reply

Your email address will not be published. Required fields are marked *