组合OSS服务实现打包业务文件zip下载

2023-05-16

前言

实现文件打包成zip下载,支持zip包含目录、文件。废话不多说,直接上码。


一、设计思路

  1. 后端组织文件,打包成zip
  2. 上传到OSS存储
  3. 返回文件名称给前端
  4. 前端根据返回的文件名称(url)直接从oss服务下载(这样做可以减轻业务服务器的压力,但是注意OSS服务上的文件注意定期清理)

二、核心代码

oss实现这里就不多说了,这里实际上还是涉及到一些契约编程。
impl实现方法

  @Override
    public String exportAppAlbum(ConstructionAlbumInfoVo constructionAlbumInfoVo) {
        String fileName = null;
        String albumName = exportEventImgs(constructionAlbumInfoVo, fileExtList);
        List<FileExt> fileExtList = new ArrayList<>();
       
        //开始导出
        InputStream fileInputStream = null;
        try {
            String today = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_MS_FORMAT);
            fileInputStream = ZipFileUtil.getFileInputStream(today, fileExtList);
            //上传文件到oss
            String resultFilename =
                    albumName + "_" + today + ".zip";
            ossClient.putObject(bucket, resultFilename, fileInputStream, "application/octet-stream");
            fileName = ossService.generateUrl(resultFilename);
        } catch (Exception e) {
            log.error("打包失败:", e);
            throw new BusinessException("下载文件打包失败");
        } finally {
            // 关闭流
            try {
                if (null != fileInputStream) {
                    fileInputStream.close();
                }
            } catch (IOException e) {
                log.error("打包失败:", e);
            }
        }
        return fileName;
    }

exportEventImgs方法

private String exportEventImgs(ConstructionAlbumInfoVo constructionAlbumInfoVo, List<FileExt> fileExtList) {
        String ids = constructionAlbumInfoVo.getIds();
        List<String> idList = Stream.of(ids.split(",")).collect(Collectors.toList());
        AtomicReference<Long> albumId = new AtomicReference<>();
        idList.stream().forEach(d -> {
            //查询事件信息
            Long eventId = Long.parseLong(d);
            ConstructionAlbum event = baseMapper.selectById(eventId);
            //查询相册信息
            albumId.set(event.getParentId());

            //查询照片信息
            QueryWrapper<ConstructionAlbum> qw = new QueryWrapper<>();
            qw.eq("parent_id", eventId);
            qw.eq("data_type", 3);
            qw.eq("delete_state", 1);
            List<ConstructionAlbum> imgList = baseMapper.selectList(qw);
            if (CollectionUtil.isNotEmpty(imgList)) {

                AtomicInteger count = new AtomicInteger(1);
                imgList.stream().forEach(a -> {
                    String url = a.getSourceUrl();
                    if (StringUtils.isNotEmpty(url)) {
                        url = url.replace("+", "%2B");
                        url = url.replace("&", "%26");
                        FileExt fileInfoByUrl = ExportUtil                      
                                .getFileInfoByUrl(url, event.getName(), DateUtil.format(event.getCreateTime(), DatePattern.PURE_DATETIME_MS_FORMAT), a.getName(), (long) count.get());
                        if (null != fileInfoByUrl && null != fileInfoByUrl.getInputStream()) {
                             //设置文件名称
                            fileInfoByUrl.setFileName(a.getName());
                            //设置目录名称
                            fileInfoByUrl.setFolder(event.getName());
                            fileExtList.add(fileInfoByUrl);
                            count.getAndIncrement();
                        } else {
                            log.error("打包失败:名称【{}】", url);
                        }
                    }
                });
            }
        });

        ConstructionAlbum album = baseMapper.selectById(albumId.get());
        return album.getName();
    }

实际上就是根据选中的id,查询文件的事件、相册名称,事件名称作为目录、相册下的照片作为文件名称。
FileExt扩展对象

@Data
public class FileExt {

    //文件流
    private InputStream inputStream;

    //文件名称
    private String fileName;
    //文件大小
    private String fileSize;
    //文件目录名称
    private String folder;

}

ExportUtil工具类

@Slf4j
public class ExportUtil {

