Six Practical File Upload and Download Solutions for Spring Boot
This article presents six commonly used file upload and download techniques for Spring Boot, covering basic Multipart handling, stream-based download, integration with Alibaba Cloud OSS and MinIO, as well as high‑concurrency chunked uploads with Nginx, each accompanied by complete code examples and usage scenarios.
File upload and download may seem trivial, but implementing them correctly in a large framework like Spring Boot can be challenging; improper handling can lead to lost files, slow uploads, or time‑outs that jeopardize a project.
1. Basic File Upload: Multipart + Spring Boot Controller
Applicable Scenario
Simple file upload without complex requirements, such as a standard form submission or API endpoint.
Code Example
@RestController
public class FileUploadController {
// Spring Boot default file upload
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) throws IOException {
// Get original file name
String fileName = file.getOriginalFilename();
// Define local storage path
String savePath = "D:/uploads/" + fileName;
// Save file locally
File dest = new File(savePath);
file.transferTo(dest);
return "Upload successful! Saved path: " + savePath;
}
}Explanation
The code leverages Spring Boot's built‑in MultipartFile handling to store small files directly on the server with minimal configuration.
2. File Download: InputStream + OutputStream
Applicable Scenario
When you need to provide a download endpoint that controls streaming, supports large files, or applies custom headers.
Code Example
@GetMapping("/download")
public void downloadFile(HttpServletResponse response) throws IOException {
String filePath = "D:/uploads/sample.txt";
File file = new File(filePath);
if (!file.exists()) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
InputStream inputStream = new FileInputStream(file);
OutputStream outputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
}Explanation
This implementation manually reads the file via InputStream and writes it to the HTTP response using OutputStream , giving precise control over the download process.
3. File Upload + OSS: Spring Boot Integration with Alibaba Cloud OSS
Applicable Scenario
Storing files in the cloud for large‑scale access and reducing server load.
Maven Dependency
com.aliyun
aliyun-sdk-oss
3.10.2Code Example
@RestController
public class OssFileUploadController {
@Value("${aliyun.oss.endpoint}") private String endpoint;
@Value("${aliyun.oss.access-key-id}") private String accessKeyId;
@Value("${aliyun.oss.access-key-secret}") private String accessKeySecret;
@Value("${aliyun.oss.bucket-name}") private String bucketName;
@PostMapping("/uploadToOss")
public String uploadFileToOss(@RequestParam("file") MultipartFile file) {
try {
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
String fileName = file.getOriginalFilename();
InputStream inputStream = file.getInputStream();
ossClient.putObject(bucketName, fileName, inputStream);
ossClient.shutdown();
return "File uploaded to OSS successfully! File name: " + fileName;
} catch (Exception e) {
e.printStackTrace();
return "Upload failed: " + e.getMessage();
}
}
}Explanation
The controller reads OSS configuration from properties, creates an OSSClient , and uploads the received file to the specified bucket.
4. File Download + OSS: Direct Download from OSS
Applicable Scenario
When files have already been stored in OSS and need to be served to clients without involving the application server's storage.
Code Example
@GetMapping("/downloadFromOss")
public void downloadFileFromOss(@RequestParam("fileName") String fileName, HttpServletResponse response) {
try {
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
OSSObject ossObject = ossClient.getObject(bucketName, fileName);
InputStream inputStream = ossObject.getObjectContent();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
OutputStream outputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
ossClient.shutdown();
} catch (IOException e) {
e.printStackTrace();
}
}Explanation
The method fetches the object from OSS, streams it directly to the HTTP response, and thus offloads storage responsibilities to the cloud.
5. File Upload + MinIO: Distributed Storage Solution
Applicable Scenario
When a self‑hosted, S3‑compatible storage is preferred over public cloud services.
Maven Dependency
io.minio
minio
8.0.3Code Example
@RestController
public class MinioFileUploadController {
@Value("${minio.url}") private String minioUrl;
@Value("${minio.access-key}") private String accessKey;
@Value("${minio.secret-key}") private String secretKey;
@Value("${minio.bucket-name}") private String bucketName;
@PostMapping("/uploadToMinio")
public String uploadToMinio(@RequestParam("file") MultipartFile file) {
try {
MinioClient minioClient = MinioClient.builder()
.endpoint(minioUrl)
.credentials(accessKey, secretKey)
.build();
String fileName = file.getOriginalFilename();
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build()
);
return "File uploaded to MinIO successfully, file name: " + fileName;
} catch (Exception e) {
e.printStackTrace();
return "Upload failed: " + e.getMessage();
}
}
}Explanation
MinIO uses the same S3‑compatible API as OSS; the code creates a MinioClient and stores the file in a private bucket.
6. High‑Concurrency File Upload: Spring Boot + Nginx + Chunked Upload
Applicable Scenario
Large files or many simultaneous uploads where a single request would time out; chunked uploading splits the file into smaller parts.
Front‑end JavaScript Example
// Front‑end chunked upload example
const uploadFile = (file) => {
const chunkSize = 1024 * 1024; // 1 MB per chunk
let start = 0;
let end = chunkSize;
const totalChunks = Math.ceil(file.size / chunkSize);
const uploadNextChunk = () => {
const formData = new FormData();
formData.append('file', file.slice(start, end));
fetch('/uploadChunk', {
method: 'POST',
body: formData
}).then(response => {
if (response.ok) {
start = end;
end = start + chunkSize;
if (start < file.size) {
uploadNextChunk(); // recurse
} else {
alert('File upload completed!');
}
} else {
alert('Upload failed!');
}
});
};
uploadNextChunk(); // start uploading
};Back‑end Spring Boot Chunk Handler
@RestController
public class FileUploadController {
@PostMapping("/uploadChunk")
public String uploadChunk(@RequestParam("file") MultipartFile file) {
try {
String fileName = "bigfile_part_" + System.currentTimeMillis();
String savePath = "D:/uploads/" + fileName;
File dest = new File(savePath);
file.transferTo(dest);
return "Chunk uploaded successfully: " + fileName;
} catch (IOException e) {
e.printStackTrace();
return "Upload failed: " + e.getMessage();
}
}
}Explanation
The front‑end slices the file and sends each chunk via fetch ; the back‑end stores each chunk locally. After all chunks are received, they can be merged into the final file, enabling reliable high‑throughput uploads.
Conclusion
The article covered six different file upload/download tools, ranging from basic local storage to cloud‑based OSS/MinIO solutions and high‑concurrency chunked uploads. For simple needs, Spring Boot's built‑in Multipart and OSS integration are sufficient; for more complex or large‑scale scenarios, MinIO or chunked uploads with Nginx provide greater control and scalability.
Regardless of project size, handling file transfer correctly is crucial to avoid later stability problems; the provided code snippets give a solid starting point for implementation.
Promotional note: If you are preparing for a Java interview, the site ddkk.com offers over 10,000 Java interview questions and a comprehensive set of tutorials for free.
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.