SpringBoot+Minio实现多文件下载和批量下载

时间:2024-10-28 21:37:01

文章目录

    • SpringBoot+minio实现多文件下载
      • 1、SpringBoot+minio实现多文件打成一个压缩包下载
        • 1. 添加依赖
        • 2. 配置 MinIO 客户端
        • 3. 创建下载和压缩逻辑
        • 4. 创建控制器方法来触发下载
        • 5. 测试下载功能
        • 注意事项
      • 2、在minio指定的桶名下面生产一个文件夹
        • 1. MinIO 配置
        • 2. 编写业务逻辑
          • 文件夹操作和压缩下载
        • 3. 创建控制器
        • 4. 测试
        • 注意事项
      • 3、在minio指定的桶名下面生产一个临时文件夹
        • 1. 配置 MinIO 客户端
        • 2. 创建数据库实体类
        • 3. 创建存储库接口
        • 4. MinIO 服务实现
        • 5. 控制器实现
        • 6. 测试接口
        • 注意事项
      • 4、直接在内存中打包再上传
        • 1. MinIO 配置
        • 2. 创建数据库实体类
        • 3. 创建存储库接口
        • 4. 编写服务逻辑
        • 5. 创建控制器
        • 6. 测试接口
        • 注意事项
      • 5、本地生产一个临时目录进行打包再上传
        • 具体步骤如下:
        • 1. 使用系统临时目录
        • 示例代码
        • 2. 应用程序的特定临时目录
        • 3. 清理策略
        • 4. 权限和安全性
        • 5. 例子
        • 本地临时目录总结
        • 6. 添加依赖
        • 2. MinioService 实现
        • 3. 创建控制器
        • 4. 测试接口
        • 总结
      • 6、通过多线程将下载的文件合成在一个zip包中
        • 1. 添加依赖
        • 2. 创建 MinioService 类
        • 3. 创建控制器
        • 4. 测试接口
        • 注意事项
        • 总结
    • SpringBoot+minio实现文件批量下载
      • 1、for循环
        • 1. 准备工作
        • 2. 添加依赖
        • 3. 配置MinIO
        • 4. 创建MinIO配置类
        • 5. 创建下载控制器
        • 6. 测试下载功能
        • 7. 额外的压缩功能
        • 8. 安全性
        • 示例:压缩文件下载
        • 总结
      • 2、多线程
        • 1. 添加依赖
        • 2. 创建MinIO配置类
        • 3. 创建下载控制器
        • 4. 关键点解析
        • 5. 测试下载功能
        • 6. 性能优化
        • 7. 安全性
        • 总结

SpringBoot+minio实现多文件下载

1、SpringBoot+minio实现多文件打成一个压缩包下载

要在 Spring Boot 中使用 MinIO 实现多文件打包成一个压缩文件并下载,主要分为以下几个步骤:

  1. 连接 MinIO:创建 MinIO 客户端,用于与 MinIO 进行通信。
  2. 文件读取:从 MinIO 中读取多个文件。
  3. 文件压缩:将文件压缩为 ZIP 格式。
  4. 文件下载:将生成的 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 实现上述功能时,可以按以下步骤操作:

  1. 创建 MinIO 文件夹:在 MinIO 指定的桶内创建一个文件夹。
  2. 上传文件到文件夹:将需要下载的文件复制到该文件夹。
  3. 打包文件夹为 ZIP 并下载:将文件夹内的文件打包为 ZIP 文件并返回给客户端。
  4. 清理文件夹:下载成功后,删除 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;