  public static FileExt getFileInfoByUrl(String photoUrl,String prefix,String createTime,String fullName,Long count){
    InputStream is = null;
    try {
      // 构造URL
      URL url = new URL(photoUrl);
      // 打开连接
      URLConnection con = url.openConnection();
      //设置请求超时为5s
      con.setConnectTimeout(5 * 1000);
      // 输入流
      is = con.getInputStream();
      FileExt zipFileExt = new FileExt();
      //对url路径做截取,这里实际上还是一个契约命名规则,大家可以根据自己的业务调整
      String folder = prefix + "_" + fullName.split("/")[0] + "_" + createTime;
      String suffix = photoUrl.substring(photoUrl.lastIndexOf("."), photoUrl.length());
      String fileName = folder + "_"+ count + suffix;
      zipFileExt.setFileName(fileName);
      zipFileExt.setInputStream(is);
      zipFileExt.setFolder(folder);
      return zipFileExt;
    } catch (Exception e){
      log.error("下载图片失败:名称【{}】", photoUrl);
    }

    return null;
  }

}

ZipFileUtil工具类

@Slf4j
public class ZipFileUtil {

    public static String zipSuffix = ".zip";
    public static String fileNameField = "x-oss-meta-filename";

    /**
     *
     * @param fileName  压缩后的文件名称:测试.zip
     * @param fileExtList    子文件名称 + 文件流
     * @return
     */
    public static File compressionZipFile(String fileName, List<FileExt> fileExtList){
        File zipFile = null;
        try {
            zipFile = File.createTempFile(fileName, zipSuffix);
            FileOutputStream f = new FileOutputStream(zipFile);
            ZipOutputStream zos = new ZipOutputStream(f);

            //去重
            Map<String, List<FileExt>> collect = fileExtList.stream().collect(Collectors.groupingBy(FileExt::getFileName));
            fileExtList.clear();
            for (Map.Entry<String, List<FileExt>> entry : collect.entrySet()){
                fileExtList.add(entry.getValue().get(0));
            }

            for (FileExt zfe : fileExtList) {
                InputStream inputStream = zfe.getInputStream();
                if(StringUtils.isEmpty(zfe.getFolder())){
                    zfe.setFolder("/");
                }else{
                    zfe.setFolder(zfe.getFolder() + "/");
                }
                zos.putNextEntry(new ZipEntry(zfe.getFolder() + zfe.getFileName()));
                byte[] buf = new byte[1024 * 1024];
                int size = 0;
                while ((size = inputStream.read(buf)) != -1) {
                    zos.write(buf, 0, size);
                }
                inputStream.close();
                zos.closeEntry();
            }
            zos.close();
        } catch (IOException e) {
            log.error("压缩文件是报错:{}",e.getMessage());
            e.printStackTrace();
        }
        return zipFile;
    }

    public static InputStream getFileInputStream(String fileName, List<FileExt> zipFileExtList) throws Exception {
        File file = compressionZipFile(fileName, zipFileExtList);
        return new FileInputStream(file);
    }

