SpringBoot根據多階層創建文件,然後壓縮成壓縮包進行下載

来源:https://www.cnblogs.com/Serendipitys/p/17979459
-Advertisement-
Play Games

臨時接到一個需求說讓根據按照下麵的這個圖片的結構來打包下載指定位置下的文件到指定位置! 實現思路: 1.把已經實現的樹形結構的代碼進行調用,拿到他的數據進行創建對應的文件夾 2.因為結構下方的文件沒有特別直觀的資料庫中的關聯關係,所以還需要對於管理關係進行梳理 3.創建好階級文件,然後調用網上找的工 ...


臨時接到一個需求說讓根據按照下麵的這個圖片的結構來打包下載指定位置下的文件到指定位置!

實現思路:
  1.把已經實現的樹形結構的代碼進行調用,拿到他的數據進行創建對應的文件夾
  2.因為結構下方的文件沒有特別直觀的資料庫中的關聯關係,所以還需要對於管理關係進行梳理
  3.創建好階級文件,然後調用網上找的工具類打包成為rar壓縮包,然後把路勁交給前端進行調用下載
調用數據,然後傳遞給創建文件方法進行實現:
/**
 * 打包佐證成果文件,壓縮成為壓縮包!
 *
 * @param projectId
 * @param departId
 */
@ApiOperation(value = "打包佐證成果文件", notes = "佐證與成果-打包佐證成果文件")
@RequestMapping("/exportZip")
public Result<?> exportZip(@RequestParam(name = "projectId", required = false) String projectId, @RequestParam(name = "departId", required = true) String departId) {
    // 獲取樹形結構
    Result<List<SelectTreeMoneyModel>> loadAllTreeRoot = this.loadAllTreeRoot(projectId, departId);
    // 下載壓縮文件,將獲取到的樹形結構,傳遞到實現類進行解析跟實現
    String downloadZipFile = downloadZipFile(loadAllTreeRoot, "佐證跟成果", "/");
    return Result.ok(downloadZipFile);
}
遞歸的創建子集文件夾,然後調用工具類進行壓縮成為壓縮包文件,註:刪除文件必須捋清楚然後進行使用,其實不刪除也只會在指定的位置生成一份,所以我這邊沒有進行使用!
 /**
 * 遞歸的創建子集文件夾
 *
 * @param data
 * @param rootFile
 */

