@

目录

一、前言

1、什么是poi-tl

poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库。同类型的FreeMarker或Velocity基于文本模板和数据生成新的html页面或配置文件。而poi tl是一个基于Word模板和数据生成新文档的Word模板引擎。

Word模板具有丰富的样式。Poi-tl将在生成的文档中完美地保留模板中的样式。也可以设置标记的样式。标记的样式将应用于替换的文本,因此您可以专注于模板设计。

poi-tl是一个“无逻辑”模板引擎。没有复杂的控制结构和变量分配,只有标签,有些标签可以用文本、图片、表格等代替,有些标签会隐藏某些文档内容,而另一些标签会循环一系列文档内容。

像变量赋值或条件语句这样的“强大”构造可以很容易地在模板系统中专门修改应用程序的外观。。。然而,以分离为代价,将模板本身变成应用程序逻辑的一部分。

poi-tl支持自定义函数(插件),函数可以在Word模板的任何地方执行,在文档的任何地方做任何事情都是poi-tl的目标。

2、官方信息

2.1 源码仓库

GitHub - Sayi/poi-tl: Generate awesome word(docx) with template

2.2 中文文档

Poi-tl Documentation (deepoove.com)

2.3 开源协议

Apache License 2.0

3、poi-tl的优势

3.1 poi-tl和其他模板引擎的对比

下面表格是官方文档中提供的与其他模板引擎的对比

方案 移植性 功能性 易用性
Poi-tl Java跨平台 Word模板引擎,基于Apache POI,提供更友好的API 低代码,准备文档模板和数据即可
Apache POI Java跨平台 Apache项目,封装了常见的文档操作,也可以操作底层XML结构 文档不全,这里有一个教程:Apache POI Word快速入门
Freemarker XML跨平台 仅支持文本,很大的局限性 不推荐,XML结构的代码几乎无法维护
OpenOffice 部署OpenOffice,移植性较差 - 需要了解OpenOffice的API
HTML浏览器导出 依赖浏览器的实现,移植性较差 HTML不能很好的兼容Word的格式,样式糟糕 -
Jacob、winlib Windows平台 - 复杂,完全不推荐使用

3.2 poi-tl Word模板引擎支持的功能

Word模板引擎功能 描述
文本 将标签渲染为文本
图片 将标签渲染为图片
表格 将标签渲染为表格
列表 将标签渲染为列表
图表 条形图(3D条形图)、柱形图(3D柱形图)、面积图(3D面积图)、折线图(3D折线图)、雷达图、饼图(3D饼图)、散点图等图表渲染
If Condition判断 根据条件隐藏或者显示某些文档内容(包括文本、段落、图片、表格、列表、图表等)
Foreach Loop循环 根据集合循环某些文档内容(包括文本、段落、图片、表格、列表、图表等)
Loop表格行 循环复制渲染表格的某一行
Loop表格列 循环复制渲染表格的某一列
Loop有序列表 支持有序列表的循环,同时支持多级列表
Highlight代码高亮 word中代码块高亮展示,支持26种语言和上百种着色样式
Markdown 将Markdown渲染为word文档
Word批注 完整的批注功能,创建批注、修改批注等
Word附件 Word中插入附件
SDT内容控件 内容控件内标签支持
Textbox文本框 文本框内标签支持
图片替换 将原有图片替换成另一张图片
书签、锚点、超链接 支持设置书签,文档内锚点和超链接功能
Expression Language 完全支持SpringEL表达式,可以扩展更多的表达式:OGNL, MVEL…
样式 模板即样式,同时代码也可以设置样式
模板嵌套 模板包含子模板,子模板再包含子模板
合并 Word合并Merge,也可以在指定位置进行合并
用户自定义函数(插件) 插件化设计,在文档任何位置执行函数

二、基本的使用配置

1、引入依赖

1.1 Maven

<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.1</version>
</dependency>

1.2 Gradle

implementation 'com.deepoove:poi-tl:1.12.1'

2、配置

2.1 新建配置

ConfigureBuilder builder = Configure.builder();

2.2 标签前后缀替换

poi-tl所有的标签都是以{{开头,以}}结尾,这是为了致敬Google CTemplate。标签可以出现在任何位置,包括页眉,页脚,表格内部,文本框等,表格布局可以设计出很多优秀专业的文档,推荐使用表格布局。

当然如果你更偏爱freemarker ${} 的方式,也可以添加如下配置修改标签的前后缀配置:

builder.buildGramer("${", "}");

2.3 加载模板

XWPFTemplate template = XWPFTemplate.compile("template.docx", builder.buid());

poi-tl加载使用XWPFTemplate.compile方法来加载模板,支持模板以绝对路径(String),File、InputStream、XWPFDocument四种格式传入。

2.4 填充数据

