Java使用poi-tl1.9.1生成Word文檔的技巧分享
前言
也許在您的工作當(dāng)中會碰到如下的一些場景,比如您需要組織一個(gè)活動,主辦方需要對每個(gè)報(bào)名參加的單位進(jìn)行報(bào)名通知書的生成。也許您會說,參加活動的不多,可以采取人工的方式進(jìn)行信息填寫,然后再發(fā)送給報(bào)名人員就好。如果僅是幾個(gè)人或者幾十個(gè)人還好,如果是幾百人,您還會選擇這種方式么?
針對這種批量動態(tài)個(gè)性化的word生成需求,有沒有什么技術(shù)可以進(jìn)行輔助生成呢?一定是有的,在Java的世界中,實(shí)現(xiàn)這種需求有好幾種實(shí)現(xiàn)方案,本文推薦一種簡單快捷的實(shí)現(xiàn)方式,基于開源的poi-tl的實(shí)現(xiàn)機(jī)制。本文將簡單介紹poi-tl的相關(guān)知識,通過一個(gè)實(shí)際的案例實(shí)踐,充分介紹如何利用poi-tl進(jìn)行目標(biāo)文檔的生成,同時(shí)分享幾個(gè)不同的office版本如何進(jìn)行圖表生成的解決方案。如果剛好您也在進(jìn)行相關(guān)技術(shù)選型,本文可以作為使用參考。
一、poi-tl簡介
1、什么是poi-tl
poi-tl(poi template language)是Word模板引擎,使用Word模板和數(shù)據(jù)創(chuàng)建很棒的Word文檔。poi-tl是一款采用Apache License 2.0開源協(xié)議的開源產(chǎn)品,poi-tl github地址。
2、常見的word生成對比
方案 | 移植性 | 功能性 | 易用性 |
---|---|---|---|
Poi-tl | Java跨平臺 | Word模板引擎,基于Apache POI,提供更友好的API | 低代碼,準(zhǔn)備文檔模板和數(shù)據(jù)即可 |
Apache POI | Java跨平臺 | Apache項(xiàng)目,封裝了常見的文檔操作,也可以操作底層XML結(jié)構(gòu) | 文檔不全,這里有一個(gè)教程:Apache POI Word快速入門 |
Freemarker | XML跨平臺 | 僅支持文本,很大的局限性 | 不推薦,XML結(jié)構(gòu)的代碼幾乎無法維護(hù) |
OpenOffice | 部署OpenOffice,移植性較差 | - | 需要了解OpenOffice的API |
HTML瀏覽器導(dǎo)出 | 依賴瀏覽器的實(shí)現(xiàn),移植性較差 | HTML不能很好的兼容Word的格式,樣式糟糕 | - |
Jacob、winlib | Windows平臺 | - | 復(fù)雜,完全不推薦使用 |
3、poi-tl功能點(diǎn)
d模板引擎功能 | 描述 |
---|---|
文本 | 將標(biāo)簽渲染為文本 |
圖片 | 將標(biāo)簽渲染為圖片 |
表格 | 將標(biāo)簽渲染為表格 |
列表 | 將標(biāo)簽渲染為列表 |
圖表 | 條形圖(3D條形圖)、柱形圖(3D柱形圖)、面積圖(3D面積圖)、折線圖(3D折線圖)、雷達(dá)圖、餅圖(3D餅圖)、散點(diǎn)圖等圖表渲染 |
If Condition判斷 | 根據(jù)條件隱藏或者顯示某些文檔內(nèi)容(包括文本、段落、圖片、表格、列表、圖表等) |
Foreach Loop循環(huán) | 根據(jù)集合循環(huán)某些文檔內(nèi)容(包括文本、段落、圖片、表格、列表、圖表等) |
Loop表格行 | 循環(huán)復(fù)制渲染表格的某一行 |
Loop表格列 | 循環(huán)復(fù)制渲染表格的某一列 |
Loop有序列表 | 支持有序列表的循環(huán),同時(shí)支持多級列表 |
Highlight代碼高亮 | word中代碼塊高亮展示,支持26種語言和上百種著色樣式 |
Markdown | 將Markdown渲染為word文檔 |
Word批注 | 完整的批注功能,創(chuàng)建批注、修改批注等 |
Word附件 | Word中插入附件 |
SDT內(nèi)容控件 | 內(nèi)容控件內(nèi)標(biāo)簽支持 |
Textbox文本框 | 文本框內(nèi)標(biāo)簽支持 |
圖片替換 | 將原有圖片替換成另一張圖片 |
書簽、錨點(diǎn)、超鏈接 | 支持設(shè)置書簽,文檔內(nèi)錨點(diǎn)和超鏈接功能 |
Expression Language | 完全支持SpringEL表達(dá)式,可以擴(kuò)展更多的表達(dá)式:OGNL, MVEL…? |
樣式 | 模板即樣式,同時(shí)代碼也可以設(shè)置樣式 |
模板嵌套 | 模板包含子模板,子模板再包含子模板 |
合并 | Word合并Merge,也可以在指定位置進(jìn)行合并 |
用戶自定義函數(shù)(插件) | 插件化設(shè)計(jì),在文檔任何位置執(zhí)行函數(shù) |
二、poi-tl文檔生成
通常來說,我們會先制作好一個(gè)標(biāo)準(zhǔn)的參考模板,讓后將需要替換的數(shù)據(jù)替換到目標(biāo)參數(shù)中,完成相應(yīng)參數(shù)的替換,所以剛開始先來準(zhǔn)備一分word模板。
1、模板準(zhǔn)備
在電腦的任意盤符,這里以D盤為例,創(chuàng)建一個(gè)文件輸入.docx的word文檔,打開文檔編輯
在這個(gè)模板中定義了文本標(biāo)簽以及圖片的定義。這里注意的是,{{}}這對標(biāo)準(zhǔn)參數(shù)符必須是英文狀態(tài)下輸入,之前有朋友就是沒注意中英文,導(dǎo)致程序沒有按照預(yù)期出來。同時(shí)注意圖片的引用符在參數(shù)名稱前面加上英文@符號。
在模板中加入一些圖表信息,豐富素材,這里需要設(shè)置。我個(gè)人電腦上的圖表參數(shù)設(shè)置如下(尤其注意不同的office版本,對應(yīng)的編輯處理方法不一致):
2、目標(biāo)參數(shù)填充
首先在工程中進(jìn)行pom.xml引入
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yelang</groupId> <artifactId>poi-demo2</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.9.1</version> </dependency> </dependencies> </project>
參數(shù)填充:這里為了演示方便,直接構(gòu)造演示數(shù)據(jù),真實(shí)項(xiàng)目中可以使從數(shù)據(jù)庫或者其它接口獲取相應(yīng)的數(shù)據(jù)來進(jìn)行參數(shù)的設(shè)置。
package com.yelang.test; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.data.ChartMultiSeriesRenderData; import com.deepoove.poi.data.Charts; import com.deepoove.poi.data.PictureRenderData; import com.deepoove.poi.data.PictureType; import com.deepoove.poi.data.Pictures; import com.deepoove.poi.data.SeriesRenderData; public class TestMain2 { public static void main(String[] args) throws IOException { Map<String, Object> map = new HashMap<String,Object>(); map.put("score", "28"); map.put("title", "測試任務(wù)"); map.put("type", "上半年綜合測評"); map.put("status", "已完成"); map.put("time", "2023-07-18"); map.put("locpicture", new PictureRenderData(400, 300, "D:/image.jpg")); map.put("urlImg", Pictures.ofUrl("https://p1.itc.cn/images01/20230418/5d13ab4a86c04a8dac668bf4129e1f0c.png", PictureType.PNG).size(400, 300).create()); ChartMultiSeriesRenderData sbqk = Charts .ofMultiSeries("十六市區(qū)縣情況", new String[] { "濟(jì)南","青島","煙臺","威海"}) .addSeries("上報(bào)情況", new Double[] { 15.0,20.6,42.6,90.1}) .addSeries("查出情況", new Double[] { 12.0,15.3,28.6,80.1}) .create(); map.put("sbqk", sbqk); ChartMultiSeriesRenderData sjzlpm = Charts .ofMultiSeries("醫(yī)院綜合排名", new String[] { "山東大學(xué)齊魯醫(yī)院","山東省泰山醫(yī)院","山東省第二人民醫(yī)院","山東省第三醫(yī)院"}) .addSeries("數(shù)據(jù)質(zhì)量排名", new Double[] { 70.5,40.6,22.7,85.4}) .addSeries("價(jià)格質(zhì)量排名", new Double[] { 80.5,75.6,72.7,85.4}) .create(); map.put("sjzlpm", sjzlpm); ChartMultiSeriesRenderData qst = Charts .ofMultiSeries("任務(wù)趨勢", new String[] { "06-10","06-11","06-12","06-13","06-14","06-15"}) .addSeries("微信端", new Double[] { 70.5,40.6,22.7,85.4,700.0,40.8}) .addSeries("PC端", new Double[] { 80.5,50.6,62.7,45.4,200.0,140.8}) .addSeries("小程序端", new Double[] { 120.5,520.6,362.7,405.4,300.0,340.8}) .create(); map.put("qst", qst); //柱狀圖、折線圖共存 List<SeriesRenderData> seriesRenderData = new ArrayList<SeriesRenderData>(3); SeriesRenderData series1 = new SeriesRenderData("GDP", new Double[] {70.5,40.6,22.7,85.4,700.0,40.8}); series1.setComboType(SeriesRenderData.ComboType.BAR); seriesRenderData.add(series1); SeriesRenderData series2 = new SeriesRenderData("人口", new Double[] {80.5,50.6,62.7,45.4,200.0,140.8}); series2.setComboType(SeriesRenderData.ComboType.BAR); seriesRenderData.add(series2); SeriesRenderData series3 = new SeriesRenderData("指數(shù)", new Double[] {0.6,0.6,0.7,0.4,0.7,0.8}); series3.setComboType(SeriesRenderData.ComboType.LINE); seriesRenderData.add(series3); ChartMultiSeriesRenderData hntb = Charts .ofMultiSeries("某省社會排名", new String[] { "城市1","城市2","城市3","城市4","城市5","城市6"}) .create(); hntb.setSeriesDatas(seriesRenderData); map.put("hntb", hntb); File file = new File("D:/文件輸入.docx"); XWPFTemplate template = XWPFTemplate.compile(file).render(map); FileOutputStream out = new FileOutputStream(new File("D:\\文件輸出.docx")); template.write(out); out.flush(); out.close(); template.close(); System.out.println("完成"); } }
3、生成效果
將以上代碼運(yùn)行后,可以在D盤目錄中看到以下的輸出結(jié)果。
三、可能會遇到的問題
1、混合圖表生成報(bào)錯(cuò)
如果在代碼運(yùn)行過程中遇到以下異常:
Exception in thread "main" com.deepoove.poi.exception.RenderException: Combo chart must set comboType field of series! at com.deepoove.poi.policy.reference.MultiSeriesChartTemplateRenderPolicy.validate(MultiSeriesChartTemplateRenderPolicy.java:122) at com.deepoove.poi.policy.reference.MultiSeriesChartTemplateRenderPolicy.doRender(MultiSeriesChartTemplateRenderPolicy.java:56) at com.deepoove.poi.policy.reference.MultiSeriesChartTemplateRenderPolicy.doRender(MultiSeriesChartTemplateRenderPolicy.java:48) at com.deepoove.poi.policy.reference.AbstractTemplateRenderPolicy.render(AbstractTemplateRenderPolicy.java:38) at com.deepoove.poi.render.processor.ElementProcessor.visit(ElementProcessor.java:70) at com.deepoove.poi.render.processor.ElementProcessor.visit(ElementProcessor.java:56) at com.deepoove.poi.template.ChartTemplate.accept(ChartTemplate.java:117) at com.deepoove.poi.render.processor.DocumentProcessor.visit(DocumentProcessor.java:104) at com.deepoove.poi.template.ChartTemplate.accept(ChartTemplate.java:117) at com.deepoove.poi.render.processor.DocumentProcessor.lambda$process$0(DocumentProcessor.java:58) at java.util.ArrayList.forEach(Unknown Source) at com.deepoove.poi.render.processor.DocumentProcessor.process(DocumentProcessor.java:58) at com.deepoove.poi.render.DefaultRender.renderTemplate(DefaultRender.java:82) at com.deepoove.poi.render.DefaultRender.render(DefaultRender.java:64) at com.deepoove.poi.XWPFTemplate.render(XWPFTemplate.java:127) at com.yelang.test.TestMain2.main(TestMain2.java:87)
Combo chart must set comboType field of series!這個(gè)問題大概率是因?yàn)閳D表生成沒有指定圖表類型。只需要的代碼中指定圖表類型即可,錯(cuò)誤參考代碼如下:
ChartMultiSeriesRenderData hntb = Charts .ofMultiSeries("title", new String[] { "06-10","06-11","06-12","06-13","06-14","06-15"}) .addSeries("系列1", new Double[] { 70.5,40.6,22.7,85.4,700.0,40.8}) .addSeries("系列1", new Double[] { 80.5,50.6,62.7,45.4,200.0,140.8}) .addSeries("系列1", new Double[] { 120.5,520.6,362.7,405.4,300.0,340.8}) .create();
正確參考代碼,通過series3.setComboType(SeriesRenderData.ComboType.LINE)指定:
List<SeriesRenderData> seriesRenderData = new ArrayList<SeriesRenderData>(3); SeriesRenderData series1 = new SeriesRenderData("GDP", new Double[] {70.5,40.6,22.7,85.4,700.0,40.8}); series1.setComboType(SeriesRenderData.ComboType.BAR); seriesRenderData.add(series1); SeriesRenderData series2 = new SeriesRenderData("人口", new Double[] {80.5,50.6,62.7,45.4,200.0,140.8}); series2.setComboType(SeriesRenderData.ComboType.BAR); seriesRenderData.add(series2); SeriesRenderData series3 = new SeriesRenderData("指數(shù)", new Double[] {0.6,0.6,0.7,0.4,0.7,0.8}); series3.setComboType(SeriesRenderData.ComboType.LINE); seriesRenderData.add(series3); ChartMultiSeriesRenderData hntb = Charts .ofMultiSeries("某省社會排名", new String[] { "城市1","城市2","城市3","城市4","城市5","城市6"}) .create(); hntb.setSeriesDatas(seriesRenderData);
2、圖表參數(shù)設(shè)置技巧
不同版本的office,對于參數(shù)的替換設(shè)置界面不一樣,尤其需要注意。這里提供兩種環(huán)境的設(shè)置參考。第一種是office2021。
office2021的圖表參數(shù)設(shè)置是鼠標(biāo)點(diǎn)擊圖表右鍵,出現(xiàn)查看可選文字,在這里進(jìn)行設(shè)置。
在以wps為例,本機(jī)安裝版本為:wps11.1.0
雙擊圖表空白區(qū),在文字選項(xiàng)中的大小與屬性一欄進(jìn)行設(shè)置
總結(jié)
以上就是本文的主要內(nèi)容,本文將簡單介紹poi-tl的相關(guān)知識,通過一個(gè)實(shí)際的案例實(shí)踐,充分介紹如何利用poi-tl進(jìn)行目標(biāo)文檔的生成,同時(shí)分享幾個(gè)不同的office版本如何進(jìn)行圖表生成的解決方案。如果剛好您也在進(jìn)行相關(guān)技術(shù)選型,本文可以作為使用參考。行文倉促,如有不當(dāng)之處,歡迎批評指正。
poi-tl 參考技術(shù)網(wǎng)站:https://deepoove.com/poi-tl/
以上就是Java使用poi-tl1.9.1生成Word文檔的技巧分享的詳細(xì)內(nèi)容,更多關(guān)于Java使用poi-tl1.9.1生成Word的資料請關(guān)注腳本之家其它相關(guān)文章!
- java 使用POI合并兩個(gè)word文檔
- java實(shí)現(xiàn)在線預(yù)覽--poi實(shí)現(xiàn)word、excel、ppt轉(zhuǎn)html的方法
- java poi設(shè)置生成的word的圖片為上下型環(huán)繞以及其位置的實(shí)現(xiàn)
- 利用Java Apache POI 生成Word文檔示例代碼
- java Apache poi 對word doc文件進(jìn)行讀寫操作
- Java使用poi將word轉(zhuǎn)換為html
- Java中使用Apache POI讀取word文件簡單示例
- java使用poi讀取ppt文件和poi讀取excel、word示例
- java通過poi解析word入門的操作方法
相關(guān)文章
SpringBoot使用TraceId進(jìn)行日志追蹤的實(shí)現(xiàn)
本文主要介紹了SpringBoot使用TraceId進(jìn)行日志追蹤的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01Spring?Boot?多數(shù)據(jù)源處理事務(wù)的思路詳解
這篇文章主要介紹了Spring?Boot?多數(shù)據(jù)源如何處理事務(wù),本文單純就是技術(shù)探討,要從實(shí)際應(yīng)用中來說的話,我并不建議這樣去玩分布式事務(wù)、也不建議這樣去玩多數(shù)據(jù)源,畢竟分布式事務(wù)主要還是用在微服務(wù)場景下,對Spring?Boot?多數(shù)據(jù)源事務(wù)相關(guān)知識感興趣的朋友參考下本文2022-06-06SpringBoot設(shè)置Json返回字段為非空問題
這篇文章主要介紹了SpringBoot設(shè)置Json返回字段為非空問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08mybatis批量update時(shí)報(bào)錯(cuò)multi-statement not allow的問題
這篇文章主要介紹了mybatis批量update時(shí)報(bào)錯(cuò)multi-statement not allow的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10java高并發(fā)寫入用戶信息到數(shù)據(jù)庫的幾種方法
本文主要介紹了java高并發(fā)寫入用戶信息到數(shù)據(jù)庫的幾種方法,具有很好的參考價(jià)值。下面跟著小編一起來看下吧2017-03-03如何實(shí)現(xiàn)在IDEA中導(dǎo)入一個(gè)模塊
這篇文章主要介紹了如何實(shí)現(xiàn)在IDEA中導(dǎo)入一個(gè)模塊方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04SpringBoot集成單點(diǎn)登錄CAS的方法實(shí)現(xiàn)
本文主要介紹了SpringBoot集成單點(diǎn)登錄CAS的方法實(shí)現(xiàn),包括CAS的基本概念、集成步驟、具體代碼示例等,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03