java中下载多个文件和文件夹打压缩包下载,并自定义包中每个文件的名称

我的需求是一个可以批量下载文件或文件夹的接口,下载一个文件就正常下载,下载多个文件或单个多个文件夹都压缩成zip下载

本来想的是直接用hutool里面的ziputil工具类就行,但是我这里报错的文件都是用随机字符串命名的,直接用ZipUtil.zip方法下载下来的压缩包中文件都是原本文件的随机字符串名称

下面是我的处理方式,其中的一些工具类和压缩相关的类还是用的hutool中的,只不过没有用 ZipUtil封装好的方法

java 复制代码
@Override
    @OperLog(type = OperType.DOWNLOAD)
    public void download(List<String> ids) {
        List<WebDisk> webDiskList = this.webDiskMapper.selectList(new QueryWrapper<WebDisk>().in("id", ids));
        if (webDiskList.isEmpty()) {
            throw new RuntimeException("文件不存在,下载失败");
        }
        if (webDiskList.size() == 1 && webDiskList.get(0).isFile()) {
            WebDisk webDisk = webDiskList.get(0);
            try (FileInputStream is = new FileInputStream(this.getFullPath(webDisk));
                 ServletOutputStream os = response.getOutputStream()) {

                response.setContentType(request.getSession().getServletContext().getMimeType(webDisk.getFileSuffix())); // 获取文件的mimetype
                response.setHeader("content-disposition", "attachment;fileName=" + URLEncoder.encode(webDisk.getOriginName(), "UTF-8"));
                IoUtil.copy(is, os);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("下载失败,系统内部错误");
            }
        } else {
            response.setContentType(request.getSession().getServletContext().getMimeType("zip")); // 获取文件的mimetype

            try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {

                response.setHeader("content-disposition", "attachment;fileName=" +
                        URLEncoder.encode(FileNameUtil.mainName(webDiskList.get(0).getOriginName()) + ".zip", "UTF-8"));

                webDiskList.forEach(webDisk -> {
                    try {
                        this.addFileToZip(webDisk, zos, "", new HashMap<>());
                    } catch (IOException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }
                });
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

主要的方法就是下面这个 addFileToZip方法

因为上传文件的时候用随机字符串命名就是为了防止文件名称重复,所以这里打压缩包的时候给他们都设置为上传时候的原名称,但是为了防止名称重复,以名称后面累加括号加数字的方式重命名了

因为我上传的时候校验了不能上传重复名称的文件夹,所以我这里就只处理了重名的文件

java 复制代码
 private void addFileToZip(WebDisk webDisk, ZipOutputStream zos, String path, Map<String, Integer> nameCount) throws IOException {
        String filePath = this.getFullPath(webDisk);
        File file = FileUtil.file(filePath);

        String curFilePath = path + (webDisk.isFile() ? webDisk.getOriginName() : (webDisk.getOriginName() + "/"));
        ZipEntry zipEntry = new ZipEntry(curFilePath);
        try {
            zos.putNextEntry(zipEntry);
        } catch (ZipException e) {
            // 有重复名称文件
            String mainName = FileNameUtil.mainName(curFilePath);
            String extName = FileNameUtil.extName(curFilePath);
            int num = MapUtil.getInt(nameCount, curFilePath, 0) + 1;
            String newFilePath = path + mainName + "(" + num + ")" + "." + extName;

            zipEntry = new ZipEntry(newFilePath);
            zos.putNextEntry(zipEntry);

            nameCount.put(curFilePath, num);
        }


        if (file.isFile()) {
            try (FileInputStream is = new FileInputStream(file)) {
                IoUtil.copy(is, zos);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if (file.isDirectory()) {
            this.webDiskMapper.selectList(new QueryWrapper<WebDisk>().eq("pid", webDisk.getId()).eq("is_delete", 0))
                    .forEach(sub -> {
                        try {
                            this.addFileToZip(sub, zos, webDisk.getOriginName() + File.separator, nameCount);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });
        }
        zos.closeEntry();
    }

需要注意的是我这里目录的层级关系已经维护到表里了,所以递归找下级的时候直接查的库

相关推荐
考虑考虑8 小时前
JDK26中的Map.ofLazy
java·后端·java ee
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 14 章 MCP 服务端(上):注解式实现与工具来源
java·人工智能·开源
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 15 章 MCP 服务端(下):三种协议形态、Streamable 传输与状态管理
java·人工智能·开源
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 16 章 向量存储(上):`VectorStore` 接口体系、`BatchingStrategy`
java·人工智能·开源
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 12 章 工具循环的流式形态、Usage 累加与扩展体系
java·人工智能·开源
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 23 章 模型供应商实现:从 `OpenAiSetup` 到 Bedrock
java·人工智能·开源
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 06 章 内置 Advisor 全景:13 个实现逐个剖到源码级
java·人工智能·开源
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 03 章 消息体系与 Prompt:不可变模型、`ChatOptions` 与模板渲染
java·人工智能·开源
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 24 章 生产实践与 2.x 迁移:陷阱清单、AOT 与调优
java·人工智能·开源
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 10 章 工具调用(中):执行链路、结果转换与工具限制
java·人工智能·开源