poi-tl数据类似于哈希或者字典,可以是Map结构(key是标签名称):

Map<String, Object> data = new HashMap<>();
data.put("name", "Sayi");
data.put("start_time", "2019-08-04");
template.render(dataMap);

2.5 输出文件

poi-tl以流的方式进行输出:

template.write(OutputStream stream);

可以写到任意输出流中,比如文件流:

template.write(new FileOutputStream("output.docx"));

如网络流:

response.setContentType("application/octet-stream");
response.setHeader("Content-disposition","attachment;filename=\""+"out_template.docx"+"\""); // HttpServletResponse response
OutputStream out = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(out);
template.write(bos);
bos.flush();
out.flush();
PoitlIOUtils.closeQuietlyMulti(template, bos, out);

三、各类模板标签替换和填充

1 文本

1.1 文本的标签如下

{{var}}

1.2 支持数据类型

  • String :文本

  • TextRenderData :有样式的文本

  • HyperlinkTextRenderData :超链接和锚点文本

  • Object :调用 toString() 方法转化为文本

1.3 文本数据填充方式如下

代码示例

put("name", "Sayi");
put("author", new TextRenderData("000000", "Sayi"));
put("link", new HyperlinkTextRenderData("website", "http://deepoove.com"));
put("anchor", new HyperlinkTextRenderData("anchortxt", "anchor:appendix1"));

除了new操作符,还提供了更加优雅的工厂 Texts 和链式调用的方式轻松构建文本模型。

链式代码示例

put("author", Texts.of("Sayi").color("000000").create());
put("link", Texts.of("website").link("http://deepoove.com").create());
put("anchor", Texts.of("anchortxt").anchor("appendix1").create());

2 图片

2.1 图片的标签如下:

图片标签以@开始:{{@var}}

2.2 支持数据类型

  • String :图片url或者本地路径,默认使用图片自身尺寸

  • PictureRenderData

  • ByteArrayPictureRenderData

  • FilePictureRenderData

  • UrlPictureRenderData

2.3 图片数据填充方式如下

// 指定图片路径
put("image", "logo.png");
// svg图片
put("svg", "https://img.shields.io/badge/jdk-1.6%2B-orange.svg"); // 设置图片宽高
put("image1", Pictures.ofLocal("logo.png").size(120, 120).create()); // 图片流
put("streamImg", Pictures.ofStream(new FileInputStream("logo.jpeg"), PictureType.JPEG)
.size(100, 120).create()); // 网络图片(注意网络耗时对系统可能的性能影响)
put("urlImg", Pictures.ofUrl("http://deepoove.com/images/icecream.png")
.size(100, 100).create()); // java图片
put("buffered", Pictures.ofBufferedImage(bufferImage, PictureType.PNG)
.size(100, 100).create());

3 表格

3.1 表格的标签如下:

表格标签以#开始:{{#var}}

3.2 支持数据类型

  • TableRenderData

3.3 表格数据填充方式如下

  1. 基础表格示例
// 一个2行2列的表格
put("table0", Tables.of(new String[][] {
new String[] { "00", "01" },
new String[] { "10", "11" }
}).border(BorderStyle.DEFAULT).create());
  1. 表格样式示例
// 第0行居中且背景为蓝色的表格
RowRenderData row0 = Rows.of("姓名", "学历").textColor("FFFFFF")
.bgColor("4472C4").center().create();
RowRenderData row1 = Rows.create("李四", "博士");
put("table1", Tables.create(row0, row1));
  1. 表格合并示例
// 合并第1行所有单元格的表格
RowRenderData row0 = Rows.of("列0", "列1", "列2").center().bgColor("4472C4").create();
RowRenderData row1 = Rows.create("没有数据", null, null);
MergeCellRule rule = MergeCellRule.builder().map(Grid.of(1, 0), Grid.of(1, 2)).build();
put("table3", Tables.of(row0, row1).mergeRule(rule).create());

4、列表

4.1 列表的标签如下:

列表标签以*开始:{{*var}}

4.2 支持数据类型

  • List<String>
  • NumberingRenderData

4.3 列表数据填充方式如下

put("list", Numberings.create("Plug-in grammar",
"Supports word text, pictures, table...",
"Not just templates"));

四、验证

1、准备模板

首先我们建立一个word文件,在word文件里填充一下内容。

