携程居家办公“免审批”的热点一出,表面看是时间更自由、更灵活了,但我们通勤人静下心再仔细琢磨一下,其实省下通勤时间,却陷入24小时待命?携程的“免审批...
2025-09-07 0
最近在项目当中遇到一个需要解压文件为zip,通过前端进行下载,这和常规的文件下载不同,在 zip 文件还会存在目录,目录中再存放文件,当时找了很多资料都不尽人意,所以自己写了这篇文字供以后参考。SpringBoot 的版本为2.5.15,zip4j 的版本为 2.11.5
zip4j是一个功能强大的 Java 库,专门用于处理 ZIP 文件格式。它提供了一系列易于使用的 API,使得开发人员可以方便地在 Java 应用程序中执行各种 ZIP 文件操作,包括创建、读取、更新和提取 ZIP 文件等。GitHub地址 里面说明了各种 API 的使用和示例。
具体思路是打算通过 zip4j 创建一个 zip 文件,然后通过 API 在 zip 文件里面创建目录和文件。当时的业务需求是下载每一个文件的附录文件,每一个文件都会有多个附录文件,不可能去一个个下载,所以需压缩为 zip 格式。具体的代码如下:
/** * 创建 zip 文件 * * @param ids 文件id集合 * @return zip 文件的路径 */private String createZipFile(String ids) { Integer[] intArray = Convert.toIntArray(ids); // 创建一个列表用于存放所有附件文件的路径,后续统一压缩到一个zip文件中 List<String> allFilePaths = new ArrayList<>(); // 循环查询每个id对应的附件文件路径并添加到列表中 // 里面的代码大家可能会觉得麻烦,不用细看,只需要知道这层for循环是为了找到附录文件在磁盘的地址 for (int id : intArray) { List<SysDownloadCenterAttachment> attachmentList = sysDownloadCenterAttachmentMapper.selectList(new LambdaQueryWrapper<SysDownloadCenterAttachment>() .eq(SysDownloadCenterAttachment::getDownloadCenterId, id)); if (!CollectionUtils.isEmpty(attachmentList)) { List<String> filePaths = attachmentList.stream().map(attachment -> { String filePath = scjtConfig.getUploadPath() + attachment.getLocation(); if (!StringUtils.startsWith(filePath, "D:")) { filePath = "D:" + filePath; } return filePath; }).collect(Collectors.toList()); allFilePaths.addAll(filePaths); } } // 创建ZipFile对象,指定zip文件的路径 ZipFile zipFile = new ZipFile("d:/filename.zip"); // 循环附录文件地址 for (String filePath : allFilePaths) { File file = new File(filePath); if (file.exists()) { // 获取文件名(包含后缀) String fileName = file.getName(); // 这里假设附件所属的id可以通过某种方式获取,比如从文件路径解析或者其他逻辑判断,示例中用一个方法 getFileIdFromPath 来表示获取id的逻辑,你需要根据实际情况替换 String folderNameInsideZip = getFileTitleFromPath(intArray, filePath); // 构造在zip文件中存放的路径,格式为 "id标识的文件夹名/原文件名" try { // 尝试获取目标文件夹在zip文件中的FileHeader FileHeader folderHeader = zipFile.getFileHeader(folderNameInsideZip + "/"); log.info("文件夹在zip文件中的FileHeader:" + folderHeader); // 如果zip文件中指定目录不存在,则创建,这一步判断是必须的,不然会导致下一次文件添加动作会覆盖之前的文件 if (Objects.isNull(folderHeader)) { new File(folderNameInsideZip).mkdirs(); // 创建文件夹 ZipParameters folderPar = new ZipParameters(); folderPar.setCompressionLevel(CompressionLevel.NORMAL); folderPar.setEncryptFiles(false); zipFile.addFolder(new File(folderNameInsideZip), folderPar); log.info("文件夹已成功添加到zip文件中。"); } // 创建ZipParameters对象,用于设置添加文件的参数 ZipParameters parameters = new ZipParameters(); // 设置压缩方法,这里使用默认压缩方法 parameters.setCompressionMethod(CompressionMethod.DEFLATE); // 设置压缩级别,这里使用默认压缩级别 parameters.setCompressionLevel(CompressionLevel.NORMAL); // 设置添加文件在zip文件中的路径,格式为 "文件夹名/文件名" parameters.setFileNameInZip(folderNameInsideZip + "/" + file.getName()); // 将文件添加到zip文件中的指定文件夹路径下 zipFile.addFile(file, parameters); log.info("文件已成功添加到zip文件中的指定文件夹。"); } catch (ZipException e) { throw new RuntimeException(e); } } } return zipFile.getFile().getAbsolutePath();}
上面代码运行完毕,就会在d:/filename.zip的位置存在一个 zip 文件,打开后会看到目录结构和文件信息。接下来就需要前端来下载这个 zip 文件,我这里建立下载后就删除这个 zip 文件,这样下次重新生成时就不会出现文件合并的问题。后端下载代码如下:
/** * 下载文件的附件,附件较多 压缩为zip下载 * * @param ids 文件id集合 * @param response * @return */@Override@SneakyThrowspublic ResponseEntity<Resource> downloadZip(String ids, HttpServletResponse response) { // 创建zip文件 String zipFilePath = createZipFile(ids); File file = new File(zipFilePath); InputStreamResource resource = new InputStreamResource(new FileInputStream(file)); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=sample.zip") .contentType(MediaType.APPLICATION_OCTET_STREAM) .contentLength(file.length()) .body(resource);}
前段代码如下:
export function downloadCenterZip(ids) { return request({ url: `/system/download/center/downloadZip`, method: 'post', data: ids, responseType: 'blob' // 标识返回类型为blob })}
/** * 下载按钮操作 */function handleDownloadZip() { downloadCenterZip(ids.value.toString()).then(res => { console.log(res) const url = window.URL.createObjectURL(new Blob([res], {type: 'application/zip'})); let a = document.createElement('a') a.href = url a.download = 'download.zip' a.click() URL.revokeObjectURL(url) // 释放内存 a.remove() })}
对于其他格式文件的下载,其实思路都差不多,后端都需要返回一个blob或者byte数组,然后前端使用超链接的方式来触发下载。
相关文章
携程居家办公“免审批”的热点一出,表面看是时间更自由、更灵活了,但我们通勤人静下心再仔细琢磨一下,其实省下通勤时间,却陷入24小时待命?携程的“免审批...
2025-09-07 0
亲,这款游戏可以开挂的,确实是有挂的,很多玩家在这款游戏中打牌都会发现很多用户的牌特别好,总是好牌,而且好像能看到-人的牌一样。所以很多小伙伴就怀疑这...
2025-09-07 0
提到折叠屏,相信大部分朋友都会第一时间想到华为,确实也是如此,如今华为在国内折叠屏市场可以说是独一档的存在,多个季度市场份额超过70%,而且无论是大折...
2025-09-07 0
电工必会的四种仪表万用表、钳形电流表、绝缘电阻表和接地电阻测试仪。以下是具体介绍:万用表:是电工最常用的多功能测量仪器,可测量电流、电压、电阻等基本参...
2025-09-07 0
发表评论