文章目录
SpringBoot+minio实现多文件下载
1、SpringBoot+minio实现多文件打成一个压缩包下载
要在 Spring Boot 中使用 MinIO 实现多文件打包成一个压缩文件并下载,主要分为以下几个步骤:
- 连接 MinIO:创建 MinIO 客户端,用于与 MinIO 进行通信。
- 文件读取:从 MinIO 中读取多个文件。
- 文件压缩:将文件压缩为 ZIP 格式。
- 文件下载:将生成的 ZIP 文件流返回给客户端。
1. 添加依赖
如果还没有添加 MinIO 依赖,可以手动下载 MinIO 客户端库,或者直接用 Maven 来管理依赖:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.5</version>
</dependency>
2. 配置 MinIO 客户端
在 application.properties
中添加 MinIO 配置:
minio.url=http://localhost:9000
minio.accessKey=your-access-key
minio.secretKey=your-secret-key
minio.bucketName=your-bucket
然后在 @Configuration
类中配置 MinIO 客户端:
import io.minio.MinioClient;
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.url}")
private String url;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(url)
.credentials(accessKey, secretKey)
.build();
}
}
3. 创建下载和压缩逻辑
在服务类中添加下载和压缩方法,以下代码会将指定的文件列表压缩成一个 ZIP 并返回给客户端。
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Service
public class MinioService {
@Autowired
private MinioClient minioClient;
@Value("${minio.bucketName}")
private String bucketName;
public void downloadFilesAsZip(List<String> fileNames, HttpServletResponse response) {
try {
// 设置响应头,文件名为 download.zip
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=download.zip");
// 创建 ZIP 输出流
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
for (String fileName : fileNames) {
// 获取每个文件的输入流
try (InputStream inputStream = minioClient.getObject(
GetObjectArgs.builder().bucket(bucketName).object(fileName).build())) {
// 创建 ZIP 文件条目
zipOut.putNextEntry(new ZipEntry(fileName));
// 将文件数据写入 ZIP
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) >= 0) {
zipOut.write(buffer, 0, length);
}
zipOut.closeEntry(); // 结束该条目的写入
}
}
zipOut.finish(); // 完成 ZIP 文件
}
} catch (Exception e) {
throw new RuntimeException("Error occurred while downloading files as zip", e);
}
}
}
4. 创建控制器方法来触发下载
在控制器中定义一个方法,接收前端的请求并调用服务类进行压缩与下载。
@RestController
public class FileDownloadController {
@Autowired
private MinioService minioService;
@GetMapping("/download-zip")
public void downloadZip(@RequestParam List<String> fileNames, HttpServletResponse response) {
minioService.downloadFilesAsZip(fileNames, response);
}
}
5. 测试下载功能
现在可以通过 HTTP GET 请求测试该功能:
GET http://localhost:8080/download-zip?fileNames=file1.txt&fileNames=file2.jpg&fileNames=file3.pdf
注意事项
- 内存消耗:如果文件较多或较大,生成 ZIP 文件的过程可能会占用大量内存。可以优化为逐个文件流写入 ZIP,避免内存问题。
- 异常处理:可扩展异常处理,捕获 MinIO 连接失败、文件不存在等情况,并返回更详细的错误信息。
这个实现将从 MinIO 读取文件流,逐一压缩到 ZIP 中,并通过 HTTP 响应流返回给客户端。
2、在minio指定的桶名下面生产一个文件夹
SpringBoot+minio实现多文件下载时在minio指定的桶名下面生产一个文件夹,将需要下载放到这个文件夹中,并把这个文件夹打成一个压缩包后进行下载,下载成功后删除这个文件夹
在使用 Spring Boot 和 MinIO 实现上述功能时,可以按以下步骤操作:
- 创建 MinIO 文件夹:在 MinIO 指定的桶内创建一个文件夹。
- 上传文件到文件夹:将需要下载的文件复制到该文件夹。
- 打包文件夹为 ZIP 并下载:将文件夹内的文件打包为 ZIP 文件并返回给客户端。
- 清理文件夹:下载成功后,删除 MinIO 上的文件夹及其内容。
以下是实现的详细步骤和代码。
1. MinIO 配置
确保 MinIO 客户端配置正确。使用 application.properties
配置 MinIO 相关信息。
minio.url=http://localhost:9000
minio.accessKey=your-access-key
minio.secretKey=your-secret-key
minio.bucketName=your-bucket
并创建 MinIO 客户端配置类:
import io.minio.MinioClient;
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.url}")
private String url;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(url)
.credentials(accessKey, secretKey)
.build();
}
}
2. 编写业务逻辑
在服务类中添加方法来实现各步骤。
文件夹操作和压缩下载
import io.minio.CopyObjectArgs;
import io.minio.MinioClient;
import io.minio.RemoveObjectArgs;
import io.minio.GetObjectArgs;
import io.minio.ObjectWriteResponse;
import io.minio.UploadObjectArgs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Service
public class MinioService {
@Autowired
private MinioClient minioClient;
@Value("${minio.bucketName}")
private String bucketName;
// 将需要下载的文件放入临时文件夹并压缩下载
public void downloadFolderAsZip(List<String> fileNames, HttpServletResponse response) {
String tempFolderName = "temp-folder-" + UUID.randomUUID(); // 随机生成临时文件夹名称
try {
// 上传文件到临时文件夹
for (String fileName : fileNames) {
String objectName = tempFolderName + "/" + fileName;
// 复制原始文件到临时文件夹
minioClient.copyObject(
CopyObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.source(bucketName + "/" + fileName)
.build()
);
}
// 设置响应头
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=download.zip");
// 创建 ZIP 输出流
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
for (String fileName : fileNames) {
String objectName = tempFolderName + "/" + fileName;
// 获取临时文件夹中的每个文件流
try (InputStream inputStream = minioClient.getObject(
GetObjectArgs.builder().bucket(bucketName).object(objectName).build())) {
// 写入 ZIP 条目
zipOut.putNextEntry(new ZipEntry(fileName));
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) >= 0) {
zipOut.write(buffer, 0, length);
}
zipOut.closeEntry(); // 结束条目写入
}
}
zipOut.finish(); // 完成 ZIP 文件
}
// 下载完成后删除临时文件夹
deleteFolder(tempFolderName);
} catch (Exception e) {
throw new RuntimeException("Error occurred while downloading folder as zip", e);
}
}
// 删除指定文件夹及其内容
private void deleteFolder(String folderName) {
try {
Iterable<Result<Item>> items = minioClient.listObjects(ListObjectsArgs.builder()
.bucket(bucketName)
.prefix(folderName + "/")
.recursive(true)
.build());
for (Result<Item> itemResult : items) {
Item item = itemResult.get();
minioClient.removeObject(
RemoveObjectArgs.builder().bucket(bucketName).object(item.objectName()).build()
);
}
} catch (Exception e) {
throw new RuntimeException("Error occurred while deleting folder", e);
}
}
}
3. 创建控制器
控制器方法用于接受文件名列表并调用服务中的方法进行下载。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@RestController
public class FileDownloadController {
@Autowired
private MinioService minioService;
@GetMapping("/download-zip")
public void downloadZip(@RequestParam List<String> fileNames, HttpServletResponse response) {
minioService.downloadFolderAsZip(fileNames, response);
}
}
4. 测试
可以通过以下 GET 请求测试功能:
GET http://localhost:8080/download-zip?fileNames=file1.txt&fileNames=file2.jpg&fileNames=file3.pdf
注意事项
- 异步清理:如果文件数量多或者体积大,删除文件夹可能会影响性能。可以考虑将删除操作异步处理。
- 异常处理:添加异常处理逻辑,确保在复制、压缩、删除等环节处理各种可能的错误。
3、在minio指定的桶名下面生产一个临时文件夹
SpringBoot+minio实现多文件下载时在minio指定的桶名下面生产一个文件夹,将需要下载放到这个文件夹中,并把这个文件夹打成一个压缩包后进行下载,下载成功后保留压缩包信息存放到数据库并且删除这个文件夹
要实现此功能,需要将多个文件上传到一个临时文件夹,并将该文件夹压缩为一个 ZIP 文件,供客户端下载。在下载成功后,将压缩包信息存储到数据库,并删除临时文件夹的所有文件。
以下是实现步骤和代码:
- 创建 MinIO 文件夹:在 MinIO 的指定桶下创建一个临时文件夹,并将文件复制到该文件夹中。
- 打包下载:将文件夹打包为 ZIP 文件返回给客户端。
- 保存记录:将 ZIP 文件信息存储到数据库中。
- 清理临时文件夹:下载完成后,删除临时文件夹中的所有文件,但保留 ZIP 文件。
1. 配置 MinIO 客户端
在 application.properties
中添加 MinIO 和数据库的配置:
# MinIO 配置
minio.url=http://localhost:9000
minio.accessKey=your-access-key
minio.secretKey=your-secret-key
minio.bucketName=your-bucket
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/yourdb
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update
2. 创建数据库实体类
创建一个实体类 ZipFileRecord
来保存压缩包信息:
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
public class ZipFileRecord {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fileName;
private String filePath;
private LocalDateTime createdTime;
// Getters and Setters
// ...
}
3. 创建存储库接口
创建一个 ZipFileRecordRepository
,用于保存压缩包信息:
import org.springframework.data.jpa.repository.JpaRepository;
public interface ZipFileRecordRepository extends JpaRepository<ZipFileRecord, Long> {
}
4. MinIO 服务实现
编写服务类 MinioService
,完成文件夹创建、文件复制、打包下载、数据库保存和清理的逻辑。
import io.minio.*;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Service
public class MinioService {
@Autowired
private MinioClient minioClient;
@Autowired
private ZipFileRecordRepository zipFileRecordRepository;
@Value("${minio.bucketName}")
private String bucketName;
public void downloadFolderAsZip(List<String> fileNames, HttpServletResponse response) {
String tempFolderName = "temp-folder-" + UUID.randomUUID(); // 创建临时文件夹
String zipFileName = "download-" + UUID.randomUUID() + ".zip";
String zipFilePath = tempFolderName + "/" + zipFileName;
try {
// 复制文件到临时文件夹
for (String fileName : fileNames) {
String objectName = tempFolderName + "/" + fileName;
minioClient.copyObject(
CopyObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.source(bucketName + "/" + fileName)
.build()
);
}
// 设置响应头,下载压缩包
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=" + zipFileName);
// 创建 ZIP 输出流
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
for (String fileName : fileNames) {
String objectName = tempFolderName + "/" + fileName;
// 获取每个文件的输入流
try (InputStream inputStream = minioClient.getObject(
GetObjectArgs.builder().bucket(bucketName).object(objectName).build())) {
// 写入 ZIP 条目
zipOut.putNextEntry(new ZipEntry(fileName));
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) >= 0) {
zipOut.write(buffer, 0, length);
}
zipOut.closeEntry(); // 结束条目写入
}
}
zipOut.finish(); // 完成 ZIP 文件
}
// 将 ZIP 文件信息保存到数据库
saveZipFileRecord(zipFileName, zipFilePath);
// 删除临时文件夹中的文件
deleteFolder(tempFolderName);
} catch (Exception e) {
throw new RuntimeException("Error occurred while downloading folder as zip", e);
}
}
// 保存 ZIP 文件信息到数据库
private void saveZipFileRecord(String zipFileName, String zipFilePath) {
ZipFileRecord record = new ZipFileRecord();
record.setFileName(zipFileName);
record.setFilePath(zipFilePath);
record.setCreatedTime(LocalDateTime.now());
zipFileRecordRepository.save(record);
}
// 删除指定文件夹及其内容
private void deleteFolder(String folderName) {
try {
Iterable<Result<Item>> items = minioClient.listObjects(
ListObjectsArgs.