2、准备测试代码

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.data.*;
import dto.Qiankuan;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.*; public class PoitlTest { public static void main(String[] args) throws IOException {
ConfigureBuilder builder = Configure.builder();
//获取模板的文件流
FileInputStream fileInputStream = new FileInputStream("D:\\文章\\word生成\\poi-tl\\qiantiao.docx"); HashMap<String, Object> dataMap = new HashMap<>();
//添加文本
LocalDate currentDate = LocalDate.now();
LocalDate endDate = currentDate.plusYears(1L);
dataMap.put("debtor", "陈有楚");
dataMap.put("nowYear", String.valueOf(currentDate.getYear()));
dataMap.put("nowMonth", String.valueOf(currentDate.getMonthValue()));
dataMap.put("nowDay", String.valueOf(currentDate.getDayOfMonth()));
//验证换行的情况
dataMap.put("arrears", "\n一顿老魏,\n贵州大黄牛,\nv我50");
dataMap.put("endYear", String.valueOf(endDate.getYear()));
dataMap.put("endMonth", String.valueOf(endDate.getMonthValue()));
dataMap.put("endDay", String.valueOf(endDate.getDayOfMonth()));
//添加列表
List<String> list = Arrays.asList("阿大", "阿二", "阿三");
Numberings.NumberingBuilder numberingBuilder = Numberings.of(NumberingFormat.DECIMAL);
for (String s : list) {
numberingBuilder.addItem(s);
}
dataMap.put("witness", numberingBuilder.create());
//添加图片,考虑到实际生产环境图片大都都从文件服务获取,所以这里用图片流做例子
PictureRenderData pictureRenderData = Pictures.ofStream(Files.newInputStream(Paths.get("D:\\picture\\其他\\24-05-23-142418.png")), PictureType.JPEG)
.size(300, 220).create();
dataMap.put("image1", pictureRenderData);
List<Qiankuan> qiankuanList = getQiankuanList();
//添加表格
//填充表头,表格的第一行
RowRenderData row0 = Rows.of("拖欠物品", "拖欠次数", "偿还期限").center().bgColor("4472C4").create();
Tables.TableBuilder tableBuilder = Tables.of(row0);
//填充表格内容
for (Qiankuan qiankuan : qiankuanList) {
RowRenderData row = Rows.create(qiankuan.getName(), String.valueOf(qiankuan.getCount()), qiankuan.getQixian());
tableBuilder.addRow(row);
}
//MergeCellRule rule = MergeCellRule.builder().map(MergeCellRule.Grid.of(1, 0), MergeCellRule.Grid.of(1, 2)).build();
//tableBuilder.mergeRule(rule);
dataMap.put("table1", tableBuilder.create()); ChartMultiSeriesRenderData chart = Charts
.ofMultiSeries("ChartTitle", new String[] { "中文", "English" })
.addSeries("countries", new Double[] { 15.0, 6.0 })
.addSeries("speakers", new Double[] { 223.0, 119.0 })
.create(); dataMap.put("barChart", chart);
XWPFTemplate template = XWPFTemplate.compile(fileInputStream, builder.build())
.render(dataMap);
template.writeAndClose(Files.newOutputStream(Paths.get("D:\\test\\qiantiao-poitl.docx")));
System.out.println("success");
} static List<Qiankuan> getQiankuanList() {
List<Qiankuan> list = new ArrayList<>();
Qiankuan q1 = new Qiankuan();
q1.setName("一顿老魏");
q1.setCount(1);
q1.setQixian("三月内");
list.add(q1); Qiankuan q2 = new Qiankuan();
q2.setName("一顿大黄牛");
q2.setCount(1);
q2.setQixian("半年内");
list.add(q2); Qiankuan q3 = new Qiankuan();
q3.setName("特一特");
q3.setCount(3);
q3.setQixian("一周内");
list.add(q3); Qiankuan q4 = new Qiankuan();
q4.setName("v我50");
q4.setCount(5);
q4.setQixian("一周内");
list.add(q4);
return list;
} }

3、生成效果

