@

目录

一、前言

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. Django相关配置信息

    Django相关配置信息 1.配置数据库mysql 1.1 setting.py中配置信息 DATABASES = { 'default': { 'ENGINE': 'django.db.backen ...

  2. RabbitMQ详解(上)

    一:MQ的相关概念 MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内容是message 而已,还是一种跨进程的通信机制,用于上下游传递消息.在 ...

  3. rails的接口查询详解

    Retrieving Objects from the Database find "find"是一种常用的数据库查询方法,在Rails中被用于从数据库中查找单个记录.它可以接收一 ...

  4. 在unity中制作live2d参数的AnimationClip[简单随笔]

    假定:已经成功导入模型.相关文档参考:https://github.com/gtf35/live2d_unity_sdk_chinese_document(人力翻译版的Live2d SDK文档) 全部 ...

  5. Python 项目:外星人入侵--第二部分

    外星人入侵 6.驾驶飞船 玩家左右移动飞船,用户按左或右按键时作出响应. 6.1响应按键 当用户在按键时,在python中注册一个事件,事件都是通过方法pygame.event.get()获取的. 在 ...

  6. RocketMQ消费者是如何负载均衡的

    摘要:RocketMQ 支持两种消息模式:集群消费( Clustering )和广播消费( Broadcasting ). 本文分享自华为云社区<一文讲透RocketMQ消费者是如何负载均衡的& ...

  7. Prism Sample 7 Module xaml

    这一节使用xaml标记甚为不解. 本节注册module 的方式同directory一节很类似.在那一节中,用工厂方法创建一模块目录: protected override IModuleCatalog ...

  8. map和multimap

    map相对于set区别,map具有键值和实值,所有元素根据键值自动排序,pair的第一个值被称为键值key,pair的第二个值被称为实值value.map也是以红黑树为底层实现机制,根据key进行排序 ...

  9. 【CSS】画出宽度为1像素的线或边框

    由于多倍的设计图在移动设备上显示时会将设计图进行缩小到视口宽度,而1px的边框没有随着页面进行缩小而导致效果太粗,想要还原设计图1px的显示效果,因此需要一些方法来实现边框宽度小于1px. 实现方法很 ...

  10. .NET Core 波场链离线签名、广播交易(发送 TRX和USDT)笔记

    Get Started NuGet You can run the following command to install the Tron.Wallet.Net in your project. ...