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

下载后就是这样的

相关推荐
冻柠檬飞冰走茶2 小时前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
文丑颜不良啊2 小时前
LeetCode2161~2180题目解析
java·leetcode
FRing032 小时前
vue2干货总结7(自定义指令、插槽、单页应用程序、路由的使用(VueRouter))
开发语言·前端·vue.js·vue2
雪落漂泊2 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法
波力海苔夹心脆6753 小时前
C# WPF 资源字典详解:ResourceDictionary、MergedDictionaries 与自定义控件案例
开发语言·c#·wpf·入门教程·resource·资源字典
不会算法的笨小孩3 小时前
异常的使用以及会出现的问题
开发语言·c++·c++11·异常
文丑颜不良啊4 小时前
LeetCode2141~2160题目解析
java·leetcode
LabVIEW开发4 小时前
LabVIEW 连接板:28 个端子怎么排,优先级怎么定
java·算法·labview
天天被压力4 小时前
【A股分钟级高频数据完全手册 #07】北交所历史分钟K线接口:京市Pro版分时批量
java·人工智能·python
天天被压力4 小时前
【A股分钟级高频数据完全手册 #08】股票日、分时数据接口对比:普通分时与Pro版差异实测
java·人工智能·python