📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.
🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.
▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube
Learn and master in Spring boot at Spring Boot Tutorial
The source code of this tutorial available on my GitHub Repository.
Table of Contents
- Tools and Technologies Used
- Create and Import Spring Boot Project
- Project Directory Structure
- The pom.xml File
- Configuring Server and File Storage Properties
- Automatically binding properties to a POJO class
- Writing APIs for File Upload and Download
- Service for Storing Files in the FileSystem and retrieving them
- Custom Exception Classes
- Running the Application and Testing the APIs via Postman
1. Tools and Technologies Used
- Spring Boot 3+
- JDK - 17 or later
- Spring Framework - 6+
- Maven - 3.2+
- IDE - Eclipse or Spring Tool Suite (STS)
2. Create and Import Spring Boot Project
- Generate: Maven Project
- Java Version: 17 (Default)
- Spring Boot: 3.0.4
- Group: net.javaguides.springboot
- Artifact: springboot-upload-download-file-rest-api-example
- Name: sspringboot-upload-download-file-rest-api-example
- Description: springboot-upload-download-file-rest-api-example
- Package Name : net.guides.springboot.springbootfileupload
- Packaging: jar (This is the default value)
- Dependencies: Web
3. Project Directory Structure
4. The pom.xml File
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.javaguides.springboot</groupId>
<artifactId>springboot-upload-download-file-rest-api-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-upload-download-file-rest-api-example</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
5. Configuring Server and File Storage Properties
## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=200MB
# Max Request Size
spring.servlet.multipart.max-request-size=215MB
## File Storage Properties
file.upload-dir=./uploads
server.port=8081
6. Automatically binding properties to a POJO class
package net.javaguides.springboot.fileuploaddownload.property;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "file")
public class FileStorageProperties {
private String uploadDir;
public String getUploadDir() {
return uploadDir;
}
public void setUploadDir(String uploadDir) {
this.uploadDir = uploadDir;
}
}
7. Writing APIs for File Upload and Download
7.1 File Upload Rest API
Let’s now write the REST APIs for uploading single as well as multiple files. Create a new controller class called FileUploadController inside net.javaguides.springboot.fileuploaddownload.controller package and add following code to it:package net.javaguides.springboot.fileuploaddownload.controller;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import net.javaguides.springboot.fileuploaddownload.payload.Response;
import net.javaguides.springboot.fileuploaddownload.service.FileStorageService;
@RestController
public class FileUploadController {
@Autowired
private FileStorageService fileStorageService;
@PostMapping("/uploadFile")
public Response uploadFile(@RequestParam("file") MultipartFile file) {
String fileName = fileStorageService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/downloadFile/")
.path(fileName)
.toUriString();
return new Response(fileName, fileDownloadUri,
file.getContentType(), file.getSize());
}
@PostMapping("/uploadMultipleFiles")
public List < Response > uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
return Arrays.asList(files)
.stream()
.map(file - > uploadFile(file))
.collect(Collectors.toList());
}
}
7.2 File Download Rest API
Let’s now write the REST API for downloading a file. Create a new controller class called FileDownloadController inside net.javaguides.springboot.fileuploaddownload.controller package and add following code to it:package net.javaguides.springboot.fileuploaddownload.controller; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import net.javaguides.springboot.fileuploaddownload.service.FileStorageService; @RestController public class FileDownloadController { private static final Logger logger = LoggerFactory.getLogger(FileDownloadController.class); @Autowired private FileStorageService fileStorageService; @GetMapping("/downloadFile/{fileName:.+}") public ResponseEntity < Resource > downloadFile(@PathVariable String fileName, HttpServletRequest request) { // Load file as Resource Resource resource = fileStorageService.loadFileAsResource(fileName); // Try to determine file's content type String contentType = null; try { contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath()); } catch (IOException ex) { logger.info("Could not determine file type."); } // Fallback to the default content type if type could not be determined if (contentType == null) { contentType = "application/octet-stream"; } return ResponseEntity.ok() .contentType(MediaType.parseMediaType(contentType)) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .body(resource); } }
7.3 Create Response
This Response class used to return responses from the /uploadFile and /uploadMultipleFiles APIs.Let's create Response class inside net.javaguides.springboot.fileuploaddownload.payload package with the following contents:
public class Response { private String fileName; private String fileDownloadUri; private String fileType; private long size; public Response(String fileName, String fileDownloadUri, String fileType, long size) { this.fileName = fileName; this.fileDownloadUri = fileDownloadUri; this.fileType = fileType; this.size = size; } // Getters and Setters (Omitted for brevity) }
8. Service for Storing Files in the FileSystem and retrieving them
package net.javaguides.springboot.fileuploaddownload.service;
import java.io.IOException;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import net.javaguides.springboot.fileuploaddownload.exception.FileStorageException;
import net.javaguides.springboot.fileuploaddownload.exception.FileNotFoundException;
import net.javaguides.springboot.fileuploaddownload.property.FileStorageProperties;
@Service
public class FileStorageService {
private final Path fileStorageLocation;
@Autowired
public FileStorageService(FileStorageProperties fileStorageProperties) {
this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
.toAbsolutePath().normalize();
try {
Files.createDirectories(this.fileStorageLocation);
} catch (Exception ex) {
throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex);
}
}
public String storeFile(MultipartFile file) {
// Normalize file name
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
try {
// Check if the file's name contains invalid characters
if (fileName.contains("..")) {
throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
}
// Copy file to the target location (Replacing existing file with the same name)
Path targetLocation = this.fileStorageLocation.resolve(fileName);
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
return fileName;
} catch (IOException ex) {
throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
}
}
public Resource loadFileAsResource(String fileName) {
try {
Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
Resource resource = new UrlResource(filePath.toUri());
if (resource.exists()) {
return resource;
} else {
throw new FileNotFoundException("File not found " + fileName);
}
} catch (MalformedURLException ex) {
throw new FileNotFoundException("File not found " + fileName, ex);
}
}
}
9. Custom Exception Classes
FileNotFoundException
package net.javaguides.springboot.fileuploaddownload.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class FileNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1 L;
public FileNotFoundException(String message) {
super(message);
}
public FileNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
FileStorageException
package net.javaguides.springboot.fileuploaddownload.exception;
public class FileStorageException extends RuntimeException {
private static final long serialVersionUID = 1 L;
public FileStorageException(String message) {
super(message);
}
public FileStorageException(String message, Throwable cause) {
super(message, cause);
}
}
To know more about exception handling in Spring boot then check out Spring Boot 2 Exception Handling for REST APIs
10. Running the Application and Testing the APIs via Postman
mvn spring-boot:run
Can I write down the source of the blog and post it on my technical blog?
ReplyDelete