freemarker生成複雜樣式圖片並無檔案損壞的excel

Hlingoes發表於2021-05-30

參考Freemarker整合poi匯出帶有圖片的Excel教程優化程式碼實現和Excel版本相容。

(因對程式碼結構該動太大,沒有提交PR,程式碼核心思路和程式碼源於大腦補丁)

功能介紹:
1.支援Freemarker匯出Excel的所有功能(完美匯出複雜的合併單元格、合併行和列、顏色、字型等)
2.支援匯出帶有圖片的Excel
3.支援多Sheet頁匯出
4.支援匯出單元格註釋
5.支援完美匯出.xls、.xlsx格式,生成檔案開啟無報錯提醒
6.適用於生成複雜樣式的Excel,不適用於大資料量匯出

需求背景

企業級需求中有較多複雜樣式的excel需求,包括各種單元格合併,插入圖片,而且變更頻繁,案例如下:

單純使用JAVA POI無法滿足此類開發需求。Freemarker匯出的Excel為xml格式,此格式所有的富文字資訊都會丟失,只留下文字內容,不能直接匯出帶有圖片的Excel。通常使用Freemaker直接將.xml重新命名為.xls的方法,對複雜樣式相容不友好,會有彈框報錯。基於此種需求,開發此工具匯出帶有圖片的Excel。

依賴包

<dependencies><!-- 僅僅需要基本的starter,不需要web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency><!-- 模板引擎 -->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.28</version>
    </dependency><!-- java處理Excel檔案,支援excel2003 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>3.17</version>
    </dependency><!--支援excel2007以上,效能特別好-->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.17</version>
        <exclusions>
            <exclusion>
                <artifactId>poi</artifactId>
                <groupId>org.apache.poi</groupId>
            </exclusion>
        </exclusions>
    </dependency><!-- java解析XML檔案 -->
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.6.1</version>
    </dependency><!-- 使用其中的FileUtils工具類 -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency><dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.9</version>
    </dependency>

使用步驟

1. 參考Freemaker語法設定佔位符,將Excel檔案另存為XML;

2. 將模板XML放到專案的模板目錄中

3. 匯出效果

@Test
public void writeExcel() throws IOException {
    Map<String, Object> dataMap = getDemoDataMap();
    String templateName = "圖片-顏色-單元格合併-樣例.xml";
    /*
        若改變圖片位置,修改後4個引數
        dx1 dy1 起始單元格中的x,y座標.
        dx2 dy2 結束單元格中的x,y座標
        col1,row1 指定起始的單元格,下標從0開始
        col2,row2 指定結束的單元格 ,下標從0開始
     */
    HSSFClientAnchor hssfClientAnchor = new HSSFClientAnchor(0, 0, 0, 0, (short) 5, 1, (short) 13, 21);
    // 讀取resource下的檔案
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    // 獲取單個檔案
    Resource resource = resolver.getResource("template/功能簡介.png");
    File img = resource.getFile();

    ExcelImage hssfImage = new ExcelImage(img, 0, hssfClientAnchor);
    List<ExcelImage> hssfImgs = new ArrayList<>();
    hssfImgs.add(hssfImage);
    ExcelWriter.writeExcel2003(dataMap, templateName, "圖片-顏色-單元格合併-樣例-2003", hssfImgs);

    XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor(0, 0, 0, 0, (short) 5, 1, (short) 13, 21);
    ExcelImage xssfImage = new ExcelImage(img, 0, xssfClientAnchor);
    List<ExcelImage> xssfImgs = new ArrayList<>();
    xssfImgs.add(xssfImage);
    ExcelWriter.writeExcel2007(dataMap, templateName, "圖片-顏色-單元格合併-樣例-2007", xssfImgs);
}

程式碼邏輯

1. 使用Freemaker給佔位符賦值,生成XML檔案,該XML檔案中包含Excel原始樣式和所有資料;

2. 解析XML中的Excel樣式,轉化為CellStyle;

3. 遍歷XML的資料格式,按照讀取的CellStyle重新生成Excel;

4. 將圖片插入到給定的單元格中;

結論:此方法的邏輯是通過Freemaker模板引擎,給預置的Excel模板動態賦值,生成中間態的XML檔案,再解析該XML檔案生成新的Excel檔案。將複雜的樣式和資料的編輯放在模板中,通過兩次IO生成檔案,不適合大資料量的匯出,適合結構複雜和多樣定製的Excel生成。

專案地址:

1. 541211190/freemarker-excel (原作者的專案)
2. Hlingoes/freemaker-poi-excel (按原作者思路重新實現的專案)

相關文章