本文 Demo 已收录到 demo-for-all-in-java 我的项目中,欢送大家
star
反对!后续将继续更新!
前言
产品经理急冲冲地走了过去。「当初须要将按这些数据生成一个 Word 报告文档,你来安顿下」
我的项目中有这么一个需要,须要将用户填写的数据填充到一个 Word 文档中,而这个 Word 文档是人家给定了的。换句话说,让你依照这个文档的内容格局生成新的文档。
什么是 Poi-tl?
官网:http://deepoove.com/poi-tl/1.9.x/
poi-tl
(poi template language)是一种 Word 模板引擎,能够基于 Word 模板和数据生成新的文档,它的底层是通过 Apache POI 来实现的。
Apache POI 不仅封装了易用的文档 API(文本、图片、表格、页眉、页脚、图表等),也能够在底层间接操作文档 XML 构造。
poi-tl
领有如下个性(理解瞄一眼就行):
内容 | 形容 |
---|---|
文本 | 将标签渲染为文本 |
图片 | 将标签渲染为图片 |
表格 | 将标签渲染为表格 |
列表 | 将标签渲染为列表 |
图表 | 条形图(3D 条形图)、柱形图(3D 柱形图)、面积图(3D 面积图)、折线图(3D 折线图)、雷达图、饼图(3D 饼图)等图表渲染 |
If Condition 判断 | 暗藏或者显示某些文档内容(包含文本、段落、图片、表格、列表、图表等) |
Foreach Loop 循环 | 循环某些文档内容(包含文本、段落、图片、表格、列表、图表等) |
Loop 表格行 | 循环渲染表格的某一行 |
Loop 表格列 | 循环渲染表格的某一列 |
Loop 有序列表 | 反对有序列表的循环,同时反对多级列表 |
图片替换 | 将原有图片替换成另一张图片 |
书签、锚点、超链接 | 反对设置书签,文档内锚点和超链接性能 |
弱小的表达式 | 齐全反对 SpringEL 表达式,能够扩大更多的表达式:OGNL, MVEL… |
标签定制 | 反对自定义标签前后缀 |
文本框 | 文本框内标签反对 |
款式 | 模板即款式,同时代码也能够设置款式 |
模板嵌套 | 模板蕴含子模板,子模板再蕴含子模板 |
合并 | Word 合并 Merge,也能够在指定地位进行合并 |
用户自定义函数(插件) | 在文档任何地位执行函数 |
咱们就能够应用这个它来实现这个需要。
如何应用 Poi-tl?
本篇文章将以 Spring Boot 我的项目作为演示,屏幕前的敌人们能够一起跟着我的步骤来,实际一番!
- 首先创立一个 Spring Boot 我的项目,版本目前我的 Demo 是 2.2.1,你能够更改你的 Spring Boot 版本,那当初我这里曾经创立好了。
其中,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>
- 筹备一个 Word 模板
这一步你能够本人动手做一个 Word 模板,这里我先演示下。就先创立一个名为 Hello World.docx
的 Word 文档,模板内容如下:
找一个你喜爱的地位寄存这个模板,我当初把它放到我的项目的 resource
目录。
{{title}}
这种由两个大括号包住的,目前能够看成占位符,这个模板中有 4 个占位符,后续的数据就渲染到这些中央上。
- 获取模板所在的门路,并将数据渲染到模板上
渲染只需一行代码,就是应用 XWPFTemplate
的 API 就能够了,通过 complie
和 render
办法,就能够将数据渲染到模板中,失去渲染好的新文档。
@SpringBootTest
public class PoiTlApplicationTest {
@Test
public void test() {
// 获取 Word 模板所在门路
String filepath = this.getClass().getClassLoader().getResource("hello-world.docx").getPath();
// 通过 XWPFTemplate 编译文件并渲染数据到模板中
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", "这还不关注 god23bin?再不关注我可要求你关注了!");
}});
try {
// 将实现数据渲染的文档写出
template.writeAndClose(new FileOutputStream("output.docx"));
} catch (IOException e) {e.printStackTrace();
}
}
}
执行这个单元测试,就能够看到在我的项目所在目录下输入了新的文档 output.docx
,关上这个文档,咱们就能够看到如下图所示的内容:
功败垂成,这就是渲染好的新文档了,是不是很简略,一行代码就实现了依据模板进行数据的渲染!
相干概念
模板
模板是 Docx 格局的 Word 文档,咱们能够应用 Microsoft office、WPS Office 等软件来制作模板。
标签
下面说到 {{title}}
这种了解成占位符,实际上,官网是称之为「标签」。
所有的标签都是以 {{
结尾,以 }}
结尾,标签能够呈现在任何地位,包含页眉,页脚,表格外部,文本框等。
表格布局能够设计出很多优良业余的文档,举荐应用表格布局。
poi-tl 模板遵循 所见即所得
的设计,模板和标签的款式会被齐全保留,就如我下面演示的, 一级题目和字体色彩的款式就被保留下来了。
数据模型
数据模型,也就是咱们须要渲染到模板中的数据,能够是哈希表,也能够是一般的 Java 对象。
- 哈希表(key 名是标签名):
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", "这还不关注 god23bin?再不关注我可要求你关注了!");
- Java 对象(属性名是标签名):
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("这还不关注 god23bin?再不关注我可要求你关注了!");
有了哈希表和或者 Java 对象的数据模型后,将这个数据丢给渲染的 API,就能够实现数据的渲染了。
标签的写法
poi-tl 里只有标签,那么咱们须要晓得标签的写法是怎么的。在 Word 文档里,能够有:文本、图片、表格、列表等元素,那么对应的,咱们的标签也有这些。
文本标签 {{var}}
简略粗犷,间接 {{标签名}}
就是文本标签了。
图片标签 {{@var}}
{{@标签名}}
就是图片标签,@
标识了这个标签的类型是图片,其余的也是同理,不同的符号标识不同类型的标签。
表格标签 {{#var}}
应用 #
标识这是一个表格标签。
列表标签 {{*var}}
应用 *
标识这是一个列表标签。
其余的标签
剩下的标签还有很多,具体的内容你能够浏览官网文档,这里就不一一介绍了。
上面我将写下我用过的内容。
插件
插件,又称为 自定义函数,它容许咱们在模板标签地位处执行事后定义好的函数。因为插件机制的存在,咱们简直能够在模板的任何地位执行任意操作。
插件是 poi-tl 的外围,默认的标签和援用标签都是通过插件加载。
默认插件
poi-tl 默认提供了八个策略插件,用来解决文本、图片、列表、表格、文档嵌套、援用图片、援用多系列图表、援用单系列图表等:
- TextRenderPolicy
- PictureRenderPolicy
- NumberingRenderPolicy
- TableRenderPolicy
- DocxRenderPolicy
- MultiSeriesChartTemplateRenderPolicy
- SingleSeriesChartTemplateRenderPolicy
- DefaultPictureTemplateRenderPolicy
因为这 8 个插件是常常用到的,所以这些插件被注册为不同的标签类型,也就是咱们看到过的 {{var}}、{{@var}}、{{#var}}
等不同类型的标签,从而搭建了 poi-tl 的标签体系。
除了这 8 个通用的策略插件外,还内置了一些额定用处的插件:
DynamicTableRenderPolicy |
动静表格插件,容许间接操作表格对象 | 示例 - 动静表格 |
---|---|---|
HackLoopTableRenderPolicy |
循环表格行,下文会具体介绍 | 示例 - 表格行循环 |
LoopColumnTableRenderPolicy |
循环表格列 | 示例 - 表格列循环 |
BookmarkRenderPolicy |
书签和锚点 | 示例 -Swagger 文档 |
JSONRenderPolicy |
高亮显示 JSON 代码块 | 示例 -Swagger 文档 |
AbstractChartTemplateRenderPolicy |
援用图表插件,容许间接操作图表对象 | |
ParagraphRenderPolicy |
渲染一个段落,能够蕴含不同款式文本,图片等 | |
DocumentRenderPolicy |
渲染多个段落和表格 | |
TOCRenderPolicy |
Beta 试验性能:目录,打开文档时须要更新域 |
应用插件
为了让插件在某个标签处执行,咱们须要将 插件与标签绑定。
当咱们有个模板标签为 {{description}}
,默认是文本标签,如果心愿在这个地位做些不一样或者更简单的事件,咱们能够 将插件利用到这个模板标签,比方渲染 HTML:
ConfigureBuilder builder = Configure.builder();
builder.bind("description", new HtmlRenderPolicy());
此时,{{description}}
将不再是一个文本标签,而是一个自定义的反对 HTML 渲染的标签。
当然,这里的 HTML 渲染的插件,默认是没有提供的,须要引入以下的依赖项,能力反对 HTML 的渲染。
<!-- 反对渲染 HTML 的插件 -->
<dependency>
<groupId>io.github.draco1023</groupId>
<artifactId>poi-tl-ext</artifactId>
<version>0.3.3</version>
</dependency>
示例:咱们对 {{author}} 这个标签绑定上反对 HTML 渲染的插件,这样就能渲染 HTML 的文本了。
@SpringBootTest
public class PoiTlApplicationTest {
@Test
public void test() {
// 获取 Word 模板所在门路
String filepath = this.getClass().getClassLoader().getResource("hello-world.docx").getPath();
// 给标签绑定插件
Configure configure = Configure.builder().bind("author", new HtmlRenderPolicy()).build();
// 通过 XWPFTemplate 编译文件并渲染数据到模板中
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", "这还不关注 god23bin?再不关注我可要求你关注了!");
}});
try {
// 将实现数据渲染的文档写出
template.writeAndClose(new FileOutputStream("output.docx"));
} catch (IOException e) {e.printStackTrace();
}
}
}
生成的 Word 文档如下图所示,能够看到 {{author}} 这个标签的 HTML 文本曾经渲染胜利了!(蓝框框)
表格行循环
当有相似如下需要的时候,在表格里展现多行同类型的数据,那么就须要用到表格的行循环了。
这里也是波及到插件的,具体就是应用 HackLoopTableRenderPolicy
这个插件策略,这个策略可能依据汇合数据进行循环渲染,这样就渲染数据到表格的行上了,汇合有多少个元素,那么就有多少行。
咱们来看下这个表格行循环的模板是怎么写的,是这样的:
能够看到 {{articles}}
和 {{columns}}
是规范的文本标签,咱们这里将这两个标签置于 循环行的上一行,循环行里设置要循环的标签和内容,留神这里的标签是应用 []
的,以此来辨别规范的标签语法。
同时 {{articles}}
和 {{columns}}
标签对应的数据就是文章和专栏的汇合。
咱们写一个该模板的数据模型,以 Java 对象来写,同时模仿数据从数据库中读取。
数据模型:AcWordModel
public class AcWordModel {
/**
* 文章明细数据模型 - 表格行循环
*/
private List<Article> articles;
/**
* 专栏明细数据模型
*/
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
}
进行测试,获取数据和模板,让标签和表格行循环的插件进行绑定
@Test
public void rowLoopTest() {
// 获取数据,这里伪装是从数据库中查问失去的
AcWordModel data = getFromDB();
// 获取 Word 模板所在门路
String filepath = this.getClass().getClassLoader().getResource("table-row-loop.docx").getPath();
// 给标签绑定插件,这里就绑定表格行循环的插件
Configure configure = Configure.builder()
.bind("articles", new HackLoopTableRenderPolicy())
.bind("columns", new HackLoopTableRenderPolicy())
.build();
// 通过 XWPFTemplate 编译文件并渲染数据到模板中
XWPFTemplate template = XWPFTemplate.compile(filepath, configure).render(data);
try {
// 将实现数据渲染的文档写出
template.writeAndClose(new FileOutputStream("ac-word.docx"));
} catch (IOException e) {e.printStackTrace();
}
}
这样,就能实现表格的行循环了!
封装 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 生成指标文档门路
* @param data 待渲染的数据模型 - 哈希表模式
*/
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 生成指标文档门路
* @param data 待渲染的数据模型 -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 生成指标文档门路
* @param data 待渲染的数据模型 - 哈希表模式
* @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 生成指标文档门路
* @param data 待渲染的数据模型 -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();
}
}
}
最初的最初
心愿各位屏幕前的 靓仔靓女们
给个三连!你轻轻地点了个赞,那将在我的心里世界削减一颗亮堂而夺目的星!
咱们下期再见!