📘 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 TutorialWe’ll first build the REST APIs for uploading and downloading files, and then test those APIs using 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
- Project: Select Maven
- Java Version: 17(Default)
- Spring Boot Version: 3.04
- Group: net.javaguides.springboot
- Artifact: springboot-upload-download-file-rest-api-example
- Name: springboot-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
File Upload Rest API
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());
}
}
File Download Rest API
package net.javaguides.springboot.fileuploaddownload.controller; import java.io.IOException; import jakarta.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); } }
Response
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
1. Upload File
2. Upload Multiple Files
3. Download the File
Conclusion
Learn and master in Spring boot at Spring Boot Tutorial
your guide is not up to date compared to github files... mind check that out?
ReplyDeleteThanks a lot. I really did benefited from this tutorial.
ReplyDeleteand It's work ^^
I've just a little problem at the download GET request,
I always get a 403 Forbidden status (with Postman)
If u have any idea where it can be the problem
*nb I used exactly the same code
I always get a 404 not found status (with Postman)*
DeleteMay be video tutorial will help to your issues.
DeleteCan you please tell how can I integerate it with authentication
ReplyDeleteIt would have been great if there were explainatory comments in the code.Would have been even better.
ReplyDelete