一种更好的模板生成word(docx)的方法,基于Apache POI。
FreeMarker 或 Velocity 根据文本模板和数据生成新的 html 页面或配置文件。 poi-tl是一个Word模板引擎,可以根据Word模板和数据生成新文档。
Word模板样式丰富。 Poi-tl会在生成的文档中完美保留模板中的样式。您还可以设置标签的样式。标签的样式将应用于替换的文本,因此您可以专注于模板设计。
poi-tl 是一个“无逻辑”模板引擎。没有复杂的控制结构和变量赋值,只有标签,有些标签可以替换为文本、图片、表格等,有些标签会隐藏某些文档内容,而另一些标签会循环一系列文档内容。
诸如变量赋值或条件语句之类的“强大”构造可以轻松地在模板系统中专门修改应用程序的外观...但是,以分离为代价,将模板本身变成应用程序逻辑的一部分。
《谷歌C模板》
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}}总是说生活就像一盒{{thing}}。
输出:
妈妈总是说生活就像一盒巧克力。
图片标签以@
开头,例如{{@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 测试用例。
您可以通过多种方式加入本项目,不限于以下方式:
请参阅常见问题解答。