File Upload, Download, and Web Extensions in Spring Boot 3
Introduction
Most backend services need more than CRUD JSON APIs. You often need file upload/download, request interception, and cross-cutting web hooks for logging, authentication context, and request lifecycle tracking. In this chapter, you will implement practical file endpoints and understand when to use interceptors, filters, and listeners in Spring Boot 3.
Prerequisites
- Completed:
06_spring_mvc_basics_annotations_and_routing.md07_validation_and_global_exception_handling.md
- A running Spring Boot 3 project with
spring-boot-starter-web
Multipart Upload Basics
Spring Boot supports file upload through MultipartFile.
Configure upload limits
In application.yml:
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MBEquivalent in .properties:
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=20MBSingle File Upload Endpoint
Request example:
curl -X POST http://localhost:8080/api/files/upload \
-F "file=@/path/to/avatar.png"Multiple File Upload
For batch upload:
@PostMapping("/upload-batch")
public ResponseEntity<Map<String, Object>> uploadBatch(@RequestParam("files") MultipartFile[] files) {
return ResponseEntity.ok(Map.of("count", files.length));
}You can iterate and reuse the single-file storage logic.
File Download Endpoint
Security Notes for File APIs
File APIs are common attack surfaces. Protect them with:
- file size limits
- extension allowlist (for example only
.png,.jpg,.pdf) - storage path normalization and traversal checks
- virus scanning (for enterprise scenarios)
Warning
Path Traversal Risk
Never trust raw file names from clients. Always normalize paths and prevent ../ traversal outside the upload root.
Serve Static Resources
By default, Spring Boot serves static files from:
src/main/resources/staticsrc/main/resources/public
Example:
src/main/resources/static/logo.pngThen accessible at:
GET /logo.pngFor user-uploaded files, avoid exposing arbitrary disk paths directly. Prefer controlled download endpoints.
Interceptor vs Filter vs Listener
These are common extension points in web apps:
| Component | Layer | Typical use |
|---|---|---|
| Filter | Servlet container level | CORS, encoding, low-level request wrapping |
| Interceptor | Spring MVC level | auth checks, request timing, user context in MVC flow |
| Listener | Servlet lifecycle events | startup hooks, session lifecycle tracking |
Create a Simple Interceptor
Register it:
Simple Filter Example
Filters execute before MVC routing, so they are ideal for generic request/response concerns.
Common Upload/Download Errors
Maximum upload size exceeded
- Increase multipart limits in config
- Confirm reverse proxy (for example Nginx) allows same size
Download returns 404 but file exists
- Check storage path and working directory
- Log absolute path to verify expected location
Uploaded filename appears garbled
- Set proper request encoding and test with UTF-8 filenames
Best Practices
- Store uploaded files with generated names (UUID), keep original name as metadata
- Separate file metadata (DB) and binary storage (disk/object storage)
- Use object storage (S3/OSS/MinIO) for scalable production systems
- Add auth checks for upload/download endpoints
- Audit upload and download operations
Quick Recap
In this chapter, you learned:
- Multipart upload config and endpoints
- Controlled file download responses
- Static resource behavior
- Core differences between interceptor/filter/listener
- Practical extension patterns for request processing
Next chapter will cover content negotiation and custom HttpMessageConverter support for multiple response formats.
FAQ
Should files be stored in the database?
Small files can be, but most systems store file binaries in object storage and keep metadata in relational tables.
Interceptor or filter for authentication?
Both can work. In Spring MVC APIs, interceptors are often simpler for route-level logic. Security frameworks (Spring Security) usually handle auth in filter chains.
Can I directly expose /uploads as static files?
Possible, but risky unless you strictly control access and file types. Controlled download endpoints are safer.
Why use UUID file names?
To avoid collisions and reduce risks from user-provided names.
Do I need listener in every project?
No. Use listeners when you need app/session lifecycle hooks; many APIs can run without custom listeners.