    /**
     *根据网络文件路径获取输入流
     * @param url
     * @return
     */
    public static InputStream getImageStream(String url) {
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setReadTimeout(5000);
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = connection.getInputStream();
                return inputStream;
            }
        } catch (IOException e) {
            log.error("获取网络图片出现异常,图片路径为:{}.异常信息为:{}", url, e.getMessage());
            System.out.println("获取网络图片出现异常,图片路径为:" + url);
            e.printStackTrace();
        }
        return null;
    }

    public static FileExt getFileInfoByUrl(String url){
        FileExt zipFileExt = new FileExt();
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            //30s
            connection.setReadTimeout(30000);
            connection.setConnectTimeout(30000);
            connection.setRequestMethod("GET");
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                String fileSize = getFileSize(connection.getContentLengthLong());
//                String fileName = connection.getHeaderField(fileNameField);
                //对url路径做截取
                String fileName = url.substring(url.lastIndexOf("/") + 1, url.length());
                InputStream inputStream = connection.getInputStream();
                zipFileExt.setFileSize(fileSize);
                zipFileExt.setFileName(fileName);
                zipFileExt.setInputStream(inputStream);
            }
        } catch (IOException e) {
            log.error("获取网络图片出现异常,图片路径为:{}.异常信息为:{}", url, e.getMessage());
            System.out.println("获取网络图片出现异常,图片路径为:" + url);
            e.printStackTrace();
        }
        return zipFileExt;
    }

    public static String getFileUrlSize(String url){
        String result = "0";
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setReadTimeout(5000);
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                result = getFileSize(connection.getContentLengthLong());
            }
        } catch (IOException e) {
            log.error("获取网络图片出现异常,图片路径为:{}.异常信息为:{}", url, e.getMessage());
            System.out.println("获取网络图片出现异常,图片路径为:" + url);
            e.printStackTrace();
        }
        return result;
    }

    public static String getFileNameByURL(String url){
        String result = "";
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setReadTimeout(5000);
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                result = connection.getHeaderField(fileNameField);
            }
        } catch (IOException e) {
            log.error("获取网络图片出现异常,图片路径为:{}.异常信息为:{}", url, e.getMessage());
            System.out.println("获取网络图片出现异常,图片路径为:" + url);
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 字节转kb/mb/gb
     * @param size
     * @return
     */
    public static String getFileSize(long size) {
        //以B为单位
        if (size < 1024) {
            return String.valueOf(size) + "B";
        } else {
            size = size / 1024;
        }
        //以KB为单位
        if (size < 1024) {
            return String.valueOf(size) + "KB";
        } else {
            size = size / 1024;
        }
        if (size < 1024) {
            //以MB为单位
            size = size * 100;
            return String.valueOf((size / 100)) + "."
                    + String.valueOf((size % 100)) + "MB";
        } else {
            //以GB为单位的,先除于1024再作同样的处理
            size = size * 100 / 1024;
            return String.valueOf((size / 100)) + "."
                    + String.valueOf((size % 100)) + "GB";
        }
    }
}

总结

  • 其实没啥好总结的,也就是将zip打包、OSS上传下载做了一个组合而已。打包zip文件做了服务公共业务提取处理。希望能帮到大家uping
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

