Fast Large‑File Chunked Upload with Spring Boot and MinIO
This article walks through setting up MinIO, installing it via Docker on CentOS 7, configuring Spring Boot, and implementing chunked, instant‑resume, and resumable uploads for large files, complete with code examples, Docker commands, and troubleshooting tips.
Overview
MinIO is an open‑source object storage server that runs on Linux, Windows, and macOS. It offers simple installation, high scalability, high availability, SSL/TLS encryption, access control, and multi‑language SDKs (Java, Python, Ruby, Go).
Application Scenarios
Massive data storage for enterprises.
Image, audio, and video media storage.
Cloud‑native applications integrated with Kubernetes, Docker Swarm, etc.
Data protection and disaster recovery using multi‑replica writes and erasure coding.
Big‑Data, AI, and ML workloads via S3 Select and HDFS interfaces.
Chunked Upload with Spring Boot and MinIO
The process consists of the following steps:
Front‑end splits the file into multiple chunks and generates a unique identifier for each chunk.
Each chunk is uploaded to MinIO using the Java SDK; the object key combines the base name and the chunk ID.
After all chunks are uploaded, a back‑end API merges them into the final file, either on the application server or using MinIO’s built‑in compose feature.
Instant upload (秒传) is achieved by checking the file name and MD5 hash on the back‑end before uploading; if the file already exists, the URL is returned directly.
Resumable upload (续传) records uploaded chunk indices and status flags; when a network interruption occurs, uploading resumes from the next missing chunk.
Error handling covers service failures, network timeouts, and client exceptions to ensure a smooth upload experience.
CentOS 7 MinIO Installation via Docker
mkdir minioPull the MinIO image:
docker search minio docker pull minio/minioRun the container:
docker run -p 9000:9000 -p 9090:9090 \
--net=host \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=IT@WangHui" \
-e "MINIO_SECRET_KEY=IT@WangHui" \
minio/minio server /data --console-address ":9000" -address ":9090"Access the MinIO console at http://localhost:9000. Ensure the firewall allows ports 9000 and 9090:
firewall-cmd --zone=public --add-port=9000/tcp --permanent
firewall-cmd --zone=public --add-port=9090/tcp --permanent
firewall-cmd --reloadSpring Boot Environment Setup
Add the MinIO Java client dependency (version 8.5.2) to pom.xml:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.2</version>
</dependency>Configure the server and MinIO properties in application.yml (example values shown):
server:
port: 8080
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
minio:
access-key: dAMaxkWaXUD1CV1JHbqw
secret-key: AXt3SD0JFkDENFbMeJKOOQb5wj8KvabZWu33Rs84
url: http://192.168.18.14:9090
bucket-name: wanghuiMinIO Configuration Class
package com.xiaohui.config;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.minio")
public class MinioConfig {
private String accessKey;
private String secretKey;
private String url;
private String bucketName;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(url)
.credentials(accessKey, secretKey)
.build();
}
}Utility Class for MinIO Operations
package com.xiaohui.utils;
import io.minio.*;
import io.minio.http.Method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@Component
public class MinioUtils {
@Autowired
private MinioClient minioClient;
@Autowired
private MinioConfig configuration;
public boolean existBucket(String name) {
try {
boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
if (!exists) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
return true;
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void upload(MultipartFile file, String fileName) {
try (InputStream in = file.getInputStream()) {
minioClient.putObject(PutObjectArgs.builder()
.bucket(configuration.getBucketName())
.object(fileName)
.stream(in, file.getSize(), -1)
.contentType(file.getContentType())
.build());
} catch (Exception e) {
e.printStackTrace();
}
}
public ResponseEntity<byte[]> download(String fileName) {
// Implementation omitted for brevity – see source for full code handling streams and headers.
return null;
}
public String getFileUrl(String objectFile) {
try {
return minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(configuration.getBucketName())
.object(objectFile)
.build());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}Controller Layer
package com.xiaohui.controller;
import com.xiaohui.utils.AjaxResult;
import com.xiaohui.utils.MinioUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
@CrossOrigin
@RestController
@RequestMapping("/api")
public class MinioFileUploadController {
@Autowired
private MinioUtils minioUtils;
@GetMapping("/upload")
public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, String fileName) {
minioUtils.upload(file, fileName);
return AjaxResult.success("Upload successful");
}
@GetMapping("/dowload")
public ResponseEntity<byte[]> dowloadFile(@RequestParam("fileName") String fileName) {
return minioUtils.download(fileName);
}
@GetMapping("/getUrl")
public AjaxResult getFileUrl(@RequestParam("fileName") String fileName) {
HashMap<String, String> map = new HashMap<>();
map.put("FileUrl", minioUtils.getFileUrl(fileName));
return AjaxResult.success(map);
}
}Functional Testing
After deploying the Docker container and starting the Spring Boot application, large files are uploaded in chunks, merged, and can be accessed via the generated URLs. Screenshots in the original article show successful uploads and the resulting file URLs.
Key Takeaways
MinIO provides a lightweight, S3‑compatible storage backend suitable for large‑file handling.
Chunked upload, instant‑upload, and resumable upload are implemented by combining front‑end slicing with back‑end merging logic.
Docker simplifies MinIO deployment on CentOS 7; firewall configuration is essential.
Spring Boot integration uses the MinIO Java SDK, configuration properties, and utility wrappers for bucket management, file upload, download, and URL generation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer XiaoFu
xiaofucode.com – a programmer learning guide driven by the pursuit of profit
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.
