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

下载后就是这样的

相关推荐
折哥的程序人生 · 物流技术专研8 小时前
Java面试85题图解版 · 特别篇:2026后端高频面试题复盘(算法底层逻辑+高并发架构设计全解析,附Java实战代码)
java·网络·数据库·算法·面试
xxie1237948 小时前
return与print
开发语言·python
秋98 小时前
从 Python 后端工程师转型 AI Engineer(AI 工程化)的完整补课清单(2026实战版)
开发语言·人工智能·python
一条泥憨鱼8 小时前
【Redis】数据类型和常用命令
java·数据库·redis·后端·缓存
云烟成雨TD8 小时前
Spring AI Alibaba 1.x 系列【78】沙箱(Sandbox)
java·人工智能·spring
程序员二叉9 小时前
【Java】 异常高频面试题精讲 | 易错点+对比总结
java·开发语言·面试
周航宇JoeZhou9 小时前
JB3-9-SpringAI(二)
java·ai·agent·多智能体·调度·智能体·观察
好家伙VCC9 小时前
Web Components主题热切换方案揭秘
java·前端
慕木沐9 小时前
Google ADK Java 1.0版本 核心机制与实战 Demo
java·开发语言·python
Roann_seo%9 小时前
C++文件操作完全指南:从文本读写到二进制文件处理
开发语言·c++