一種更好的模板產生word(docx)的方法,基於Apache POI。
FreeMarker 或 Velocity 根據文字範本和資料產生新的 html 頁面或設定檔。 poi-tl是一個Word模板引擎,可以根據Word模板和資料產生新文件。
Word模板樣式豐富。 Poi-tl會在產生的文件中完美保留範本中的樣式。您也可以設定標籤的樣式。標籤的樣式將套用於替換的文本,因此您可以專注於模板設計。
poi-tl 是一個「無邏輯」模板引擎。沒有複雜的控制結構和變數賦值,只有標籤,有些標籤可以替換為文字、圖片、表格等,有些標籤會隱藏某些文件內容,而有些標籤會循環一系列文件內容。
諸如變數賦值或條件語句之類的「強大」構造可以輕鬆地在模板系統中專門修改應用程式的外觀...但是,以分離為代價,將模板本身變成應用程式邏輯的一部分。
《GoogleC模板》
poi-tl支援自訂函數(外掛程式) ,可以在Word範本中的任何位置執行函數,在文件中的任何位置做任何事情是poi-tl的目標。
特徵 | 描述 |
---|---|
✅ 文字 | 將標籤渲染為文字 |
✅ 圖片 | 將標籤渲染為圖片 |
✅ 桌子 | 將標籤渲染為表格 |
✅ 編號 | 將標籤渲染為編號 |
✅ 圖表 | 長條圖(3D長條圖)、長條圖(3D長條圖)、面積圖(3D面積圖)、折線圖(3D折線圖)、雷達圖、圓餅圖(3D圓餅圖)等圖表渲染 |
✅ 如果條件 | 根據條件隱藏或顯示某些文件內容(包括文字、段落、圖片、表格、清單、圖表等) |
✅ Foreach 循環 | 根據集合循環遍歷某些文件內容(包括文字、段落、圖片、表格、清單、圖表等) |
✅ 循環表行 | 循環複製渲染表的一行 |
✅ 循環表列 | 循環複製並渲染表格的一列 |
✅ 循環有序列表 | 支援有序列表的循環,同時支援多層列表 |
✅ 突出顯示代碼 | 代碼塊文字高亮,支援26種語言、數百種著色風格 |
✅ 降價 | 將 Markdown 轉換為 Word 文檔 |
✅ 文字附件 | 在Word中插入附件 |
✅ 文字評論 | 完成支援評論、建立評論、修改評論等。 |
✅ 字 SDT | 完整支援結構化文件標籤 |
✅ 文字框 | 文字方塊中的標籤支持 |
✅ 圖片替換 | 用另一張圖片取代原來的圖片 |
✅ 書籤、錨點、超鏈接 | 支援在文件中設定書籤、錨點和超鏈接 |
✅ 表達語言 | 完全支援SpringEL表達式,可以擴展更多表達式:OGNL、MVEL... |
✅ 風格 | 模板就是樣式,程式碼也可以設定樣式 |
✅ 模板嵌套 | 模板包含子模板,子模板又包含子模板 |
✅ 合併 | 單字合併 合併,也可以在指定位置合併 |
✅ 自訂功能(插件) | 插件式設計,在文件任意位置執行功能 |
< dependency >
< groupId >com.deepoove</ groupId >
< artifactId >poi-tl</ artifactId >
< version >1.12.2</ version >
</ dependency >
注意:poi-tl
1.12.x
需要 POI 版本5.2.2+
。
從一個非常簡單的例子開始:將{{title}}
替換為「poi-tl template engine」。
template.docx
,包括內容{{title}}
//The core API uses a minimalist design, only one line of code is required
XWPFTemplate . compile ( "template.docx" ). render ( new HashMap < String , Object >(){{
put ( "title" , "poi-tl template engine" );
}}). writeToFile ( "out_template.docx" );
打開out_template.docx
文檔,一切如你所願。
標籤由兩個大括號組成, {{title}}
是標籤, {{?title}}
也是標籤, title
是標籤的名稱, ?
標識標籤的類型。接下來我們來看看都有哪些標籤類型。
文字標籤是Word範本中最基本的標籤類型。 {{name}}
將被資料模型中鍵name
的值取代。如果key不存在,則清除該標籤(程式可以設定是否保留該標籤或拋出異常)。
文字標記的樣式將套用於替換的文本,如下例所示。
代碼:
put ( "name" , "Mama" );
put ( "thing" , "chocolates" );
模板:
{{name}}總是說人生就像一盒{{東西}}。
輸出:
媽媽總是說人生就像一盒巧克力。
圖片標籤以@
開頭,例如{{@logo}}
會在資料模型中尋找 key 為logo
的值,然後將標籤替換為圖片。圖片標籤對應的資料可以是簡單的URL或Path字串,也可以是包含圖片寬度和高度的結構體。
代碼:
put ( "watermelon" , "assets/watermelon.png" );
put ( "watermelon" , "http://x/lemon.png" );
put ( "lemon" , Pictures . ofLocal ( "sob.jpeg" , PictureType . JPEG ). size ( 24 , 24 ). create ());
模板:
Fruit Logo:
watermelon {{@watermelon}}
lemon {{@lemon}}
banana {{@banana}}
輸出:
Fruit Logo:
watermelon ?
lemon ?
banana ?
table 標籤以#
開頭,例如{{#table}}
,它將呈現為 N 行 N 列的 Word 表格。 N的值取決於table
標籤的資料。
代碼:
put ( "table" , Tables . of ( new String [][] {
new String [] { "Song name" , "Artist" }
}). border ( BorderStyle . DEFAULT ). create ());
模板:
{{#table}}
輸出:
歌曲名稱 | 藝術家 |
列表標籤對應於Word的符號列表或編號列表,以*
開頭,例如{{*number}}
。
代碼:
put ( "list" , Numberings . create ( "Plug-in grammar" ,
"Supports word text, pictures, table..." ,
"Template, not just template, but also style template" ));
模板:
{{*list}}
輸出:
● Plug-in grammar
● Supports word text, pictures, table...
● Templates, not just templates, but also style templates
一節由前後兩個標籤組成,起始標籤由?
標示。 ,結束標籤以/
標識,如{{?section}}
為sections塊的開始標籤, {{/section} }
為結束標籤, section
為該section的名稱。
在處理一系列文件元素時,部分非常有用。位於某部分的文件元素(文字、圖片、表格等)可以呈現零次、一次或 N 次,取決於該部分的值。
如果該節的值為null
、 false
或空集合,則不會顯示位於該節中的所有文檔元素,類似於 if 語句的條件為false
。
資料模型:
{
"announce" : false
}
模板:
Made it,Ma!{{?announce}}Top of the world!{{/announce}}
Made it,Ma!
{{?announce}}
Top of the world!?
{{/announce}}
輸出:
Made it,Ma!
Made it,Ma!
如果該節的值不為null
、 false
且不是集合,則該節中的所有文檔元素將被渲染一次,類似於 if 語句的條件為true
。
資料模型:
{
"person" : { "name" : " Sayi " }
}
模板:
{{?person}}
Hi {{name}}!
{{/person}}
輸出:
Hi Sayi!
如果該section的值是非空集合,則該section中的文檔元素將循環一次或N次,具體取決於集合的大小,類似於foreach語法。
資料模型:
{
"songs" : [
{ "name" : " Memories " },
{ "name" : " Sugar " },
{ "name" : " Last Dance " }
]
}
模板:
{{?songs}}
{{name}}
{{/songs}}
輸出:
Memories
Sugar
Last Dance
在循環中,可以使用一個特殊的標籤{{=#this}}
來直接引用目前迭代的物件。
資料模型:
{
"produces" : [
" application/json " ,
" application/xml "
]
}
模板:
{{?produces}}
{{=#this}}
{{/produces}}
輸出:
application/json
application/xml
嵌套是在一個Word模板中合併另一個Word模板,可以理解為導入、包含或word文檔合併,用+
標記,如{{+nested}}
。
代碼:
class AddrModel {
String addr ;
public AddrModel ( String addr ) {
this . addr = addr ;
}
}
List < AddrModel > subData = new ArrayList <>();
subData . add ( new AddrModel ( "Hangzhou,China" ));
subData . add ( new AddrModel ( "Shanghai,China" ));
put ( "nested" , Includes . ofLocal ( "sub.docx" ). setRenderModel ( subData ). create ());
兩個Word範本:
主.docx:
Hello, World
{{+nested}}
子.docx:
Address: {{addr}}
輸出:
Hello, World
Address: Hangzhou,China
Address: Shanghai,China
中文文檔
如需更多範例和所有範例的原始程式碼,請參閱 JUnit 測試案例。
您可以透過多種方式加入本項目,不限於以下方式:
請參閱常見問題。