组合OSS服务实现打包业务文件zip下载 的相关文章

  • 在 Swift 中从字符串创建 ZIP 文件

    let data InPractiseThisWillBeAReheallyLongString createDir let docsDir FileManager default urls for documentDirectory in
  • 如何通过 Scala 中的 Play Framework 2.5 流式传输压缩文件(即时)?

    我想流式传输一些文件并即时压缩它们 以便用户可以将多个文件下载到一个压缩文件中 而无需向本地磁盘写入任何内容 但是 我当前的实现将所有内容保存在内存中 并且不适用于大文件 有什么办法可以解决吗 我正在研究这个实现 https gist gi
  • C# 如何杀死阻塞的线程?

    我有一个线程 void threadCode object o doStuffHere o Blocking call Sometimes hangs 我这样称呼它 Thread t new Thread new ThreadStart d
  • 从其他服务器下载之前是否可以动态压缩文件?

    我想知道是否可以编写浏览器扩展或简单的 Java 脚本代码 其中包含指向不同位置的 URL 列表 可以将所有内容压缩在一起 我是说 例如 有 3 个不同的图像文件 http example1 com a png http example1
  • 读取 jar 文件中的 zip 文件

    之前我们的 Web 应用程序中有一些 zip 文件 我们想要解析 zip 文件中的特定文本文档 这不是问题 URL url getClass getResource zipfile ZipFile zip new ZipFile url g
  • PHP zipArchive 类的大小限制?

    我正在 PHP 中创建一个 zip 文件供用户下载 我没有从 PHP 或检查 zipArchive 类的 GetStatusString 函数中得到任何错误 但是 如果我将一些文件放入存档中 那么当我尝试打开它时 我会收到错误 压缩的 zi
  • 如何在 Rails 5.x.x 应用程序中以 Zip 格式从 S3 下载多个文件?

    我正在实现允许用户从 S3 下载单个文件或多个文件的功能 单个文件下载工作正常 但对于多个文件 我在 Heroku 上收到错误 Errno ENOENT No such file or directory rb file s lstat 用
  • 提取 Zip 内的目录

    我正在编写一个脚本 将 zip 存档中的文件提取到该脚本所在的目录中 这是我的代码 zip new ZipArchive if zip gt open latest zip TRUE zip gt extractTo zip gt clos
  • 如何从 zip 中打开 html 文件?

    有什么方法可以从包含 html 引用的图像的 zip 文件中打开 html 文件吗 我生成带有资源相对路径的 html 但浏览器不会在 zip 文件中找到它们 我必须先将其提取 从拉链打开它是理想的选择 有什么办法可以做到吗 据我所知 只有
  • 使用node.js核心zlib模块压缩成.zip文件

    如何压缩一个或多个文件并将其保存到 zip包含所提供的 node js 的扩展文件zlib https nodejs org api zlib html模块 我想出了如何保存到 gz使用 gzip 如下 const gzip zlib cr
  • 覆盖 ZipArchiveEntry 的内容

    如何覆盖 a 的内容ZipArchiveEntry 以下代码使用StreamWriter with StringBuilder如果新文件内容比原始文件内容短 则会失败 例如 using System IO Compression using
  • 使用 ionic zip 时压缩失败

    我正在使用最新版本的 ionic zip 版本 1 9 1 8 我已经设置了 ionic zip 的属性ParallelDeflateThreshold 0 过去两个月 压缩机制工作得很好 突然 它停止工作了 压缩线程挂起 ionic zi
  • 使用 Java 将文件附加到 zip 文件

    我当前正在提取一个 war 文件的内容 然后将一些新文件添加到目录结构中 然后创建一个新的 war 文件 这一切都是通过Java以编程方式完成的 但我想知道复制战争文件然后附加文件是否会更有效 然后我就不必等待战争扩大然后必须再次被压缩 我
  • Osmdroid 离线文件

    我有一个 osmdroid 地图 我想从 MOBAC 的 osmdroid zip 或 gemf 文件加载离线图块 我查看了它 无论我走到哪里 它都说只需将其放入 sdcard osmdroid 中即可 但它不起作用 我需要更改代码中的某些
  • 如何从 Java 中的 HttpResponse 获取单个表单字段并将其写入文件?

    我正在调用客户端的下载服务 该服务会发回 MIME 数据并尝试保存 zip 文件 该服务不仅返回文件本身 还返回其他几个 MIME 字段 因此 当我使用entity getContent 打开输入流时 我最终将所有这些数据写入我的zip 文
  • 需要使用 Node.js 压缩整个目录

    我需要使用 Node js 压缩整个目录 我目前正在使用node zip 每次该进程运行时都会生成一个无效的ZIP文件 正如您可以从这个 Github 问题 https github com Stuk jszip issues 41 是否有
  • 适用于 iOS 的最佳存档器库 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个可在我的 iOS 应用程序中使用的存档器库 zip 或其他格式 就以下方面而言 最好的图书
  • ZipArchives 存储绝对路径

    我可以使用相对路径压缩文件吗 例如 zip gt addFile c wamp www foo file txt ZIP 应该具有如下目录结构 foo gt file txt and not wamp gt www gt foo gt fi
  • 使用 fopen() 包装器创建 ZIP 文件

    如何使用以下命令创建 ZIP 文件fopen 包装器 http es php net manual en wrappers compression php 这显然是not道路
  • 为什么 Python zipfile 不提供与命令行 zip 相同的输出 .zip 文件大小?

    这是生成的文件的大小zip seq 10000 gt 1 txt zip 1 1 txt adding 1 txt deflated 54 ls og 1 zip rw r r 1 22762 Aug 29 10 04 1 zip 这是一个