根据模板动态生成word(三)使用poi-tl生成word的更多相关文章

  1. 【POI word】使用POI实现对Word的读取以及生成

    项目结构如下: 那第一部分:先是读取Word文档 package com.it.WordTest; import java.io.FileInputStream; import java.io.Fil ...

  2. Freemaker基于word模板动态导出压缩文件汇总整理

    Freemaker基于word模板动态导出压缩文件汇总整理 Freemaker基于word模板动态导出单个文件思路和代码详情见连接: https://www.cnblogs.com/lsy-blogs ...

  3. C# 处理Word自动生成报告 三、设计模板

    C# 处理Word自动生成报告 一.概述 C# 处理Word自动生成报告 二.数据源例子 C# 处理Word自动生成报告 三.设计模板 C# 处理Word自动生成报告 四.程序处理 既然是模板就少不了 ...

  4. Freemaker基于word模板动态导出汇总整理

    Freemaker基于word模板动态导出汇总整理 一.使用的jar包: 二.Word模板动态导出的基本思路: 1.首先通过自己在word中创建好需要导出的word文本+表格的模板,模板中需要填写内容 ...

  5. C#读取Word模板替换相应的字符串(标签)生成新的Word

    在平常工作中,生成word的方式主要是C#读取html的模板文件处理之后保存为.doc文件,这样的好处是方便,快捷,能满足大部分的需求.不过有些特殊的需求并不能满足,如要生成的Word为一个表格,只是 ...

  6. 利用html模板生成Word文件(服务器端不需要安装Word)

    利用html模板生成Word文件(服务器端不需要安装Word) 由于管理的原因,不能在服务器上安装Office相关组件,所以只能采用客户端读取Html模板,后台对模板中标记的字段数据替换并返回给客户端 ...

  7. 使用T4模板动态生成NPoco实体类

    这是一个妥妥的NPoco类,这是我们在工作开发中,手动去写这个实体类,属实非常心累,字段少无所谓一次两次,数量多了,字段多了,就心态裂开

  8. 三种C#.net生成静态页面的方法

    ASP.NET生成静态页面方法主要有三种   第一种方法:向服务器的动态页面发送请求,获取页面的html代码.这种方法缺点显而易见:速度慢.另外如果请求的动态页面有验证控件的话,返回的html页面却无 ...

  9. ASP.NET实现二维码 ASP.Net上传文件 SQL基础语法 C# 动态创建数据库三(MySQL) Net Core 实现谷歌翻译ApI 免费版 C#发布和调试WebService ajax调用WebService实现数据库操作 C# 实体类转json数据过滤掉字段为null的字段

    ASP.NET实现二维码 using System;using System.Collections.Generic;using System.Drawing;using System.Linq;us ...

  10. WIN 下的超动态菜单(三)代码

    WIN 下的超动态菜单(一)简介 WIN 下的超动态菜单(二)用法 WIN 下的超动态菜单(三)代码 作者:黄山松,发表于博客园:http://www.cnblogs.com/tomview/ 超动态 ...

随机推荐

  1. Java 开源项目整合

    在JAVA学习过程中,学习到的简单项目,在这里记录下. SSM框架的整合 使用到的框架:SpringMVC + Spring + MyBatis 地址:https://github.com/liyif ...

  2. OI 数论中的上界估计与时间复杂度证明

    预备 0.1 渐进符号 其实不少高等数学 / 数学分析教材在讲解无穷小的比较时已经相当严谨地介绍过大 O.小 O 记号,然而各种历史习惯记法的符号滥用(abuse of notation)[1] 直到 ...

  3. 【kafka】-分区-消费端负载均衡

    一.为什么kafka要做分区? 因为当一台机器有可能扛不住(类比:就像redis集群中的redis-cluster一样,一个master抗不住写,那么就多个master去抗写),把一个队列的单一mas ...

  4. 高阶函数_函数柯里化 以及 setState中动态key

     使用柯里化: 1 state = { 2 username: "", 3 password: "", 4 }; 5 render() { 6 return ( ...

  5. C# 组合键判断

    e.KeyboardDevice.Modifiers 同时按下了Ctrl + H键(H要最后按,因为判断了此次事件的e.Key)修饰键只能按下Ctrl,如果还同时按下了其他修饰键,则不会进入 1 pr ...

  6. 【必知必会的MySQL知识】③DML语言

    目录 前言 准备 插入数据 语法格式 插入完整行数据 插入多行数据 将检索出来的数据插入表 更新数据 准备两张表 语法 实践操作 删除数据 语法 实践操作 小结 前言 前面的两篇文章中,我们已经对My ...

  7. 百度飞桨(PaddlePaddle)-数字识别

    手写数字识别任务 用于对 0 ~ 9 的十类数字进行分类,即输入手写数字的图片,可识别出这个图片中的数字. 使用 pip 工具安装 matplotlib 和 numpy python -m pip i ...

  8. 2022-09-21:有n个动物重量分别是a1、a2、a3.....an, 这群动物一起玩叠罗汉游戏, 规定从左往右选择动物,每只动物左边动物的总重量不能超过自己的重量 返回最多能选多少个动物,求一个

    2022-09-21:有n个动物重量分别是a1.a2.a3-an, 这群动物一起玩叠罗汉游戏, 规定从左往右选择动物,每只动物左边动物的总重量不能超过自己的重量 返回最多能选多少个动物,求一个高效的算 ...

  9. 函数strncpy和memcpy的区别

    1定义 1.1 memcpy void *memcpy(void *destin, void *source, unsigned n); 参数 *destin ---- 需要粘贴的新数据(地址) *s ...

  10. 【C#代码整洁之道】读后习题

    1)劣质的代码会带来什么后果? GPT回答: 可维护性降低:代码过于复杂.难以理解.难以修改,导致维护成本增加,代码质量更加恶化. 可靠性降低:错误容易发生,很难找到并修复,因为代码模糊.逻辑混乱,并 ...