private void mkdirsChild(List<SelectTreeMoneyModel> data, File rootFile) {
    for (SelectTreeMoneyModel datum : data) {
        // 創建一個file實例對象,指向文件路徑(存放照片的根目錄)
        File childs = new File(rootFile, datum.getTitle());
        if (!childs.exists()) {
            childs.mkdirs();
        }
        // 判斷如果下麵還有子節點,如果有則調用自身
        if (!datum.isLeaf()) {
            mkdirsChild(datum.getChildren(), childs);
        }
        // 如果下麵沒有子節點,則進行判斷下麵是否有附件,如果有附件則進行下載到指定的文件夾內。
        List<ProjectResult> results = iProjectResultService.list(new LambdaQueryWrapper<ProjectResult>().eq(ProjectResult::getTypeId, datum.getKey()));
        if (ObjectUtils.isNotEmpty(results)) {
            for (ProjectResult result : results) {
                List<ProjectTaskContent> projectTaskContents = projectTaskContentService.list(new LambdaQueryWrapper<ProjectTaskContent>().eq(ProjectTaskContent::getResultId, result.getId()));
                for (ProjectTaskContent projectTaskContent : projectTaskContents) {
                    // 判斷附件表不是空的,則進行下載文件到對應的文件夾下
                    if (ObjectUtils.isNotEmpty(projectTaskContents)) {
                        RestTemplate restTemplate = new RestTemplate();
                        // 配置文件進行讀取
                        try {
                            ResponseEntity responseEntity = restTemplate.exchange(url + projectTaskContent.getFilePath(), HttpMethod.GET, null, byte[].class);
                            byte[] fileContent = (byte[]) responseEntity.getBody();
                            // 利用 File 對象,然後使用 getName() 方法獲取文件名(不包括路徑)。
                            File file = new File(projectTaskContent.getName());
                            String filenameWithoutPrefix = file.getName();
                            Files.write(Paths.get(childs + "\\" + filenameWithoutPrefix), fileContent);
                        } catch (IOException e) {
                            e.getMessage();
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }
    }
}
 /**
 * 下載壓縮文件
 *
 * @param data       數據集合【key:分類名稱,value:照片信息集合(key:照片名稱,value:照片下載路徑)】
 * @param fileStr    照片存放的文件路徑
 * @param zipFileStr 壓縮文件的路徑(加尾碼名)
 */
public String downloadZipFile(Result<List<SelectTreeMoneyModel>> data, String fileStr, String zipFileStr) {
    File rootFile = null;
    String folderPath = null;
    try {
        // 遍歷傳遞進來的數據,然後根據傳入的數據進行創建文件夾
        for (SelectTreeMoneyModel selectTreeMoneyModel : data.getResult()) {
            // 創建一個file實例對象,指向文件路徑(存放照片的根目錄)
            zipFileStr = folderUri + selectTreeMoneyModel.getTitle();
            folderPath = selectTreeMoneyModel.getTitle();
            rootFile = new File(zipFileUri + selectTreeMoneyModel.getTitle());
            if (!rootFile.exists()) {
                // 創建新文件夾,可以多層(mkdir()創建新文件夾,只能創建一層)
                rootFile.mkdirs();
            }
            // 根據判斷遞歸的創建文件夾,如果是false則有子集
            if (!selectTreeMoneyModel.isLeaf()) {
                mkdirsChild(selectTreeMoneyModel.getChildren(), rootFile);
            }
        }
        // 創建文件輸出流(zip流對象)【實際創建了zip文件,0kb】
        FileOutputStream fos1 = new FileOutputStream(new File(zipFileStr + ".zip"));
        // 壓縮法
        toZip1(rootFile, fos1, true);
        //TODO  刪除文件和壓縮文件,要保證每次壓縮只保存一份最新的存在。 因為是刪除文件,所以要慎用
        //delFolder(folderUri + folderPath);
        //delFolder(zipFileStr);
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 拼接返回的壓縮包地址
    String urlResult = url + folderPath + ".zip";
    return urlResult;
}

/**
 * 刪除文件夾
 *
 * @param folderPath 文件夾完整絕對路徑
 */
public static void delFolder(String folderPath) {
    try {
        // 刪除目錄下所有內容
        delAllFile(folderPath);
        File myFilePath = new File(folderPath);
        //刪除空文件夾
        myFilePath.delete();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * 刪除指定文件夾下所有文件
 *
 * @param path 文件夾完整絕對路徑
 */
public static boolean delAllFile(String path) {
    boolean bea = false;
    File file = new File(path);
    if (!file.exists()) {
        return bea;
    }
    if (!file.isDirectory()) {
        return bea;
    }
    //
    String[] tempList = file.list();
    File temp;
    if (tempList != null) {
        for (String var : tempList) {
            // separator 代替文件或文件夾路徑的斜線或反斜線,防止跨平臺出現錯誤
            if (path.endsWith(File.separator)) {
                temp = new File(path + var);
            } else {
                temp = new File(path + File.separator + var);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                //先刪除文件夾裡面的文件
                delAllFile(path + "/" + var);
                //再刪除空文件夾
                delFolder(path + "/" + var);
                bea = true;
            }
        }
    }
    return bea;
}

/**
 * 壓縮的遞歸方法
 *
 * @param sourceFile       源文件
 * @param zos              zip輸出流
 * @param fileName         源文件的名稱
 * @param keepDirStructure 是否保留原來的目錄結構,true:保留目錄結構;
 *                         false:所有文件跑到壓縮包根目錄下(註意:不保留目錄結構可能會出現同名文件,會壓縮失敗)
 */
private void compress(File sourceFile, ZipOutputStream zos, String fileName, boolean keepDirStructure) throws IOException {
    byte[] buf = new byte[2 * 1024];
    // 判斷是否是一個文件
    if (sourceFile.isFile()) {
        // 向zip輸出流中添加一個zip實體,構造器中name為zip實體的文件的名字
        zos.putNextEntry(new ZipEntry(fileName));
        // 創建文件(即某張圖片)的輸入流
        try (FileInputStream in = new FileInputStream(sourceFile)) {
            int len;
            // read方法:每調用一次就從FileInputStream流中讀取一個位元組,並返回下一個數據位元組,若已到達末尾,就返回-1。
            while ((len = in.read(buf, 0, buf.length)) != -1) {
                zos.write(buf, 0, len);
            }
            // 實際寫入到了zip輸出流的zip實體中,還沒寫到文件中【zip文件時0kb,不能打開,因為流沒有關閉】
            zos.closeEntry();
        } catch (IOException e) {
            throw new IOException(e);
        }
    } else {
        // 源文件時目錄
        // 獲取該目錄下所有文件和目錄的絕對路徑
        File[] listFiles = sourceFile.listFiles();
        // 空目錄
        if (listFiles == null || listFiles.length == 0) {
            // 需要保留原來的文件結構時,需要對空文件夾進行處理
            if (keepDirStructure) {
                // 空文件夾的處理
                zos.putNextEntry(new ZipEntry(fileName + "/"));
                // 沒有文件,不需要文件的copy
                zos.closeEntry();
            }
        } else {
            // 非空目錄
            for (File file : listFiles) {
                if (keepDirStructure) {
                    // 註意:getName()僅得到最後一層的名字,不是路徑,所以要加“/”,不然所有文件都跑到壓縮包根目錄下了
                    compress(file, zos, fileName + "/" + file.getName(), true);
                } else {
                    compress(file, zos, file.getName(), false);
                }
            }
        }
    }
}

/**
 * 壓縮成ZIP 方法1:保留多級目錄結構
 *
 * @param sourceFile       照片存放路徑
 * @param out              壓縮文件輸出流
 * @param keepDirStructure 是否保留原來的目錄結構,true:保留目錄結構;
 *                         false:所有文件跑到壓縮包根目錄下(註意:不保留目錄結構可能會出現同名文件,會壓縮失敗)
 */
public void toZip1(File sourceFile, OutputStream out, boolean keepDirStructure) throws IOException {
    long start = System.currentTimeMillis();
    // 創建壓縮輸出流,java7的新語法:Try-with-resources,會確保異常拋出或者try代碼塊結束時close流【該流必須實現AutoCloseable類】(若是java7之前的版本,則不會生效)
    try (ZipOutputStream zos = new ZipOutputStream(out)) {
        // 壓縮
        compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
        long end = System.currentTimeMillis();
        System.out.println("壓縮完成,耗時:" + (end - start) + " ms");
    } catch (IOException e) {
        throw new IOException(e);
    }
}
最後的實現結果

      總結: 主要還是要理清楚你的層級關係,
      1.然後在遞歸的時候一定要遞歸到最底層,然後根據最底層的數據查找跟附件表有關係的ID進行查找,然後將有關係的文件下載到指定的文件夾下,
      2.然後打包成為壓縮包這種實現直接可以進行百度查找到適合自己的工具類,如果不是直接適用,可以進行修改工具類的方法進行適配。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 依賴管理解決了在軟體開發過程中管理和協調各種依賴項的問題,簡化了開發流程,提高了項目的可靠性、可維護性和可重覆性。它們幫助開發人員更高效地管理項目的依賴關係,減少了潛在的錯誤和衝突,並提供了更好的開發體驗。 常用的依賴管理 在 JavaS ...
  • 最近,有群里在群里發了這麼一個非常有意思的卡片 Hover 動效,來源於此網站 -- key-drop,效果如下: 非常有意思酷炫的效果。而本文,我們不會完全還原此效果,而是基於此效果,嘗試去製作這麼一個類似的卡片交互效果: 該效果的幾個核心點: 卡片的 3D 旋轉跟隨滑鼠移動效果 如何讓卡片在 H ...
  • 一、定義 定義一個操作中演算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類不改變一個演算法的結構即可重定義該演算法的特定步驟。模板方法是一種類行為型模式 二、描述 模板方法模式結構比較簡單,其核心是抽象類和其中的模板方法的設計,包含以下兩個角色: 1、AbstractClass(抽象類):在抽象 ...
  • 本文在原文基礎上有刪減,原文參考泛型、Trait 和生命周期。 目錄泛型數據類型在函數定義中使用泛型結構體定義中的泛型枚舉定義中的泛型方法定義中的泛型泛型代碼的性能Trait:定義共同行為定義 trait為類型實現 trait預設實現trait 作為參數Trait Bound 語法通過 + 指定多個 ...
  • 一、pom.xml需要引入的依賴二、項目開啟熔斷器開關 2.1 註解方式 2.2 xml方式三、依賴類缺失問題四、版本匹配安全檢查問題五、測試驗證六、結論 一、pom.xml需要引入的依賴 pom.xml <!-- springboot升級到2.6.7,同樣適用於2.7.0,2.7.18等 --> ...
  • 看到標題大家可能會有點疑惑吧:OpenFeign 不是挺好用的嗎?尤其是微服務之間的遠程調用,平時用的也挺習慣的,為啥要替換呢? ...
  • 當然,我寫的簡易版協程池還有很多可以優化的地方,比如可以實現動態擴容等功能。今天我們要簡單總結一下協程池的優勢,主要是為了降低資源開銷。協程池的好處在於可以重覆利用協程,避免頻繁創建和銷毀協程,從而減少系統開銷,提高系統性能。此外,協程池還可以提高響應速度,因為一旦接收到任務,可以立即執行,不需要等... ...
  • ZooKeeperServer 實現了單機版zookeeper服務端功能,子類實現了更加豐富的分散式集群功能: ZooKeeperServer |-- QuorumZooKeeperServer |-- LeaderZooKeeperServer |-- LearnerZooKeeperServer ...
一周排行
    -Advertisement-
    Play Games
  • 前言 插件化的需求主要源於對軟體架構靈活性的追求,特別是在開發大型、複雜或需要不斷更新的軟體系統時,插件化可以提高軟體系統的可擴展性、可定製性、隔離性、安全性、可維護性、模塊化、易於升級和更新以及支持第三方開發等方面的能力,從而滿足不斷變化的業務需求和技術挑戰。 一、插件化探索 在WPF中我們想要開 ...
  • 歡迎ReaLTaiizor是一個用戶友好的、以設計為中心的.NET WinForms項目控制項庫,包含廣泛的組件。您可以使用不同的主題選項對項目進行個性化設置,並自定義用戶控制項,以使您的應用程式更加專業。 項目地址:https://github.com/Taiizor/ReaLTaiizor 步驟1: ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • Channel 是乾什麼的 The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consume ...
  • efcore如何優雅的實現按年分庫按月分表 介紹 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能、輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學習成本、零業務代碼入侵適配 距離上次發文.net相關的已經有很久了,期間一直在從事java相關的 ...
  • 前言 Spacesniffer 是一個免費的文件掃描工具,通過使用樹狀圖可視化佈局,可以立即瞭解大文件夾的位置,幫助用戶處理找到這些文件夾 當前系統C盤空間 清理後系統C盤空間 下載 Spacesniffer 下載地址:https://spacesniffer.en.softonic.com/dow ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 一、ReZero簡介 ReZero是一款.NET中間件 : 全網唯一開源界面操作就能生成API , 可以集成到任何.NET6+ API項目,無破壞性,也可讓非.NET用戶使用exe文件 免費開源:MIT最寬鬆協議 , 一直從事開源事業十年,一直堅持開源 1.1 純ReZero開發 適合.Net Co ...
  • 一:背景 1. 講故事 停了一個月沒有更新文章了,主要是忙於寫 C#內功修煉系列的PPT,現在基本上接近尾聲,可以回頭繼續更新這段時間分析dump的一些事故報告,有朋友微信上找到我,說他們的系統出現了大量的http超時,程式不響應處理了,讓我幫忙看下怎麼回事,dump也抓到了。 二:WinDbg分析 ...
  • 開始做項目管理了(本人3年java,來到這邊之後真沒想到...),天天開會溝通整理需求,他們講話的時候忙裡偷閑整理一下常用的方法,其實語言還是有共通性的,基本上看到方法名就大概能猜出來用法。出去打水的時候看到外面太陽好好,真想在外面坐著曬太陽,回來的時候好兄弟三年前送給我的鍵盤D鍵不靈了,在打"等待 ...