文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

java 批量下载将多个文件(minio中存储)压缩成一个zip包

2023-10-28 07:31

关注

我的需求是将minio中存储的文件按照查询条件查询出来统一压成一个zip包然后下载下来。

思路:针对这个需求,其实可以有多个思路,不过也大同小异,一般都是后端返回流文件前端再处理下载,也有少数是压缩成zip包之后直接给下载链接返回到前端,前端收到链接url直接window.open()进行下载,不过这种下载zip包的路径要确保是在网站下,否则访问不到,还有一个缺点就是文件没法删除,占用存储空间,后期需人为动作清理,选择哪种思路就可以看具体需求啦,我选择的是第一种思路,以下就针对第一种后端返回流方式进行具体介绍。

首先说第一种方法:将需要下载的文件找到,minio中有查询方法将文件转成inputStream,这里就不多说了,拿到一组InputStream,我们就可以写入一个zip包里了,创建临时zip路径,将流遍历写入文件,读取临时zip文件再写入response中的outputStream,最后删除临时文件。

前端处理方法最后统一介绍,后端核心代码如下:

public void downloadZip(String name, List filePaths,HttpServletResponse     response){        File zipFile = compressedFileToZip(name,filePaths);        ByteArrayOutputStream os = new ByteArrayOutputStream();        try {            FileInputStream ins = new FileInputStream(zipFile);            WritableByteChannel writableByteChannel = Channels.newChannel(os);            FileChannel fileChannel = ins.getChannel();            fileChannel.transferTo(0, fileChannel.size(), writableByteChannel);            fileChannel.close();            response.setCharacterEncoding("UTF-8");            name = URLEncoder.encode(name, "UTF-8");            response.setContentType("application/octet-stream");            response.addHeader("Content-Disposition", "attachment;filename=" + new String(name.getBytes("iso8859-1")));            response.setContentLength(os.size());            response.setHeader("filename", name);            response.addHeader("Content-Length", "" + os.size());            var outputstream = response.getOutputStream();            os.writeTo(outputstream);            os.flush();            os.close();            outputstream.flush();            outputstream.close();            writableByteChannel.close();            if(zipFile.exists()){                //删除临时文件                zipFile.delete();            }        } catch (IOException e) {            e.printStackTrace();        } finally {            try {                os.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }        public File compressedFileToZip(String name, List mediaFileEntityList) {        String zipName = name.concat(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))).concat(".zip");        //临时zip路径        String fileZipPath = System.getProperty("user.dir").concat("/").concat(zipName);        OutputStream os = null;        ZipOutputStream zos = null;        File file = new File(fileZipPath);        try {            if(!file.exists()){                file.createNewFile();            }            os= new FileOutputStream(file);            zos = new ZipOutputStream(os) ;            for (MediaFileEntity entity:mediaFileEntityList                 ) {                zos.putNextEntry(new ZipEntry(entity.getFileName()));                //minio 获取流                InputStream ins = ossService.getObject(OssConfiguration.bucket,entity.getObjectKey());                FileInputStream insf=convertToFileInputStream(ins);                WritableByteChannel writableByteChannel = Channels.newChannel(zos);                FileChannel fileChannel = insf.getChannel();                fileChannel.transferTo(0, fileChannel.size(), writableByteChannel);                zos.closeEntry();                fileChannel.close();                ins.close();            }        } catch (IOException e) {            e.printStackTrace();        }finally {            if(zos != null){                try {                    zos.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if(os != null){                try {                    os.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return file;    }

第二种方法:安装hutool依赖,调用hutool包中的ZipUtil工具类中的zip方法进行下载,。此方法需要有3个参数,分别是OutoutStream,每个流对应的文件名字符串数组,文件的InputStream数组。

首先将需要下载的文件找到,拿到一组InputStream,也就是zip方法中的第3个参数,第一个参数顾名思义就是你想要输出的地方,我们是返回给前端所以就是response.getOutputStream(),第二个参数我们遍历文件时也可以拿到,废话不多说了,上代码看吧。

在项目下安装hutool依赖

    cn.hutool    hutool-all    5.5.7
      public void dowloadToZip(List mediaFileEntityList, HttpServletResponse response) throws Exception {        int i = 0;        //如果有附件 进行zip处理        if (mediaFileEntityList != null && mediaFileEntityList.size() > 0) {            try {                //被压缩文件流集合                InputStream[] srcFiles = new InputStream[mediaFileEntityList.size()];                //被压缩文件名称                String[] srcFileNames = new String[mediaFileEntityList.size()];                for (MediaFileEntity entity : mediaFileEntityList) {                    //以下代码为获取图片inputStream                    InputStream ins = ossService.getObject(OssConfiguration.bucket,entity.getObjectKey());                    if (ins == null) {                        continue;                    }                    //塞入流数组中                    srcFiles[i] = ins;                    srcFileNames[i] = entity.getFileName();                    i++;                }                response.setCharacterEncoding("UTF-8");                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("下载.zip", "UTF-8"));                //多个文件压缩成压缩包返回                ZipUtil.zip(response.getOutputStream(), srcFileNames, srcFiles);            } catch (IOException e) {                    e.printStackTrace();            }        }    }

Controller这边可以直接写成没有返回值的接口,我的例子如下,仅供参考:

    @GetMapping("/{workspace_id}/fileDownList")    @ApiOperation(value = "查询文件的下载地址")    public void getFileStreamList(@PathVariable(name = "workspace_id") String workspaceId,      @RequestParam(name = "ids") String ids, HttpServletResponse response) throws Exception {        List fileIds= Arrays.stream(ids.split(",")).collect(Collectors.toList()).stream()                .map(Integer::parseInt)                .collect(Collectors.toList());        List mediaFileEntityList = fileService.getMediaListById(workspaceId, fileIds);//        fileUtil.downloadZip("111",mediaFileEntityList,response);//第一种方法        fileUtil.dowloadToZip(mediaFileEntityList,response);//第二种方法    }

 到此,后端zip下载就完毕了,下面我们说说前端如何处理

网上查询前端处理大致都是如下,但是我自己使用的时候下载总是提示损坏,后找了一个工具类直接调用,就可以了,示例代码请求是get,如需调整,可根据情况自行调整

核心代码如下:

import { saveAs } from 'file-saver';    const baseURL = (window as any).config.VITE_APP_BASE_API; //import.meta.env.VITE_APP_BASE_API;export default {zip(url: string, name: string) {        url = baseURL + url;        axios({            method: 'get',            url: url,            responseType: 'blob',            headers: { Authorization: 'Bearer ' + getToken() },        }).then(res => {            const isBlob = blobValidate(res.data);            if (isBlob) {                const blob = new Blob([res.data], { type: 'application/zip' });                this.saveAs(blob, name);            } else {                this.printErrMsg(res.data);            }        });    },    saveAs(text: any, name: string, opts?: any) {        saveAs(text, name, opts);    },    async printErrMsg(data: any) {        const resText = await data.text();        const rspObj = JSON.parse(resText);        const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'];        // ElMessage.error(errMsg);    },    blobValidate(data: any) {        return data.type !== 'application/json';    }};

按钮绑定方法直接调用zip下载方法,传参为url和要导出zip的名称,示例如下:

import download from '@/plugins/download';function batchDownload(){    ElMessage.success("文件下载中,请勿重复点击!");    download.zip(`/media/api/v1/files/${workspaceId}/fileDownList?ids=${selectlist.value.join(",")}`,"MediaFiles"+new Date().toLocaleDateString()+".zip")}

来源地址:https://blog.csdn.net/weixin_41043580/article/details/132598816

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