Spring Boot File Upload and Download REST API Tutorial
Introduction
File upload and download functionality is a common requirement in modern web applications.
Applications may need to allow users to upload:
- Profile pictures
- Documents
- PDFs
- Product images
- Invoices
- Reports
- Other files
Spring Boot makes it relatively simple to implement file handling through Spring MVC and the MultipartFile interface.
In this tutorial, we will build a simple Spring Boot File Upload and Download REST API.
You will learn how to:
-
Upload a file using
MultipartFile - Validate uploaded files
- Store files on the server
- Download files through a REST endpoint
- Handle missing files
- Restrict file size
- Return appropriate HTTP responses
- Apply file-upload security best practices
What is MultipartFile in Spring Boot?
MultipartFile is an interface provided by Spring that represents an uploaded file received through a multipart HTTP request.
It provides useful methods such as:
getOriginalFilename()
getContentType()
getSize()
getBytes()
getInputStream()
These methods allow your application to inspect and process uploaded files.
How File Upload Works
The basic process looks like this:
User Selects File ↓ HTTP Multipart Request ↓ Spring Boot Controller ↓ MultipartFile ↓ Validate File ↓ Store File ↓ Return Response
For downloading:
Client Request ↓ Download Endpoint ↓ Find File ↓ Read File ↓ HTTP Response ↓ Downloaded File
Create a Spring Boot Project
For this example, create a Spring Boot project with Spring Web.
The main dependency is:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
If you are using Spring Boot with Maven, place this inside the <dependencies> section of your pom.xml.
Create a File Storage Service
It is better to keep file-storage logic outside the controller.
Create:
FileStorageService.java
Example:
@Service public class FileStorageService { private final Path uploadPath = Paths.get("uploads"); public FileStorageService() throws IOException { Files.createDirectories(uploadPath); } public String storeFile(MultipartFile file) throws IOException { String fileName = StringUtils.cleanPath( file.getOriginalFilename()); Path targetLocation = uploadPath.resolve(fileName); Files.copy( file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); return fileName; } }
This service creates an uploads directory and stores uploaded files inside it.
Create the File Upload Controller
Now create:
FileController.java
Example:
@RestController @RequestMapping("/api/files") public class FileController { private final FileStorageService fileStorageService; public FileController( FileStorageService fileStorageService) { this.fileStorageService = fileStorageService; } @PostMapping("/upload") public ResponseEntity<String> uploadFile( @RequestParam("file") MultipartFile file) { try { String fileName = fileStorageService .storeFile(file); return ResponseEntity.ok( "File uploaded successfully: " + fileName); } catch (IOException ex) { return ResponseEntity .internalServerError() .body("Could not upload file."); } } }
Test the File Upload API
You can test the endpoint using Postman or another API client.
HTTP Method
POST
Endpoint
/api/files/upload
Select:
Body → form-data
Create a field named:
file
Change its type from Text to File, then select a file from your computer.
Example Response
A successful upload could return:
File uploaded successfully: employee-profile.jpg
Why Use form-data?
Files are normally uploaded using:
multipart/form-data
rather than sending the file as ordinary JSON.
A multipart request can contain both files and additional form fields.
For example:
file → employee.jpg name → Muhammad Zeeshan department → IT
Upload a File with Additional Data
You can accept additional request parameters along with the file.
@PostMapping("/upload") public ResponseEntity<String> uploadFile( @RequestParam("file") MultipartFile file, @RequestParam("description") String description) { // File processing return ResponseEntity.ok( "File uploaded successfully"); }
This allows a request to contain both file data and regular form values.
Validate the Uploaded File
Never blindly accept every uploaded file.
At minimum, check whether the file exists.
if (file.isEmpty()) { return ResponseEntity .badRequest() .body("Please select a file."); }
You should also consider checking:
- File size
- File extension
- MIME type
- Filename
- Storage location
Check File Size
Example:
long maxSize = 5 * 1024 * 1024; if (file.getSize() > maxSize) { return ResponseEntity .badRequest() .body("File size exceeds 5 MB."); }
Here, the maximum file size is approximately 5 MB.
Check the Content Type
You can inspect the uploaded file's MIME type.
String contentType = file.getContentType();
For example:
image/jpeg image/png application/pdf
However, don't rely on the client-provided content type alone for security-sensitive applications.
Configure Maximum Upload Size
Spring Boot allows multipart upload limits to be configured in:
application.properties
Example:
spring.servlet.multipart.max-file-size=5MB spring.servlet.multipart.max-request-size=10MB
The first property limits an individual uploaded file.
The second limits the overall multipart request.
Generate a Unique Filename
One important problem with file uploads is filename collision.
For example, two users could upload:
profile.jpg
Instead of using the original filename directly, generate a unique name.
Example:
String fileName = UUID.randomUUID() + "-" + StringUtils.cleanPath( file.getOriginalFilename());
The result could look like:
8b7d9f2a-profile.jpg
This reduces the chance of overwriting another file.
Download a File
Now let's create a download endpoint.
@GetMapping("/download/{fileName}") public ResponseEntity<Resource> downloadFile( @PathVariable String fileName) throws IOException { Path filePath = Paths.get("uploads") .resolve(fileName) .normalize(); Resource resource = new UrlResource( filePath.toUri()); if (!resource.exists()) { return ResponseEntity .notFound() .build(); } return ResponseEntity.ok() .body(resource); }
This endpoint reads the requested file and returns it as a resource.
Improve the Download Response
For a production REST API, you should provide an appropriate content type.
String contentType = Files.probeContentType( filePath);
Then:
return ResponseEntity.ok() .contentType( MediaType.parseMediaType( contentType)) .body(resource);
You can also tell the browser to download the file instead of displaying it.
.header( HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
Complete Download Example
@GetMapping("/download/{fileName}") public ResponseEntity<Resource> downloadFile( @PathVariable String fileName) throws IOException { Path filePath = Paths.get("uploads") .resolve(fileName) .normalize(); Resource resource = new UrlResource( filePath.toUri()); if (!resource.exists()) { return ResponseEntity .notFound() .build(); } String contentType = Files.probeContentType( filePath); if (contentType == null) { contentType = "application/octet-stream"; } return ResponseEntity.ok() .contentType( MediaType.parseMediaType( contentType)) .header( HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .body(resource); }
File Upload and Download Architecture
CLIENT │ ┌─────────┴─────────┐ ↓ ↓ Upload File Download File ↓ ↓ Controller Controller ↓ ↓ Validation File Lookup ↓ ↓ Service Resource ↓ ↓ File Storage HTTP Response
Where Should Uploaded Files Be Stored?
There are several options.
Local File System
Good for:
- Learning projects
- Small applications
- Development
Example:
/uploads
Database
Files can be stored as binary data, although this isn't always the best choice for large files.
Cloud Object Storage
Production applications often use object storage services for uploaded files.
Examples include:
- Amazon S3
- Google Cloud Storage
- Azure Blob Storage
For a large-scale application, separating file storage from the application server can make scaling easier.
File Upload Security Best Practices
File uploads can create serious security risks if implemented incorrectly.
Never Trust the Original Filename
Don't use user-provided filenames directly as storage paths.
Generate Unique Names
Use UUIDs or another safe naming strategy.
Restrict File Types
Only allow file types your application actually needs.
Limit File Size
Large uploads can consume server resources.
Store Files Outside Executable Directories
Uploaded content should not be treated as executable application code.
Validate File Content
For security-sensitive applications, don't rely solely on filename extensions or client-provided MIME types.
Protect Download Endpoints
If files contain private information, require authentication and authorization before allowing downloads.
Example API Endpoints
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /api/files/upload | Upload a file |
| GET | /api/files/download/{fileName} | Download a file |
Common Errors
File Size Exceeded
If the uploaded file exceeds the configured limit, Spring Boot can reject the request.
Make sure your multipart configuration is appropriate for your application.
File Not Found
Return:
404 Not Found
when the requested file doesn't exist.
Invalid File Type
Return:
400 Bad Request
when the uploaded file doesn't meet your application's requirements.
File Upload with Authentication
If you've followed our Spring Security and JWT tutorials, you can protect the upload endpoint.
For example:
.requestMatchers( "/api/files/upload") .hasRole("USER")
Now only authenticated users with the appropriate role can upload files.
This connects our file-upload tutorial with the security content cluster.
Best Practices for Production
For a production application:
- Validate every upload.
- Limit file size.
- Generate unique filenames.
- Avoid trusting user-provided paths.
- Protect private files.
- Use HTTPS.
- Log upload failures.
- Consider cloud object storage for large applications.
- Scan files when your application's security requirements call for malware detection.
- Never allow uploaded content to execute as application code.
Frequently Asked Questions
What is MultipartFile in Spring Boot?
MultipartFile represents a file uploaded through a multipart HTTP request.
How do I upload a file in Spring Boot?
Create a POST endpoint and receive the file with @RequestParam("file") MultipartFile file.
What is multipart/form-data?
It is an HTTP content type commonly used when sending files and form fields in the same request.
Can Spring Boot upload multiple files?
Yes. Multiple MultipartFile values can be accepted by an endpoint.
Where should files be stored?
For simple applications, local storage can be sufficient. Production applications may benefit from dedicated object storage.
Should uploaded files be stored in MySQL?
It depends on the application. For many applications, storing file metadata in MySQL and the actual files in dedicated storage is more practical for large files.
Conclusion
Spring Boot offers a straightforward approach to implementing file upload and download functionality using MultipartFile, Spring MVC, and REST endpoints.
A production-ready implementation should go beyond simply accepting a file. File size, file type, filename handling, storage, authentication, authorization, and security must all be considered.
Once you understand these concepts, you can extend the API to support profile pictures, documents, invoices, product images, and other real-world file-management requirements.
