芮城网站建设,网站建设销售话术开场白,杭州租车网站建设,做文案公众号策划兼职网站本文 Demo 已收录到 demo-for-all-in-java 项目中#xff0c;欢迎大家 star 支持#xff01;后续将持续更新#xff01; 前言 产品经理急冲冲地走了过来。「现在需要将按这些数据生成一个 Word 报告文档#xff0c;你来安排下」 项目中有这么一个需求#xff0c;需要将用户… 本文 Demo 已收录到 demo-for-all-in-java 项目中欢迎大家 star 支持后续将持续更新 前言 产品经理急冲冲地走了过来。「现在需要将按这些数据生成一个 Word 报告文档你来安排下」 项目中有这么一个需求需要将用户填写的数据填充到一个 Word 文档中而这个 Word 文档是人家给定了的。换句话说让你按照这个文档的内容格式生成新的文档。 
什么是 Poi-tl  官网http://deepoove.com/poi-tl/1.9.x/ poi-tlpoi 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  
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency
!-- Spring Boot Test 依赖 --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope
/dependency接着在 pom.xml 中引入 Poi-tl 的依赖项 
!-- Poi-tl Word 模板引擎--
dependencygroupIdcom.deepoove/groupIdartifactIdpoi-tl/artifactIdversion1.9.1/version
/dependency准备一个 Word 模板 
这一步你可以自己动手做一个 Word 模板这里我先演示下。就先创建一个名为 Hello World.docx 的 Word 文档模板内容如下 找一个你喜欢的位置存放这个模板我现在把它放到项目的 resource 目录。 {{title}} 这种由两个大括号包住的目前可以看成占位符这个模板中有 4 个占位符后续的数据就渲染到这些地方上。 获取模板所在的路径并将数据渲染到模板上 
渲染只需一行代码就是使用 XWPFTemplate 的 API 就可以了通过 complie 和 render 方法就可以将数据渲染到模板中得到渲染好的新文档。 
SpringBootTest
public class PoiTlApplicationTest {Testpublic void test() {// 获取 Word 模板所在路径String filepath  this.getClass().getClassLoader().getResource(hello-world.docx).getPath();// 通过 XWPFTemplate 编译文件并渲染数据到模板中XWPFTemplate template  XWPFTemplate.compile(filepath).render(new HashMapString, 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 名是标签名 
MapString, 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 默认提供了八个策略插件用来处理文本、图片、列表、表格、文档嵌套、引用图片、引用多系列图表、引用单系列图表等 
TextRenderPolicyPictureRenderPolicyNumberingRenderPolicyTableRenderPolicyDocxRenderPolicyMultiSeriesChartTemplateRenderPolicySingleSeriesChartTemplateRenderPolicyDefaultPictureTemplateRenderPolicy 
由于这 8 个插件是经常用到的所以这些插件被注册为不同的标签类型也就是我们看到过的 {{var}}、{{var}}、{{#var}} 等不同类型的标签从而搭建了 poi-tl 的标签体系。 
除了这 8 个通用的策略插件外还内置了一些额外用途的插件 
DynamicTableRenderPolicy动态表格插件允许直接操作表格对象示例-动态表格HackLoopTableRenderPolicy循环表格行下文会详细介绍示例-表格行循环LoopColumnTableRenderPolicy循环表格列示例-表格列循环BookmarkRenderPolicy书签和锚点示例-Swagger文档JSONRenderPolicy高亮显示JSON代码块示例-Swagger文档AbstractChartTemplateRenderPolicy引用图表插件允许直接操作图表对象ParagraphRenderPolicy渲染一个段落可以包含不同样式文本图片等DocumentRenderPolicy渲染多个段落和表格TOCRenderPolicyBeta实验功能目录打开文档时需要更新域 
使用插件 
为了让插件在某个标签处执行我们需要将插件与标签绑定。 
当我们有个模板标签为 {{description}}默认是文本标签如果希望在这个位置做些不一样或者更复杂的事情我们可以将插件应用到这个模板标签比如渲染 HTML 
ConfigureBuilder builder  Configure.builder();
builder.bind(description, new HtmlRenderPolicy());此时{{description}} 将不再是一个文本标签而是一个自定义的支持 HTML 渲染的标签。 
当然这里的 HTML 渲染的插件默认是没有提供的需要引入以下的依赖项才能支持 HTML 的渲染。 
!-- 支持渲染 HTML 的插件 --
dependencygroupIdio.github.draco1023/groupIdartifactIdpoi-tl-ext/artifactIdversion0.3.3/version
/dependency示例我们对 {{author}} 这个标签绑定上支持 HTML 渲染的插件这样就能渲染 HTML 的文本了。 
SpringBootTest
public class PoiTlApplicationTest {Testpublic 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 HashMapString, Object(){{put(title, Hello, poi-tl Word模板引擎);put(text, Hello World);put(author, h2god23bin/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 ListArticle articles;/*** 专栏明细数据模型*/private ListSpecialColumn 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
}进行测试获取数据和模板让标签和表格行循环的插件进行绑定 Testpublic 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, MapString, 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, MapString, 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();}}
} 
最后的最后 
希望各位屏幕前的靓仔靓女们给个三连你轻轻地点了个赞那将在我的心里世界增添一颗明亮而耀眼的星 
咱们下期再见