- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
本文 Demo 已收录到 demo-for-all-in-java 项目中,欢迎大家 star 支持!后续将持续更新! 。
产品经理急冲冲地走了过来。「现在需要将按这些数据生成一个 Word 报告文档,你来安排下」 。
项目中有这么一个需求,需要将用户填写的数据填充到一个 Word 文档中,而这个 Word 文档是人家给定了的。 换句话说,让你按照这个文档的内容格式生成新的文档.
官网: 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,也可以在指定位置进行合并 |
用户自定义函数(插件) | 在文档任何位置执行函数 |
我们就可以使用这个它来实现这个需求.
本篇文章将以 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 模板,这里我先演示下。就先创建一个名为 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 对象.
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 ?再不关注我可要求你关注了!");
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 文档里,可以有:文本、图片、表格、列表等元素,那么对应的,咱们的标签也有这些.
简单粗暴,直接 {{标签名}} 就是文本标签了.
{{@标签名}} 就是图片标签, @ 标识了这个标签的类型是图片,其他的也是同理,不同的符号标识不同类型的标签.
使用 # 标识这是一个表格标签.
使用 * 标识这是一个列表标签.
剩下的标签还有很多,详细的内容你可以阅读官方文档,这里就不一一介绍了.
下面我将写下我用过的内容.
插件,又称为 自定义函数 ,它允许我们在模板标签位置处执行预先定义好的函数。由于插件机制的存在,我们几乎可以在模板的任何位置执行任意操作.
插件是 poi-tl 的核心 ,默认的标签和引用标签都是通过插件加载.
poi-tl 默认提供了八个策略插件,用来处理文本、图片、列表、表格、文档嵌套、引用图片、引用多系列图表、引用单系列图表等:
由于这 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();
}
}
这样,就能实现表格的行循环了! 。
我们可以再封装下这个 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();
}
}
}
希望各位屏幕前的 靓仔靓女们 给个三连!你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星! 。
咱们下期再见! 。
最后此篇关于SpringBoot中使用Poi-tl渲染数据并生成Word文档的文章就讲到这里了,如果你想了解更多关于SpringBoot中使用Poi-tl渲染数据并生成Word文档的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试使用以下 keytool 命令为我的应用程序生成 keystore : keytool -genkey -alias tomcat -keystore tomcat.keystore -ke
编辑:在西里尔正确解决问题后,我注意到只需将生成轴的函数放在用于生成标签的函数下面就可以解决问题。 我几乎读完了 O'Reilly 书中关于 D3.js 的教程,并在倒数第二页上制作了散点图,但是当添
虽然使用 GraphiQL 效果很好,但我的老板要求我实现一个用户界面,用户可以在其中通过 UI 元素(例如复选框、映射关系)检查呈现给他们的元素并获取数据,这样做将为该人生成 graphql 输入,
我尝试在 Netbean 6.8 中使用 ws-import 生成 Java 类。我想重新生成 jax-ws,因为在 ebay.api.paypalapi 包中发现了一个错误(我认为该错误是由于 Pa
我有一个 perl 脚本,它获取系统日期并将该日期写入文件名。 系统日期被分配给 TRH1 变量,然后它被设置为一个文件名。 $TRH1 =`date + %Y%m%d%H%M`; print "TR
我是 Haskell 的新手,需要帮助。我正在尝试构建一种必须具有某种唯一性的新数据类型,因此我决定使用 UUID 作为唯一标识符: data MyType = MyType { uuid ::
我制作了一个脚本,它可以根据 Mysql 数据库中的一些表生成 XML。 该脚本在 PHP 中运行。 public function getRawMaterials($apiKey, $format
所以这是我的项目中的一个问题。 In this task, we will use OpenSSL to generate digital signatures. Please prepare a f
我在 SAS LIFEREG 中有一个加速故障时间模型,我想绘制它。因为 SAS 在绘图方面非常糟糕,我想实际重新生成 R 中曲线的数据并将它们绘制在那里。 SAS 提出了一个尺度(在指数分布固定为
我正在为 Django 后端制作一个样板,并且我需要能够使它到达下一个下载它的人显然无法访问我的 secret key 的地方,或者拥有不同的 key 。我一直在研究一些选项,并在这个过程中进行了实验
我正在创建一个生成采购订单的应用程序。我可以根据用户输入的详细信息创建文本文件。我想生成一个看起来比普通文本文件好得多的 Excel。有没有可以在我的应用程序中使用的开源库? 最佳答案 目前还没有任何
我正在尝试使用 ScalaCheck 为 BST 创建一个 Gen,但是当我调用 .sample 方法时,它给了我 java.lang.NullPointerException。我哪里错了? seal
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我尝试编写一些代码,例如(在verilog中): parameter N = 128; if (encoder_in[0] == 1) begin 23 binary_out = 1;
我正忙于在 Grails 项目中进行从 MySQL 到 Postgres 的相当复杂的数据迁移。 我正在使用 GORM 在 PostGres 中生成模式,然后执行 MySQL -> mysqldump
如何使用纯 XSLT 生成 UUID?基本上是寻找一种使用 XSLT 创建独特序列的方法。该序列可以是任意长度。 我正在使用 XSLT 2.0。 最佳答案 这是一个good example 。基本上,
我尝试安装.app文件,但是当我安装并单击“同步”(在iTunes中)时,我开始在设备上开始安装,然后停止,这是一个问题,我不知道在哪里,但我看到了我无法解决的奇怪的事情: 最佳答案 似乎您没有在Xc
自从我生成 JavaDocs 以来已经有一段时间了,我确信这些选项在过去 10 年左右的时间里已经得到了改进。 我能否得到一些有关生成器的建议,该生成器将输出类似于 .Net 文档结构的 JavaDo
我想学习如何生成 PDF,我不想使用任何第三方工具,我想自己用代码创建它。到目前为止,我所看到的唯一示例是我通过在第 3 方 dll 上打开反射器查看的代码,以查看发生了什么。不幸的是,到目前为止我看
我正在从 Epplus 库生成 excel 条形图。 这是我成功生成的。 我的 table 是这样的 Mumbai Delhi Financial D
我是一名优秀的程序员,十分优秀!