Java SpringBoot批量获取Minio中多个文件进行压缩成zip下载

FileController 接口请求为Post

java 复制代码
@RestController
@RequestMapping("/file")
@Api(tags = "file文件操作")
public class FileController {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileController.class);

    @Autowired
    private IFileService fileService;
    @ApiOperation(value = "下载压缩文件Zip", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    @RequestMapping(value = "/downZipFile", produces = "application/octet-stream", method = RequestMethod.POST)
    public void downZipFile(@RequestBody ZipFileDto zipFileDto, HttpServletResponse response) {
        try {
            fileService.downZipFile(zipFileDto, response);
        } catch (Exception e) {
            new CommonResult().failed(e.getMessage());
        }
    }
}

ZipFileDto.java 入参实体类

java 复制代码
@Data
public class ZipFileDto {
    /**
     * 文件名称.zip
     */
    private String downName;

    private List<fileListDto> fileList;

    @Data
    public static class fileListDto {
        /**
         * 下载文件名称
         */
        private String fileName;
        /**
         * 下载文件路径
         */
        private String filePath;
    }
}

IFileService.java 接口层

java 复制代码
public interface IFileService {

    void downZipFile(ZipFileDto zipFileDto, HttpServletResponse response) throws Exception;

}

MinioFileServiceImpl.java 实现类

java 复制代码
@Service
public class MinioFileServiceImpl implements IFileService {

	private static final Logger LOGGER = LoggerFactory.getLogger(MinioFileServiceImpl.class);
	@Value("${minio.storageClass}")
	private String STORAGECLASS; //存储类型
	@Value("${minio.endpoint}")
	private String ENDPOINT; //连接地址
	@Value("${minio.bucketName}")
	private String BUCKET_NAME; //存储桶名称
	@Value("${minio.accessKey}")
	private String ACCESS_KEY; //用户名
	@Value("${minio.secretKey}")
	private String SECRET_KEY; //密码

	@Override
	public void downZipFile(ZipFileDto zipFileDto, HttpServletResponse response) throws Exception {
		try {
			// 获取minio中多个文件进行压缩成zip下载
			InputStream fis;
			MinioClient minioClient = new MinioClient(ENDPOINT, ACCESS_KEY, SECRET_KEY);
			String bucketName = BUCKET_NAME;
			ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
			try (ZipOutputStream zos = new ZipOutputStream(byteArrayOutputStream)) {
				for (ZipFileDto.fileListDto fileListDto : makeUnique(zipFileDto.getFileList())) {
					String filePath = StringUtils.substringAfter(fileListDto.getFilePath(), "/mall");
					try (InputStream is = minioClient.getObject(bucketName, filePath)) {
						zos.putNextEntry(new ZipEntry(fileListDto.getFileName()));
						byte[] buffer = new byte[1024];
						int len;
						while ((len = is.read(buffer)) > 0) {
							zos.write(buffer, 0, len);
						}
						zos.closeEntry();
					}
				}
			} catch (NoSuchAlgorithmException e) {
				throw new RuntimeException(e);
			} catch (InvalidKeyException e) {
				throw new RuntimeException(e);
			}
			// 从 ByteArrayOutputStream 获取字节数组
			byte[] zipData = byteArrayOutputStream.toByteArray();
			ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(zipData);
			fis = new BufferedInputStream(byteArrayInputStream);
			byte[] buffer = new byte[fis.available()];
			fis.read(buffer);
			fis.close();
			response.reset();
			// 设置response的Header
			response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(zipFileDto.getDownName(), "UTF-8"));
			OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
			response.setContentType("application/octet-stream;charset=UTF-8");
			toClient.write(buffer);
			toClient.flush();
			toClient.close();
		} catch (MinioException | IOException e) {
			e.printStackTrace();
			LOGGER.error(e.getMessage());
		}
	}


	public static List<ZipFileDto.fileListDto> makeUnique(List<ZipFileDto.fileListDto> fileListDtos) {
		Map<String, Integer> nameCount = new HashMap<>();
		List<ZipFileDto.fileListDto> uniqueNames = new ArrayList<>();
		fileListDtos.forEach(t->{
			ZipFileDto.fileListDto fileListDto=new ZipFileDto.fileListDto();
			String str = t.getFileName();
			int lastIndex = str.lastIndexOf(".");
			String suffix = str.substring(lastIndex + 1);
			String name = str.substring(0,lastIndex);
			if (nameCount.containsKey(name)) {
				nameCount.put(name, nameCount.get(name) + 1);
				fileListDto.setFilePath(t.getFilePath());
				fileListDto.setFileName(name + "(" + nameCount.get(name) + ")."+suffix);
				uniqueNames.add(fileListDto);
			} else {
				nameCount.put(name, 1);
				fileListDto.setFilePath(t.getFilePath());
				fileListDto.setFileName(name+"."+suffix);
				uniqueNames.add(fileListDto);
			}
		});
		return uniqueNames;
	}
}

项目yml配置

XML 复制代码
minio:
  storageClass: minio  # nfs/minio
  accessKey: minioadmin
  bucketName: mall
  endpoint: http://10.110.xx.xx:9000
  secretKey: minioadmin

下载后就是这样的

相关推荐
测试员周周3 小时前
【Appium 系列】第16节-WebView-H5上下文切换 — 混合应用的自动化难点
运维·开发语言·人工智能·功能测试·appium·自动化·测试用例
Mahir086 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
杜子不疼.6 小时前
【C++ AI 大模型接入 SDK】 - DeepSeek 模型接入(上)
开发语言·c++·chatgpt
加号36 小时前
【C#】 串口通信技术深度解析及实现
开发语言·c#
sycmancia7 小时前
Qt——编辑交互功能的实现
开发语言·qt
RyFit7 小时前
SpringAI 常见问题及解决方案大全
java·ai
石山代码7 小时前
C++ 内存分区 堆区
java·开发语言·c++
绝知此事7 小时前
【算法突围 01】线性结构与哈希表:后端开发的收纳术
java·数据结构·算法·面试·jdk·散列表
无风听海7 小时前
C# 隐式转换深度解析
java·开发语言·c#
一只大袋鼠8 小时前
Git 进阶(二):分支管理、暂存栈、远程仓库与多人协作
java·开发语言·git