请关注微信公众号:拾荒的小海螺
博客地址:http://lsk-ww.cn/
1、简述
在现代 Web 应用中,大文件上传是一个常见的需求。传统的文件上传方式在面对大文件时往往效率低下,并且容易出现超时或失败的问题。通过文件切片上传技术,我们可以将大文件分割成多个小块并行上传,大大提高上传速度和稳定性。本文将介绍如何使用 Spring Boot 和 Minio 实现文件切片极速上传。
2、环境准备
- Spring Boot 项目配置
创建一个新的 Spring Boot 项目,并在 pom.xml 中添加必要的依赖:
bash
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.0</version>
</dependency>
</dependencies>
- Minio 安装与配置
下载并安装 :http://lsk-ww.cn/archives/136913647
访问 Minio 管理控制台并创建一个存储桶(bucket)。
3、实现文件切片上传
3.1 配置 Minio 客户端
在 Spring Boot 项目中,配置 Minio 客户端:
bash
import io.minio.MinioClient;
import io.minio.errors.MinioException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MinioConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
在 application.properties 文件中添加 Minio 配置信息:
bash
minio.endpoint=http://localhost:9000
minio.accessKey=YOUR_ACCESS_KEY
minio.secretKey=YOUR_SECRET_KEY
3.2 文件切片上传接口
创建一个控制器来处理文件切片上传请求:
bash
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.MinioException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
@RestController
@RequestMapping("/upload")
public class UploadController {
@Autowired
private MinioClient minioClient;
@PostMapping("/chunk")
public String uploadChunk(@RequestParam("file") MultipartFile file,
@RequestParam("chunkIndex") int chunkIndex,
@RequestParam("chunkTotal") int chunkTotal,
@RequestParam("identifier") String identifier) {
try {
String bucketName = "mybucket";
String objectName = identifier + "/" + chunkIndex;
InputStream inputStream = file.getInputStream();
minioClient.putObject(
PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build());
return "Chunk " + chunkIndex + " uploaded successfully.";
} catch (MinioException | IOException e) {
e.printStackTrace();
return "Error: " + e.getMessage();
}
}
}
3.3 合并文件切片
当所有文件切片上传完成后,需要合并这些切片形成完整文件:
bash
import io.minio.ComposeObjectArgs;
import io.minio.ComposeSource;
import io.minio.errors.MinioException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.ArrayList;
import java.util.List;
@PostMapping("/merge")
public String mergeChunks(@RequestParam("identifier") String identifier,
@RequestParam("chunkTotal") int chunkTotal) {
try {
String bucketName = "mybucket";
List<ComposeSource> sources = new ArrayList<>();
for (int i = 0; i < chunkTotal; i++) {
sources.add(ComposeSource.builder()
.bucket(bucketName)
.object(identifier + "/" + i)
.build());
}
minioClient.composeObject(
ComposeObjectArgs.builder()
.bucket(bucketName)
.object(identifier)
.sources(sources)
.build());
return "File merged successfully.";
} catch (MinioException e) {
e.printStackTrace();
return "Error: " + e.getMessage();
}
}
4、前端实现文件切片上传
前端需要将大文件切割成小块并逐块上传到服务器。以 JavaScript 为例:
bash
async function uploadFile(file) {
const chunkSize = 5 * 1024 * 1024; // 5MB
const totalChunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < totalChunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
const formData = new FormData();
formData.append('file', chunk);
formData.append('chunkIndex', i);
formData.append('chunkTotal', totalChunks);
formData.append('identifier', file.name);
await fetch('/upload/chunk', {
method: 'POST',
body: formData,
});
}
// 合并切片
await fetch('/upload/merge', {
method: 'POST',
body: JSON.stringify({
identifier: file.name,
chunkTotal: totalChunks
}),
headers: {
'Content-Type': 'application/json'
}
});
}
5、总结
通过 Spring Boot 和 Minio 的结合,我们可以轻松实现文件切片上传功能。该技术不仅提升了大文件上传的效率,还提高了上传的可靠性和用户体验。希望本文能帮助你在项目中实现这一功能。
完整的示例代码和详细配置可以根据实际需求进行调整和优化。祝你在项目开发中取得成功!