随机推荐

  • SVN异常之svn:E230001 Server SSL certificate verification failed

    起因 某一天上班 xff0c 使用idea更新代码 xff0c 发现出现如下问题 xff1a Error svn E230001 Unable to connect to a repository at URL 39 https xxx x
  • 在Linux下,禁止某一个显示屏的输出

    今天接到了一个任务 xff0c 实现显示屏的关和开 理了下思路 xff1a 1 需求 xff1a 实现终端的开关屏 xff0c 要求仅仅是终端的屏幕关掉了 xff0c 但是系统仍旧在跑 xff0c 可以用遥控器唤醒 2 方向 xff1a 2
  • 十分钟搞懂字符编码

    编码方式描述ANSI编码常见于window xff0c 与windows操作系统所面向的国家地区有关在简体中文Windows操作系统中 xff0c ANSI 编码代表 GBK 编码在繁体中文Windows操作系统中 xff0c ANSI 编
  • python数字运算

    加法 num1 span class token operator 61 span span class token builtin input span span class token punctuation span span cla
  • k8s集群运维之master节点无法调度问题

    k8s集群创建完成后 xff0c 在部署应用的时候发现master节点无法部署pod 解决步骤如下 查看节点名称 master01 k8s git span class token punctuation span master span
  • Debian 9安装Clion 2018

    现在去官网直接下载 https www jetbrains com clion 解压缩 tar zxvf CLion 2018 1 5 tar gz cd clion 2018 1 5 bin clion sh CLion是收费 的 xff
  • 从用户email信息分析是否为qq邮箱并截取qq号的sql语句

    思路 xff1a 1 email是qq邮箱 2 qq邮箱也可以自己注册的 xff0c 39 64 39 前面有可能是随意填写的字符串 xff0c 过滤 39 64 39 前面不是数字的 3 截取符合邮箱 39 64 39 前面部分即为qq号
  • 解决Ubuntu虚拟机NAT不能上网的几种方法

    vmware安装ubuntu虚拟机后 xff0c 网络经常抽风 也不知道具体是什么原因导致的 有时候开机就不能上网 xff0c 有时候 xff0c 是突然不能上网 这个时候 xff0c 尝试重启虚拟机后者电脑 xff0c 看看能否解决 或者
  • 显示https不安全的原因及解决办法

    很多人在部署了https证书之后 xff0c 有的时候仍然会出现https 不安全 的提示 xff0c 这就比较纳闷了 明明说部署了https证书会受到浏览器的信任的 xff0c 怎么还会出现这种情况 xff1f 安信SSL帮大家分析一下原
  • 小程序input输入限制小数位数

    小程序input组件本身没有自带这个校验属性 xff0c 但有一个maxlength属性 xff0c 可以通过是否输入了小数点来动态计算设置maxlength的方法达到限制输入的目的 保留一位小数 lt view class 61 34 l
  • js数组对象去重

    removeID span class token operator 61 span span class token punctuation span arr span class token punctuation span span
  • 解决echarts刷新不重绘

    切换筛选条件重新查询时候Echart不重新绘制 需要绘制之前初始化Echart echarts span class token punctuation span span class token function init span sp
  • 判断是否有值,0也是有值的情况

    span class token operator span span class token function isNaN span span class token punctuation span span class token f
  • 基于高德地图SDK进行搜索

    高德地图SDK使用地址http lbs amap com 地图设置 define GDMAPKEY 64 34 key 34 import 34 ViewController h 34 import lt MapKit MapKit h g
  • Microsoft Visual C++ Build Tools.exe安装包损坏

    Python3安装支持库的过程中经常会遇到 Microsoft Visual C 14 0 is required 此时就需要安装Visual C build tools生成工具 在运行build tool安装时 提示安装包损坏 翻墙也无效
  • debian图形界面安装

    安装GNOME中文桌面环境 安装基本的X系统 apt get install x window system core 安装GNOME桌面环境 apt get install gnome 到现在为止 xff0c 我们已成功安装完成gnome
  • Qt 调试时 程序异常结束

    在调试时 xff0c 关闭窗口 xff0c 应用程序输出窗口提示 Qt 调试时 程序异常结束 21 20 48 程序异常结束 21 20 48 The process was ended forcefully 21 20 48 G proj
  • c#webservice的简单示例

    是webservice 就概念上来说 xff0c 可能比较复杂 xff0c 不过我们可以有个宏观的了解 xff1a webservice就是个对外的接口 xff0c 里面有 函数可供外部客户调用 xff08 注意 xff1a 里面同样有客户
  • 实现常规厂家&品牌&型号业务对接物联网平台(snack3加json赋能)

    前言 之前介绍过通过snack3快速对接物模型 xff0c 不知道大家还有没有影响 记得还留了一个作业给大家想想 xff0c 就是这么兼容多型号 多版本 xff0c 这次就来跟大家分享下这么集成多型号 一 物模型文件调整 上次是利用snac
  • 组合OSS服务实现打包业务文件zip下载

    前言 实现文件打包成zip下载 xff0c 支持zip包含目录 文件 废话不多说 xff0c 直接上码 一 设计思路 后端组织文件 xff0c 打包成zip上传到OSS存储返回文件名称给前端前端根据返回的文件名称 xff08 url xff