根据模板动态生成word(三)使用poi-tl生成word

poi-tl是一个Java库,用于基于Word模板生成文档,它支持文本、图片、表格和列表等标签替换,提供友好的API。相比其他模板引擎,poi-tl具有更好的样式保留和易用性。通过配置标签前缀,可以方便地填充数据并输出到文件。文章详细介绍了poi-tl的使用配置、模板标签替换和填充方法。
摘要由CSDN通过智能技术生成

文章目录

  • 一、前言
    • 1、什么是poi-tl
    • 2、官方信息
      • 2.1 源码仓库
      • 2.2 中文文档
      • 2.3 开源协议
    • 3、poi-tl的优势
      • 3.1 poi-tl和其他模板引擎的对比
      • 3.2 poi-tl Word模板引擎支持的功能
  • 二、基本的使用配置
  • 1、引入依赖
      • 1.1 Maven
      • 1.2 Gradle
    • 2、配置
      • 2.1 新建配置
    • 2.2 标签前后缀替换
      • 2.3 加载模板
      • 2.4 填充数据
      • 2.5 输出文件
  • 三、各类模板标签替换和填充
    • 1 文本
      • 1.1 文本的标签如下
      • 1.2 支持数据类型
      • 1.3 文本数据填充方式如下
    • 2 图片
      • 2.1 图片的标签如下:
      • 2.2 支持数据类型
      • 2.3 图片数据填充方式如下
    • 3 表格
      • 3.1 表格的标签如下:
      • 3.2 支持数据类型
      • 3.3 表格数据填充方式如下
    • 4、列表
      • 4.1 列表的标签如下:
      • 4.2 支持数据类型
      • 4.3 列表数据填充方式如下
  • 四、验证
    • 1、准备模板
    • 2、准备测试代码
    • 3、生成效果

一、前言

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

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、生成效果

请添加图片描述

  • 11
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知北游z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值