文章目录
- [一、poi-tl 核心优势](#一、poi-tl 核心优势)
- 二、环境搭建
-
- [2.1 前置要求](#2.1 前置要求)
- [2.2 依赖配置](#2.2 依赖配置)
-
- [Maven 依赖](#Maven 依赖)
- [Gradle 依赖](#Gradle 依赖)
- 三、快速入门(2分钟上手)
-
- [3.1 步骤1:创建 Word 模板](#3.1 步骤1:创建 Word 模板)
- [3.2 步骤2:编写 Java 代码](#3.2 步骤2:编写 Java 代码)
- [3.3 步骤3:渲染结果(纯文本展示)](#3.3 步骤3:渲染结果(纯文本展示))
- 四、核心功能实战
-
- [4.1 文本渲染(含样式、超链接)](#4.1 文本渲染(含样式、超链接))
- [4.2 图片渲染](#4.2 图片渲染)
- [4.3 表格渲染](#4.3 表格渲染)
-
- 模板内容
- 代码实现
- 渲染结果(纯文本展示)
-
- [1. 基础表格](#1. 基础表格)
- [2. 带样式表格](#2. 带样式表格)
- [3. 合并单元格表格](#3. 合并单元格表格)
- [4.4 循环与条件判断(区块对)](#4.4 循环与条件判断(区块对))
- [4.5 图表渲染](#4.5 图表渲染)
-
- 模板制作
- 代码实现
- 渲染结果(纯文本描述)
-
- [1. 饼图](#1. 饼图)
- [2. 柱形图](#2. 柱形图)
- 五、高级功能:插件使用
-
- [5.1 代码高亮插件](#5.1 代码高亮插件)
- 六、常见配置与问题解决
-
- [6.1 标签格式自定义](#6.1 标签格式自定义)
- [6.2 Spring 表达式支持](#6.2 Spring 表达式支持)
- [6.3 常见问题](#6.3 常见问题)
- [七、Word 转 PDF](#七、Word 转 PDF)
-
- [Maven 依赖](#Maven 依赖)
- 工具方法
- 八、总结
在日常开发中,经常需要动态生成 Word 文档(如报表、合同、简历等),而 Apache POI 直接操作 Word 繁琐且易出错。poi-tl(POI Template Language)作为基于 Apache POI 的 Word 模板引擎,以「低代码、高灵活」的特性解决了这一痛点,支持文本、图片、表格、图表等多种元素的动态渲染,真正实现「模板 + 数据 = 输出」的极简开发模式。本文将从环境搭建到高级功能,结合实战 Demo 带你全面掌握 poi-tl 的使用。
一、poi-tl 核心优势
相比其他 Word 生成方案,poi-tl 具有明显优势:
-
「跨平台」:基于 Java 开发,支持 Windows、Linux 等所有 Java 兼容环境
-
「功能全面」:支持文本、图片、表格、列表、图表、循环、条件判断等几乎所有 Word 操作
-
「易用性强」:低代码设计,只需准备模板和数据,无需关注底层 XML 结构
-
「样式保留」:遵循「所见即所得」,模板中的格式样式会完全保留到输出文档
-
「插件扩展」:支持自定义插件,可实现代码高亮、Markdown 渲染等高级功能
二、环境搭建
2.1 前置要求
-
JDK 1.8+
-
Apache POI 5.2.2+(poi-tl 已内置依赖,无需额外引入)
2.2 依赖配置
Maven 依赖
xml
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.2</version>
</dependency>
Gradle 依赖
groovy
implementation 'com.deepoove:poi-tl:1.12.2'
三、快速入门(2分钟上手)
poi-tl 遵循 TDO 模式(Template + Data-model = Output),核心步骤仅3步:创建模板 → 准备数据 → 渲染输出。
3.1 步骤1:创建 Word 模板
新建 template.docx 文件,在需要动态替换的位置插入标签(默认标签格式 {``{变量名}}):
plain
文档标题:{{title}}
作者:{{author}}
创建时间:{{createTime}}
3.2 步骤2:编写 Java 代码
java
import com.deepoove.poi.XWPFTemplate;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
public class QuickStartDemo {
public static void main(String[] args) throws Exception {
// 1. 准备数据(Map 结构,key 对应模板标签名)
Map<String, Object> data = new HashMap<>();
data.put("title", "poi-tl 快速入门教程");
data.put("author", "技术学习者");
data.put("createTime", "2026-03-25");
// 2. 编译模板 + 渲染数据
XWPFTemplate template = XWPFTemplate.compile("template.docx")
.render(data);
// 3. 输出文件
template.writeAndClose(new FileOutputStream("output.docx"));
System.out.println("Word 文档生成成功!");
}
}
3.3 步骤3:渲染结果(纯文本展示)
生成的 output.docx 文档内容如下:
plain
文档标题:poi-tl 快速入门教程
作者:技术学习者
创建时间:2026-03-25
四、核心功能实战
4.1 文本渲染(含样式、超链接)
文本标签支持普通文本、带样式文本、超链接、锚点等多种形式,推荐使用 Texts 工厂类构建。
模板内容
plain
普通文本:{{name}}
带样式文本:{{styledText}}
超链接:{{link}}
锚点(跳转到附录1):{{anchor}}
代码实现
java
import com.deepoove.poi.data.Texts;
import com.deepoove.poi.data.HyperlinkTextRenderData;
// 数据准备
Map<String, Object> data = new HashMap<>();
// 普通文本
data.put("name", "poi-tl");
// 带样式文本(绿色、粗体、14号字)
data.put("styledText", Texts.of("带样式的文本")
.color("00FF00")
.bold(true)
.fontSize(14)
.create());
// 超链接
data.put("link", Texts.of("访问官网")
.link("https://deepoove.com/poi-tl/")
.create());
// 锚点
data.put("anchor", Texts.of("跳转到附录")
.anchor("appendix1")
.create());
渲染结果(纯文本展示)
plain
普通文本:poi-tl
带样式文本:带样式的文本(绿色、粗体、14号字)
超链接:访问官网(可点击跳转到 https://deepoove.com/poi-tl/)
锚点(跳转到附录1):跳转到附录(可点击跳转到文档中"附录1"锚点位置)
4.2 图片渲染
图片标签格式为 {``{@变量名}},支持本地图片、网络图片、图片流等多种来源,使用 Pictures 工厂类配置尺寸。
模板内容
plain
本地图片:{{@localImg}}
网络图片:{{@urlImg}}
SVG图片:{{@svgImg}}
代码实现
java
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.data.PictureType;
import java.io.FileInputStream;
// 数据准备
Map<String, Object> data = new HashMap<>();
// 本地图片(指定尺寸:宽150px,高100px)
data.put("localImg", Pictures.ofLocal("logo.png")
.size(150, 100)
.create());
// 网络图片
data.put("urlImg", Pictures.ofUrl("https://deepoove.com/images/icecream.png")
.size(120, 120)
.create());
// SVG图片
data.put("svgImg", Pictures.ofUrl("https://img.shields.io/badge/jdk-1.8%2B-orange.svg")
.create());
渲染结果(纯文本描述)
plain
本地图片:[显示本地 logo.png 图片,尺寸 150px × 100px,保持图片原有清晰度]
网络图片:[显示网络图片(https://deepoove.com/images/icecream.png),尺寸 120px × 120px]
SVG图片:[显示SVG格式图片(jdk 1.8+ 标识),自适应尺寸,清晰度无损耗]
4.3 表格渲染
表格标签格式为 {``{#变量名}},支持基础表格、带样式表格、单元格合并等功能,使用 Tables、Rows、Cells 工厂类构建。
模板内容
plain
基础表格:{{#basicTable}}
带样式表格:{{#styledTable}}
合并单元格表格:{{#mergeTable}}
代码实现
java
import com.deepoove.poi.data.Tables;
import com.deepoove.poi.data.Rows;
import com.deepoove.poi.data.MergeCellRule;
import com.deepoove.poi.data.Grid;
// 数据准备
Map<String, Object> data = new HashMap<>();
// 1. 基础表格(2行2列)
data.put("basicTable", Tables.of(new String[][]{
new String[]{"姓名", "年龄"},
new String[]{"张三", "25"}
}).border(BorderStyle.DEFAULT).create());
// 2. 带样式表格(表头蓝色背景、白色文字)
data.put("styledTable", Tables.create(
Rows.of("产品", "价格").textColor("FFFFFF")
.bgColor("4472C4").center().create(),
Rows.create("手机", "5999"),
Rows.create("电脑", "8999")
));
// 3. 合并单元格表格(合并第2行第1-3列)
MergeCellRule mergeRule = MergeCellRule.builder()
.map(Grid.of(1, 0), Grid.of(1, 2)) // 行1列0 到 行1列2 合并(索引从0开始)
.build();
data.put("mergeTable", Tables.of(
Rows.of("序号", "产品", "库存").center().bgColor("4472C4").create(),
Rows.create("无数据", null, null)
).mergeRule(mergeRule).create());
渲染结果(纯文本展示)
1. 基础表格
plain
---------------------
| 姓名 | 年龄 |
---------------------
| 张三 | 25 |
---------------------
(表格带默认边框,单元格内容左对齐)
2. 带样式表格
plain
-----------------------------------
| 产品 | 价格 |
-----------------------------------
| 手机 | 5999 |
-----------------------------------
| 电脑 | 8999 |
-----------------------------------
(表头:蓝色背景、白色文字、居中对齐;表格带默认边框)
3. 合并单元格表格
plain
-----------------------------------
| 序号 | 产品 | 库存 |
-----------------------------------
| 无数据 |
-----------------------------------
(表头:蓝色背景、居中对齐;第二行"无数据"跨3列合并,表格带默认边框)
4.4 循环与条件判断(区块对)
区块对标签格式为 {``{?变量名}}(开始)和 {``{/变量名}}(结束),支持循环渲染和条件显示,是动态生成列表、批量数据的核心功能。
模板内容
plain
### 产品列表
{{?products}}
{{_index + 1}}. 产品名称:{{name}},价格:{{price}}元
{{/products}}
### 特殊说明
{{?hasSpecialNote}}
⚠️ 本批次产品支持7天无理由退换
{{/hasSpecialNote}}
代码实现
java
import java.util.ArrayList;
import java.util.List;
// 定义产品类
class Product {
private String name;
private double price;
// 构造方法、getter/setter
public Product(String name, double price) {
this.name = name;
this.price = price;
}
// getter/setter 省略(实际开发中需补充)
}
// 数据准备
Map<String, Object> data = new HashMap<>();
// 循环数据(产品列表)
List<Product> products = new ArrayList<>();
products.add(new Product("智能手机", 5999.0));
products.add(new Product("平板电脑", 3299.0));
products.add(new Product("无线耳机", 899.0));
data.put("products", products);
// 条件判断(是否显示特殊说明)
data.put("hasSpecialNote", true);
渲染结果(纯文本展示)
plain
### 产品列表
1. 产品名称:智能手机,价格:5999.0元
2. 产品名称:平板电脑,价格:3299.0元
3. 产品名称:无线耳机,价格:899.0元
### 特殊说明
⚠️ 本批次产品支持7天无理由退换
4.5 图表渲染
支持条形图、柱形图、饼图、折线图等多种图表,使用 Charts 工厂类构建,标签通过「可选文字」设置。
模板制作
-
在 Word 中插入图表(如饼图、柱形图)
-
右键图表 → 图表区格式 → 可选文字 → 输入标签名(如
{``{pieChart}}、{``{barChart}})
代码实现
java
import com.deepoove.poi.data.Charts;
import com.deepoove.poi.data.ChartSingleSeriesRenderData;
import com.deepoove.poi.data.ChartMultiSeriesRenderData;
// 数据准备
Map<String, Object> data = new HashMap<>();
// 饼图(单系列图表)
ChartSingleSeriesRenderData pieChart = Charts
.ofSingleSeries("产品销量占比", new String[]{"手机", "平板", "耳机"})
.series("销量", new Integer[]{5000, 3000, 4500})
.create();
data.put("pieChart", pieChart);
// 柱形图(多系列图表)
ChartMultiSeriesRenderData barChart = Charts
.ofMultiSeries("季度销量对比", new String[]{"Q1", "Q2", "Q3", "Q4"})
.addSeries("手机", new Double[]{4500.0, 5200.0, 4800.0, 6000.0})
.addSeries("平板", new Double[]{2800.0, 3100.0, 2900.0, 3500.0})
.create();
data.put("barChart", barChart);
渲染结果(纯文本描述)
1. 饼图
plain
图表标题:产品销量占比
图表类型:饼图
数据展示:
- 手机:5000(占比约 38.5%)
- 平板:3000(占比约 23.1%)
- 耳机:4500(占比约 38.4%)
(饼图各扇区对应不同颜色,鼠标悬浮可显示具体数值和占比)
2. 柱形图
plain
图表标题:季度销量对比
图表类型:柱形图(分组柱形)
X轴:Q1、Q2、Q3、Q4(季度)
Y轴:销量
数据展示:
- 手机系列:Q1(4500)、Q2(5200)、Q3(4800)、Q4(6000)
- 平板系列:Q1(2800)、Q2(3100)、Q3(2900)、Q4(3500)
(不同产品系列用不同颜色柱形区分,清晰展示季度销量差异)
五、高级功能:插件使用
poi-tl 支持插件扩展,内置代码高亮、Markdown 渲染、批注、附件插入等实用插件,以下以代码高亮为例。
5.1 代码高亮插件
步骤1:引入依赖
xml
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl-plugin-highlight</artifactId>
<version>1.0.0</version>
</dependency>
步骤2:模板内容
plain
### Java 代码示例
{{code}}
步骤3:代码实现
java
import com.deepoove.poi.data.HighlightRenderData;
import com.deepoove.poi.plugin.highlight.HighlightRenderPolicy;
import com.deepoove.poi.plugin.highlight.HighlightStyle;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
public class HighlightDemo {
public static void main(String[] args) throws Exception {
// 数据准备
Map<String, Object> data = new HashMap<>();
// 代码高亮数据(Java语言,zenburn主题,显示行号)
HighlightRenderData codeData = new HighlightRenderData();
codeData.setCode("public class Demo {\n" +
" public static void main(String[] args) {\n" +
" System.out.println(\"Hello poi-tl!\");\n" +
" }\n" +
"}");
codeData.setLanguage("java");
codeData.setStyle(HighlightStyle.builder()
.withShowLine(true) // 显示行号
.withTheme("zenburn") // 主题(可更换为monokai、github等)
.build());
data.put("code", codeData);
// 配置插件(绑定标签和渲染策略)
Configure config = Configure.builder()
.bind("code", new HighlightRenderPolicy())
.build();
// 渲染模板
XWPFTemplate template = XWPFTemplate.compile("template.docx", config)
.render(data);
template.writeAndClose(new FileOutputStream("output.docx"));
System.out.println("带代码高亮的Word文档生成成功!");
}
}
渲染结果(纯文本描述)
plain
### Java 代码示例
1 public class Demo {
2 public static void main(String[] args) {
3 System.out.println("Hello poi-tl!");
4 }
5 }
(效果说明:代码按Java语法高亮,关键字(public、class、static等)显示对应主题颜色,注释、字符串颜色区分;左侧显示行号;背景为zenburn主题底色,代码可读性强,与IDE中代码显示效果一致)
六、常见配置与问题解决
6.1 标签格式自定义
默认标签格式为{``{变量名}},可自定义为 #{变量名} 或 ${变量名}:
java
// 自定义标签格式为 ${变量名}
Configure config = Configure.builder()
.buildGramer("${", "}")
.build();
6.2 Spring 表达式支持
引入 Spring EL 依赖后,可在标签中使用复杂表达式(如方法调用、三目运算):
xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.18</version>
</dependency>
java
// 启用 Spring EL
Configure config = Configure.builder()
.useSpringEL()
.build();
模板中使用示例:
plain
{{name.toUpperCase()}} <!-- 转大写 -->
{{price > 5000 ? '高端产品' : '中端产品'}} <!-- 三目运算 -->
{{new java.text.SimpleDateFormat('yyyy-MM-dd').format(createTime)}} <!-- 时间格式化 -->
6.3 常见问题
-
NoSuchMethodError 异常:poi-tl 依赖 Apache POI 5.2.2+,若项目中存在低版本 POI,需升级或排除冲突依赖。
-
图片无法显示:检查图片路径是否正确,网络图片需确保网络通畅,建议使用本地图片测试;若图片格式不支持(如webp),需转换为jpg、png格式。
-
表格样式错乱:表格最大宽度为 A4 纸有效宽度(14.63cm),避免设置过宽的表格;复杂表格建议拆分或调整列宽。
-
图表渲染失败:确保模板中图表的「可选文字」与代码中数据的key一致;若使用Office 2007以下版本,需保存为docx格式。
七、Word 转 PDF
Maven 依赖
xml
<!-- word 转 pdf -->
<dependency>
<groupId>com.documents4j</groupId>
<artifactId>documents4j-local</artifactId>
<version>1.1.13</version>
</dependency>
<dependency>
<groupId>com.documents4j</groupId>
<artifactId>documents4j-transformer-msoffice-word</artifactId>
<version>1.1.13</version>
</dependency>
工具方法
java
/**
* 将 word 文件转成 pdf 文件
* @param wordPath word 文件路径
* @param pdfPath pdf 输出路径
* @throws IOException
*/
public static void wordConvertPdf(String wordPath, String pdfPath) throws IOException {
InputStream wordInputStream = Files.newInputStream(Paths.get(wordPath));
// 转成 pdf
OutputStream outputStream = Files.newOutputStream(Paths.get(pdfPath));
IConverter converter = LocalConverter.builder().build();
converter.convert(wordInputStream).as(DocumentType.DOCX).to(outputStream).as(DocumentType.PDF).execute();
converter.shutDown();
}
八、总结
poi-tl 以「模板驱动」的设计大幅降低了 Java 生成 Word 文档的复杂度,从简单的文本替换到复杂的循环、图表、插件扩展,几乎能满足所有动态文档生成需求。核心要点:
-
遵循 TDO 模式,模板负责样式,数据负责内容,分离清晰,便于维护。
-
标签是核心,不同类型元素对应不同标签格式(文本{{}}、图片{{@}}、表格{{#}}、循环{{?}}),记准标签格式即可快速上手。
-
插件扩展了功能边界,可根据需求引入代码高亮、Markdown 等插件,灵活应对复杂场景。
通过本文的学习,你可以快速上手 poi-tl 并应用到实际项目中,如需更复杂的功能(如模板嵌套、动态表格、自定义渲染器),可参考 poi-tl 官方文档 进一步探索。