网站首页 > java教程 正文
用户需要上传和存储的文件越来越大,传统的单次上传方式往往会导致上传失败或用户体验不佳。为了解决这一问题,我们引入了大文件分片上传与分片合并功能。该功能可以将大文件分割成多个小分片进行上传,即使在网络不稳定的情况下也能确保上传的成功率,并且在所有分片成功上传后自动合并成完整的文件。
功能特点
1. 分片上传
- 分片处理:系统会将大文件自动分割成多个较小的分片。
- 并发上传:每个分片可以独立上传,支持并发传输,提高上传速度。
- 断点续传:如果某个分片上传失败,只需重新上传该分片,而不需要从头开始。
2. 分片合并
- 自动合并:当所有分片都成功上传后,系统会自动将这些分片合并成一个完整的文件。
- 完整性校验:在合并过程中,系统会对每个分片进行校验,确保文件的完整性和准确性。
3. 提升体验
- 稳定性:即使网络状况较差,也可以保证文件的顺利上传。
- 效率:通过并发上传和断点续传,大大提高了上传效率。
- 可靠性:自动合并机制确保最终生成的文件与原始文件完全一致。
应用场景
1. 视频上传
- 用户可以通过我们的平台上传长视频,无需担心上传过程中的中断问题。
- 视频上传完成后,系统会自动将其合并并保存到指定位置。
2. 大型文件备份
- 对于大型文件(如数据库备份、软件安装包等),可以利用分片上传功能进行高效备份。
- 确保备份文件的完整性和可用性,便于后续恢复操作。
3. 内容发布
- 平台允许用户上传高清图片、音频、视频等内容,支持多格式文件的分片上传。
- 内容上传完成后,系统会自动将其合并并展示给其他用户。
代码实操
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MinIO Java SDK -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.3</version>
</dependency>
<!-- Gson for JSON processing -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
配置MinIO参数
在application.yml文件中添加以下配置:
minio:
endpoint: http://localhost:9000
access-key: minioadmin
secret-key: minioadmin
bucket-name: my-bucket
创建服务类
创建一个服务类来处理文件上传、分片合并以及权限控制的业务逻辑:
package com.example.demo.service;
import io.minio.*;
import io.minio.errors.MinioException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
@Service
publicclass FileUploadService {
@Value("${minio.endpoint}")
private String endpoint; // MinIO服务器地址
@Value("${minio.access-key}")
private String accessKey; // MinIO访问密钥
@Value("${minio.secret-key}")
private String secretKey; // MinIO秘密密钥
@Value("${minio.bucket-name}")
private String bucketName; // 存储桶名称
/**
* 如果存储桶不存在,则创建存储桶
*/
public void createBucketIfNotExists() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
try (MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build()) {
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
}
/**
* 上传文件分片到MinIO
*
* @param fileId 文件标识符
* @param filePart 文件分片
* @return 分片对象名称
*/
public String uploadFilePart(String fileId, MultipartFile filePart) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
try (MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build()) {
// 构建分片对象名称
String objectName = fileId + "/" + UUID.randomUUID();
// 设置上传参数
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(filePart.getInputStream(), filePart.getSize(), -1)
.contentType(filePart.getContentType())
.build();
// 上传文件分片
minioClient.putObject(putObjectArgs);
return objectName;
}
}
/**
* 合并多个文件分片为一个完整文件
*
* @param fileId 文件标识符
* @param partNames 分片对象名称列表
*/
public void mergeFileParts(String fileId, String[] partNames) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
try (MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build()) {
// 构建最终文件对象名称
String finalObjectName = fileId + ".merged";
// 构建ComposeSource数组
ComposeSource[] sources = new ComposeSource[partNames.length];
for (int i = 0; i < partNames.length; i++) {
sources[i] = ComposeSource.builder().bucket(bucketName).object(partNames[i]).build();
}
// 设置合并参数
ComposeObjectArgs composeObjectArgs = ComposeObjectArgs.builder()
.bucket(bucketName)
.object(finalObjectName)
.sources(sources)
.build();
// 合并文件分片
minioClient.composeObject(composeObjectArgs);
// 删除合并后的分片
for (String partName : partNames) {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(partName).build());
}
}
}
/**
* 删除指定文件
*
* @param fileName 文件名
*/
public void deleteFile(String fileName) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
try (MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build()) {
// 删除文件
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
}
}
}
创建控制器
创建一个控制器来接收客户端的文件上传请求:
package com.example.demo.controller;
import com.example.demo.service.FileUploadService;
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.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
@RestController
@RequestMapping("/file")
publicclass FileController {
@Autowired
private FileUploadService fileUploadService;
/**
* 上传文件分片
*
* @param filePart 文件分片
* @return 分片对象名称
*/
@PostMapping("/upload/part")
public ResponseEntity<String> uploadFilePart(@RequestParam("file") MultipartFile filePart) throws IOException, NoSuchAlgorithmException, InvalidKeyException, io.minio.errors.MinioException {
// 生成文件标识符
String fileId = java.util.UUID.randomUUID().toString();
// 上传文件分片
String partName = fileUploadService.uploadFilePart(fileId, filePart);
return ResponseEntity.ok(partName);
}
/**
* 合并文件分片
*
* @param fileId 文件标识符
* @param parts 分片对象名称列表
* @return 成功消息
*/
@PostMapping("/merge")
public ResponseEntity<String> mergeFileParts(@RequestParam("fileId") String fileId, @RequestParam("parts") List<String> parts) throws IOException, NoSuchAlgorithmException, InvalidKeyException, io.minio.errors.MinioException {
// 合并文件分片
fileUploadService.mergeFileParts(fileId, parts.toArray(new String[0]));
return ResponseEntity.ok("File merged successfully");
}
/**
* 删除文件
*
* @param fileName 文件名
* @return 成功消息
*/
@DeleteMapping("/delete/{fileName}")
public ResponseEntity<String> deleteFile(@PathVariable String fileName) throws IOException, NoSuchAlgorithmException, InvalidKeyException, io.minio.errors.MinioException {
// 删除文件
fileUploadService.deleteFile(fileName);
return ResponseEntity.ok("File deleted successfully");
}
}
启动
package com.example.demo;
import com.example.demo.service.FileUploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
publicclass DemoApplication implements CommandLineRunner {
@Autowired
private FileUploadService fileUploadService;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// 确保启动时存储桶存在
fileUploadService.createBucketIfNotExists();
}
}
猜你喜欢
- 2025-05-11 全局数组的结构分析(全局数组和局部数组)
- 2025-05-11 10秒合并800个表,VSTACK就是这么厉害!
- 2025-05-11 VBA实现将批量Excel文件中的工作表合并成一个工作表
- 2025-05-11 C语言之strcat字符串拼接函数(c语言字符串拼接函数实现)
- 2025-05-11 这几个动态数组函数,简单又高效(动态数组的方法)
- 2025-05-11 数据格式的转换方法,HSTACK函数重建数组
- 2025-05-11 Java归并排序算法(技术每天进步一点)
- 2025-05-11 如何零基础学习VBA——数组函数介绍
- 2025-05-11 新增工作表数据自动汇总到总表怎么弄?会用vstack函数轻松搞定!
- 2025-05-11 字符拆分与合并,学会套路很简单(字符怎么合并)
你 发表评论:
欢迎- 05-11全局数组的结构分析(全局数组和局部数组)
- 05-1110秒合并800个表,VSTACK就是这么厉害!
- 05-11VBA实现将批量Excel文件中的工作表合并成一个工作表
- 05-11C语言之strcat字符串拼接函数(c语言字符串拼接函数实现)
- 05-11这几个动态数组函数,简单又高效(动态数组的方法)
- 05-11数据格式的转换方法,HSTACK函数重建数组
- 05-11Java归并排序算法(技术每天进步一点)
- 05-11如何零基础学习VBA——数组函数介绍
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)