本文 Demo 已收錄到 demo-for-all-in-java 項目中,歡迎大家
star
支持!后續(xù)將持續(xù)更新!
前言
產(chǎn)品經(jīng)理急沖沖地走了過來?!脯F(xiàn)在需要將按這些數(shù)據(jù)生成一個 Word 報告文檔,你來安排下」
項目中有這么一個需求,需要將用戶填寫的數(shù)據(jù)填充到一個 Word 文檔中,而這個 Word 文檔是人家給定了的。換句話說,讓你按照這個文檔的內(nèi)容格式生成新的文檔。
什么是 Poi-tl ?
官網(wǎng):http://deepoove.com/poi-tl/1.9.x/
poi-tl
(poi template language)是一種 Word 模板引擎,可以基于 Word 模板和數(shù)據(jù)生成新的文檔,它的底層是通過 Apache POI 來實現(xiàn)的。
Apache POI 不僅封裝了易用的文檔 API (文本、圖片、表格、頁眉、頁腳、圖表等),也可以在底層直接操作文檔XML結(jié)構(gòu)。
poi-tl
擁有如下特性(了解瞄一眼就行):
內(nèi)容 | 描述 |
---|---|
文本 | 將標(biāo)簽渲染為文本 |
圖片 | 將標(biāo)簽渲染為圖片 |
表格 | 將標(biāo)簽渲染為表格 |
列表 | 將標(biāo)簽渲染為列表 |
圖表 | 條形圖(3D條形圖)、柱形圖(3D柱形圖)、面積圖(3D面積圖)、折線圖(3D折線圖)、雷達(dá)圖、餅圖(3D餅圖)等圖表渲染 |
If Condition判斷 | 隱藏或者顯示某些文檔內(nèi)容(包括文本、段落、圖片、表格、列表、圖表等) |
Foreach Loop循環(huán) | 循環(huán)某些文檔內(nèi)容(包括文本、段落、圖片、表格、列表、圖表等) |
Loop表格行 | 循環(huán)渲染表格的某一行 |
Loop表格列 | 循環(huán)渲染表格的某一列 |
Loop有序列表 | 支持有序列表的循環(huán),同時支持多級列表 |
圖片替換 | 將原有圖片替換成另一張圖片 |
書簽、錨點、超鏈接 | 支持設(shè)置書簽,文檔內(nèi)錨點和超鏈接功能 |
強大的表達(dá)式 | 完全支持SpringEL表達(dá)式,可以擴展更多的表達(dá)式:OGNL, MVEL… |
標(biāo)簽定制 | 支持自定義標(biāo)簽前后綴 |
文本框 | 文本框內(nèi)標(biāo)簽支持 |
樣式 | 模板即樣式,同時代碼也可以設(shè)置樣式 |
模板嵌套 | 模板包含子模板,子模板再包含子模板 |
合并 | Word合并Merge,也可以在指定位置進行合并 |
用戶自定義函數(shù)(插件) | 在文檔任何位置執(zhí)行函數(shù) |
我們就可以使用這個它來實現(xiàn)這個需求。
如何使用 Poi-tl ?
本篇文章將以 Spring Boot 項目作為演示,屏幕前的朋友們可以一起跟著我的步驟來,實踐一番!
- 首先創(chuàng)建一個 Spring Boot 項目,版本目前我的 Demo 是 2.2.1,你可以更改你的 Spring Boot 版本,那現(xiàn)在我這里已經(jīng)創(chuàng)建好了。
其中, pom.xml
只有兩個依賴項,一個 web 和一個 test :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Test 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
-
接著在
pom.xml
中引入 Poi-tl 的依賴項:
<!-- Poi-tl Word 模板引擎-->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.9.1</version>
</dependency>
- 準(zhǔn)備一個 Word 模板
這一步你可以自己動手做一個 Word 模板,這里我先演示下。就先創(chuàng)建一個名為 Hello World.docx
的 Word 文檔,模板內(nèi)容如下:
找一個你喜歡的位置存放這個模板,我現(xiàn)在把它放到項目的 resource
目錄。
{{title}}
這種由兩個大括號包住的,目前可以看成占位符,這個模板中有 4 個占位符,后續(xù)的數(shù)據(jù)就渲染到這些地方上。
- 獲取模板所在的路徑,并將數(shù)據(jù)渲染到模板上
渲染只需一行代碼,就是使用 XWPFTemplate
的 API 就可以了,通過 complie
和 render
方法,就可以將數(shù)據(jù)渲染到模板中,得到渲染好的新文檔。
@SpringBootTest
public class PoiTlApplicationTest {
@Test
public void test() {
// 獲取 Word 模板所在路徑
String filepath = this.getClass().getClassLoader().getResource("hello-world.docx").getPath();
// 通過 XWPFTemplate 編譯文件并渲染數(shù)據(jù)到模板中
XWPFTemplate template = XWPFTemplate.compile(filepath).render(
new HashMap<String, Object>(){{
put("title", "Hello, poi-tl Word模板引擎");
put("text", "Hello World");
put("author", "god23bin");
put("description", "這還不關(guān)注 god23bin ?再不關(guān)注我可要求你關(guān)注了!");
}});
try {
// 將完成數(shù)據(jù)渲染的文檔寫出
template.writeAndClose(new FileOutputStream("output.docx"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
執(zhí)行這個單元測試,就可以看到在項目所在目錄下輸出了新的文檔 output.docx
,打開這個文檔,我們就可以看到如下圖所示的內(nèi)容:
大功告成,這就是渲染好的新文檔了,是不是很簡單,一行代碼就完成了根據(jù)模板進行數(shù)據(jù)的渲染!
相關(guān)概念
模板
模板是 Docx 格式的 Word 文檔,我們可以使用 Microsoft office、WPS Office 等軟件來制作模板。
標(biāo)簽
上面說到 {{title}}
這種理解成占位符,實際上,官方是稱之為「標(biāo)簽」。
所有的標(biāo)簽都是以 {{
開頭,以 }}
結(jié)尾,標(biāo)簽可以出現(xiàn)在任何位置,包括頁眉,頁腳,表格內(nèi)部,文本框等。
表格布局可以設(shè)計出很多優(yōu)秀專業(yè)的文檔,推薦使用表格布局。
poi-tl 模板遵循 所見即所得
的設(shè)計,模板和標(biāo)簽的樣式會被完全保留,就如我上面演示的,一級標(biāo)題和字體顏色的樣式就被保留下來了。
數(shù)據(jù)模型
數(shù)據(jù)模型,也就是我們需要渲染到模板中的數(shù)據(jù),可以是哈希表,也可以是普通的 Java 對象。
- 哈希表(key 名是標(biāo)簽名):
Map<String, Object> data = new HashMap<>();
data.put("title", "Hello, poi-tl Word模板引擎");
data.put("text", "Hello World");
data.put("author", "god23bin");
data.put("description", "這還不關(guān)注 god23bin ?再不關(guān)注我可要求你關(guān)注了!");
- Java 對象(屬性名是標(biāo)簽名):
public class DataModel {
private String title;
private String text;
private String author;
private String description;
// 省略 getter 和 setter
}
DataModel data = new DataModel();
data.setTitle("Hello, poi-tl Word模板引擎");
data.setText("Hello World");
data.setAuthor("god23bin");
data.setDescription("這還不關(guān)注 god23bin ?再不關(guān)注我可要求你關(guān)注了!");
有了哈希表和或者 Java 對象的數(shù)據(jù)模型后,將這個數(shù)據(jù)丟給渲染的 API,就可以完成數(shù)據(jù)的渲染了。
標(biāo)簽的寫法
poi-tl 里只有標(biāo)簽,那么我們需要知道標(biāo)簽的寫法是怎樣的。在 Word 文檔里,可以有:文本、圖片、表格、列表等元素,那么對應(yīng)的,咱們的標(biāo)簽也有這些。
文本標(biāo)簽 {{var}}
簡單粗暴,直接 {{標(biāo)簽名}}
就是文本標(biāo)簽了。
圖片標(biāo)簽 {{@var}}
{{@標(biāo)簽名}}
就是圖片標(biāo)簽,@
標(biāo)識了這個標(biāo)簽的類型是圖片,其他的也是同理,不同的符號標(biāo)識不同類型的標(biāo)簽。
表格標(biāo)簽 {{#var}}
使用 #
標(biāo)識這是一個表格標(biāo)簽。
列表標(biāo)簽 {{*var}}
使用 *
標(biāo)識這是一個列表標(biāo)簽。
其余的標(biāo)簽
剩下的標(biāo)簽還有很多,詳細(xì)的內(nèi)容你可以閱讀官方文檔,這里就不一一介紹了。
下面我將寫下我用過的內(nèi)容。
插件
插件,又稱為自定義函數(shù),它允許我們在模板標(biāo)簽位置處執(zhí)行預(yù)先定義好的函數(shù)。由于插件機制的存在,我們幾乎可以在模板的任何位置執(zhí)行任意操作。
插件是 poi-tl 的核心,默認(rèn)的標(biāo)簽和引用標(biāo)簽都是通過插件加載。
默認(rèn)插件
poi-tl 默認(rèn)提供了八個策略插件,用來處理文本、圖片、列表、表格、文檔嵌套、引用圖片、引用多系列圖表、引用單系列圖表等:
- TextRenderPolicy
- PictureRenderPolicy
- NumberingRenderPolicy
- TableRenderPolicy
- DocxRenderPolicy
- MultiSeriesChartTemplateRenderPolicy
- SingleSeriesChartTemplateRenderPolicy
- DefaultPictureTemplateRenderPolicy
由于這 8 個插件是經(jīng)常用到的,所以這些插件被注冊為不同的標(biāo)簽類型,也就是我們看到過的 {{var}}、{{@var}}、{{#var}}
等不同類型的標(biāo)簽,從而搭建了 poi-tl 的標(biāo)簽體系。
除了這 8 個通用的策略插件外,還內(nèi)置了一些額外用途的插件:
DynamicTableRenderPolicy |
動態(tài)表格插件,允許直接操作表格對象 | 示例-動態(tài)表格 |
---|---|---|
HackLoopTableRenderPolicy |
循環(huán)表格行,下文會詳細(xì)介紹 | 示例-表格行循環(huán) |
LoopColumnTableRenderPolicy |
循環(huán)表格列 | 示例-表格列循環(huán) |
BookmarkRenderPolicy |
書簽和錨點 | 示例-Swagger文檔 |
JSONRenderPolicy |
高亮顯示JSON代碼塊 | 示例-Swagger文檔 |
AbstractChartTemplateRenderPolicy |
引用圖表插件,允許直接操作圖表對象 | |
ParagraphRenderPolicy |
渲染一個段落,可以包含不同樣式文本,圖片等 | |
DocumentRenderPolicy |
渲染多個段落和表格 | |
TOCRenderPolicy |
Beta實驗功能:目錄,打開文檔時需要更新域 |
使用插件
為了讓插件在某個標(biāo)簽處執(zhí)行,我們需要將插件與標(biāo)簽綁定。
當(dāng)我們有個模板標(biāo)簽為 {{description}}
,默認(rèn)是文本標(biāo)簽,如果希望在這個位置做些不一樣或者更復(fù)雜的事情,我們可以將插件應(yīng)用到這個模板標(biāo)簽,比如渲染 HTML:
ConfigureBuilder builder = Configure.builder();
builder.bind("description", new HtmlRenderPolicy());
此時,{{description}}
將不再是一個文本標(biāo)簽,而是一個自定義的支持 HTML 渲染的標(biāo)簽。
當(dāng)然,這里的 HTML 渲染的插件,默認(rèn)是沒有提供的,需要引入以下的依賴項,才能支持 HTML 的渲染。
<!-- 支持渲染 HTML 的插件 -->
<dependency>
<groupId>io.github.draco1023</groupId>
<artifactId>poi-tl-ext</artifactId>
<version>0.3.3</version>
</dependency>
示例:我們對 {{author}} 這個標(biāo)簽綁定上支持 HTML 渲染的插件,這樣就能渲染 HTML 的文本了。
@SpringBootTest
public class PoiTlApplicationTest {
@Test
public void test() {
// 獲取 Word 模板所在路徑
String filepath = this.getClass().getClassLoader().getResource("hello-world.docx").getPath();
// 給標(biāo)簽綁定插件
Configure configure = Configure.builder().bind("author", new HtmlRenderPolicy()).build();
// 通過 XWPFTemplate 編譯文件并渲染數(shù)據(jù)到模板中
XWPFTemplate template = XWPFTemplate.compile(filepath, configure).render(
new HashMap<String, Object>(){{
put("title", "Hello, poi-tl Word模板引擎");
put("text", "Hello World");
put("author", "<h2>god23bin</h2>");
put("description", "這還不關(guān)注 god23bin ?再不關(guān)注我可要求你關(guān)注了!");
}});
try {
// 將完成數(shù)據(jù)渲染的文檔寫出
template.writeAndClose(new FileOutputStream("output.docx"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
生成的 Word 文檔如下圖所示,可以看到 {{author}} 這個標(biāo)簽的 HTML 文本已經(jīng)渲染成功了?。ㄋ{(lán)框框)
表格行循環(huán)
當(dāng)有類似如下需求的時候,在表格里展示多行同類型的數(shù)據(jù),那么就需要用到表格的行循環(huán)了。
這里也是涉及到插件的,具體就是使用 HackLoopTableRenderPolicy
這個插件策略,這個策略能夠根據(jù)集合數(shù)據(jù)進行循環(huán)渲染,這樣就渲染數(shù)據(jù)到表格的行上了,集合有多少個元素,那么就有多少行。
我們來看下這個表格行循環(huán)的模板是怎樣寫的,是這樣的:
可以看到 {{articles}}
和 {{columns}}
是標(biāo)準(zhǔn)的文本標(biāo)簽,我們這里將這兩個標(biāo)簽置于循環(huán)行的上一行,循環(huán)行里設(shè)置要循環(huán)的標(biāo)簽和內(nèi)容,注意這里的標(biāo)簽是使用 []
的,以此來區(qū)分標(biāo)準(zhǔn)的標(biāo)簽語法。
同時 {{articles}}
和 {{columns}}
標(biāo)簽對應(yīng)的數(shù)據(jù)就是文章和專欄的集合。
我們寫一個該模板的數(shù)據(jù)模型,以 Java 對象來寫,同時模擬數(shù)據(jù)從數(shù)據(jù)庫中讀取。
數(shù)據(jù)模型:AcWordModel
public class AcWordModel {
/**
* 文章明細(xì)數(shù)據(jù)模型-表格行循環(huán)
*/
private List<Article> articles;
/**
* 專欄明細(xì)數(shù)據(jù)模型
*/
private List<SpecialColumn> columns;
// 省略 getter 和 setter
}
其中的 Article 和 SpecialColumn 模型如下:
public class Article {
private String title;
private String tags;
private Integer reading;
private Integer likes;
// 省略 getter 和 setter
}
public class SpecialColumn {
private String name;
private Integer subscription;
private Integer nums;
// 省略 getter 和 setter
}
進行測試,獲取數(shù)據(jù)和模板,讓標(biāo)簽和表格行循環(huán)的插件進行綁定
@Test
public void rowLoopTest() {
// 獲取數(shù)據(jù),這里假裝是從數(shù)據(jù)庫中查詢得到的
AcWordModel data = getFromDB();
// 獲取 Word 模板所在路徑
String filepath = this.getClass().getClassLoader().getResource("table-row-loop.docx").getPath();
// 給標(biāo)簽綁定插件,這里就綁定表格行循環(huán)的插件
Configure configure = Configure.builder()
.bind("articles", new HackLoopTableRenderPolicy())
.bind("columns", new HackLoopTableRenderPolicy())
.build();
// 通過 XWPFTemplate 編譯文件并渲染數(shù)據(jù)到模板中
XWPFTemplate template = XWPFTemplate.compile(filepath, configure).render(data);
try {
// 將完成數(shù)據(jù)渲染的文檔寫出
template.writeAndClose(new FileOutputStream("ac-word.docx"));
} catch (IOException e) {
e.printStackTrace();
}
}
這樣,就能實現(xiàn)表格的行循環(huán)了!
封裝 Word 渲染生成新文檔的工具
我們可以再封裝下這個 API,寫一個工具類,如下:
package cn.god23bin.demo.util;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
public class WordUtil {
/**
* 生成 word 文檔
* @param wordTemplatePath word 模板路徑
* @param targetWordFilePath 生成目標(biāo)文檔路徑
* @param data 待渲染的數(shù)據(jù)模型-哈希表形式
*/
public static void generateWordFile(String wordTemplatePath, String targetWordFilePath, Map<String, Object> data) {
XWPFTemplate template = XWPFTemplate.compile(wordTemplatePath).render(data);
try {
template.writeAndClose(new FileOutputStream(targetWordFilePath));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 生成 word 文檔
* @param wordTemplatePath word 模板路徑
* @param targetWordFilePath 生成目標(biāo)文檔路徑
* @param data 待渲染的數(shù)據(jù)模型-Java對象形式
*/
public static void generateWordFile(String wordTemplatePath, String targetWordFilePath, Object data) {
XWPFTemplate template = XWPFTemplate.compile(wordTemplatePath).render(data);
try {
template.writeAndClose(new FileOutputStream(targetWordFilePath));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 生成 word 文檔
* @param wordTemplatePath word 模板路徑
* @param targetWordFilePath 生成目標(biāo)文檔路徑
* @param data 待渲染的數(shù)據(jù)模型-哈希表形式
* @param configure 渲染配置
*/
public static void generateWordFile(String wordTemplatePath, String targetWordFilePath, Map<String, Object> data, Configure configure) {
XWPFTemplate template = XWPFTemplate.compile(wordTemplatePath, configure).render(data);
try {
template.writeAndClose(new FileOutputStream(targetWordFilePath));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 生成 word 文檔
* @param wordTemplatePath word 模板路徑
* @param targetWordFilePath 生成目標(biāo)文檔路徑
* @param data 待渲染的數(shù)據(jù)模型-Java對象形式
* @param configure 渲染配置
*/
public static void generateWordFile(String wordTemplatePath, String targetWordFilePath, Object data, Configure configure) {
XWPFTemplate template = XWPFTemplate.compile(wordTemplatePath, configure).render(data);
try {
template.writeAndClose(new FileOutputStream(targetWordFilePath));
} catch (IOException e) {
e.printStackTrace();
}
}
}
最后的最后
希望各位屏幕前的靚仔靚女們
給個三連!你輕輕地點了個贊,那將在我的心里世界增添一顆明亮而耀眼的星!文章來源:http://www.zghlxwxcb.cn/news/detail-704222.html
咱們下期再見!文章來源地址http://www.zghlxwxcb.cn/news/detail-704222.html
到了這里,關(guān)于Spring Boot 中使用 Poi-tl 渲染數(shù)據(jù)并生成 Word 文檔的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!