word文件生成 Poi-tl_{{?songs}} {{/songs}} poitl-程序员宅基地

技术标签: java  apache  word  

word文件生成,poi-tl

文章部分内容来自 Poi-tl Documentation (deepoove.com)

word文件生成

生成word文件的方式有很多种,诸如apache-poi,freemaker,我们都知道word文件其实本质就是一个xml格式的文件,所以市面上大部分配置都是xml的或者是html格式的,对于开发者而言维护、学习成本较高,所以有没有一种更加简单,配置对于开发者更友好的方式呢?

现在我给大家推荐一种:POI-TL,poi大家都很熟悉就是apache的poi,用来做office组件是比较通用的做法,今天介绍的poi-tl是一种使用模板和数据就能创建很棒的word文档的方式

Poi-tl

poi-tl(poi template language)是Word模板引擎,使用模板和数据创建很棒的Word文档

方案 移植性 功能性 易用性
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平台 - 复杂,完全不推荐使用
Thymeleaf Java跨平台 使用Html方式的配置导出word,维护麻烦虽然可以在word模板用对应的语法写出后保存为html,但是不能所见即所得 不推荐

这里介绍的POI-TL也是一个免费的开源库,上手简单,维护方便,只需要学习一下他的语法便能正常配置和生成word
在这里插入图片描述

使用入门

该库提供了maven和gradle的方式以1.12.2版本为例子

  • maven

    <dependency>
      <groupId>com.deepoove</groupId>
      <artifactId>poi-tl</artifactId>
      <version>1.12.2</version>
    </dependency>
    
  • gradle

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

引入模板后,其实已经具备导出渲染word模板的能力

   /**
     * 导出模板文件
     */
    public void export(String templateId, String userId) throws Exception {
    
        // 支持InputStream传参
        var template = XWPFTemplate.compile("template.docx");
        template.render(List.of("模拟数据", "模拟数据2"));
        // 可以写入到Byte[]上传到文件存储
        template.write(new FileOutputStream("output.docx"));
    }

这里只用了三步便实现了word文件导出,

  • compile编译模板,也可以使用文件存储对象,传参使用inputStream

  • render 渲染数据,这里的数据结构需要与模板中的配置对应,后面会详细说明

  • write 输出到流,也可以输出到流转为Byte[],上传到文件存储对象

    // 以流的方式进行输出 
    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);
    
Template:模板

模板是Docx格式的Word文档,也可以使用Microsoft office、WPS Office、Pages等任何你喜欢的软件制作模板,也可以使用Apache POI代码来生成模板。

所有模板中的配置的标签都是以{ {开头,以}}结尾,标签可以出现在任何位置,包括页眉,页脚,表格内部,文本框等,表格布局可以设计出很多优秀专业的文档,推荐使用表格布局。

poi-tl模板遵循“所见即所得”的设计,模板和标签的样式会被完全保留。

Data-model:数据

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

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

可以是对象(属性名是标签名称):

public class Data {
    
  private String name;
  private String startTime;
  private Author author;
}

数据可以是树结构,每级之间用点来分隔开,比如{ {author.name}}标签对应的数据是author对象的name属性值。

模板标签

poi-tl是一种无逻辑「logic-less」的模板引擎,没有复杂的控制结构和变量赋值,只有标签。标签由前后两个大括号组成,{ {title}}是标签,{ {?title}}也是标签,title是这个标签的名称,问号标识了标签类型,接下来我们来看看有哪些默认标签类型(用户可以创建新的标签类型,这属于更高级的话题)。

文件标签
{
   {var}}

数据模型:

  • String :文本
  • TextRenderData :有样式的文本
  • HyperlinkTextRenderData :超链接和锚点文本
  • Object :调用 toString() 方法转化为文本

推荐使用工厂 Texts 构建文本模型。

put("name", "Sayi");
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());

所见即所得,标签的样式会应用到替换后的文本上,也可以通过代码设定文本的样式。

{
  "text": "Sayi",
  "style": {
    "strike": false,  //删除线
    "bold": true,  //粗体
    "italic": false, //斜体
    "color": "00FF00", //颜色
    "underLine": false, //下划线
    "fontFamily": "微软雅黑", //字体
    "fontSize": 12, //字号
    "highlightColor": "green", //背景高亮色
    "vertAlign": "superscript", //上标或者下标
    "characterSpacing" : 20 //间距
  }
}
图片
图片标签以@开始 {
   {@var}} :图片只要是一个下载地址即可

数据模型:

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

推荐使用工厂 Pictures 构建图片模型

// 指定图片路径
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图片,我们可以利用Java生成图表插入到word文档中
put("buffered", Pictures.ofBufferedImage(bufferImage, PictureType.PNG)
  .size(100, 100).create());

FilePictureRenderData的结构体

{
  "pictureType" : "PNG",  // 图片类型
  "path": "logo.png",  // 图片路径
  "pictureStyle": { 
    "width": 100, // 宽度 
    "height": 100  // 高度
  },
  "altMeta": "图片不存在" // 图片不存在显示的文字
}
动态表格
表格标签以#开始:{
   {#var}}

数据模型:

  • TableRenderData

推荐使用工厂 TablesRowsCells 构建表格模型。

  • Example 1. 基础表格示例
// 一个2行2列的表格
put("table0", Tables.of(new String[][] {
                new String[] { "00", "01" },
                new String[] { "10", "11" }
            }).border(BorderStyle.DEFAULT).create());

table simple

  • Example 2. 表格样式示例
// 第0行居中且背景为蓝色的表格
RowRenderData row0 = Rows.of("姓名", "学历").textColor("FFFFFF")
      .bgColor("4472C4").center().create();
RowRenderData row1 = Rows.create("李四", "博士");
put("table1", Tables.create(row0, row1));

table header

  • Example 3. 表格合并示例
// 合并第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());

table merge

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

数据模型:

  • List<String>
  • NumberingRenderData

推荐使用工厂 Numberings 构建列表模型。

代码示例

put("list", Numberings.create("Plug-in grammar",
                    "Supports word text, pictures, table...",
                    "Not just templates"));
区块对
区块对由前后两个标签组成,开始标签以?标识,结束标签以/标识:{
   {?sections}}{
   {/sections}}

使用示例
{
   {?songs}}

{
   {name}}

{
   {/songs}}

可以用作判断

区块对开始和结束标签中间可以包含多个图片、表格、段落、列表、图表等,开始和结束标签可以跨多个段落,也可以在同一个段落,但是如果在表格中使用区块对,开始和结束标签必须在同一个单元格内,因为跨多个单元格的渲染行为是未知的。

区块对在处理一系列文档元素的时候非常有用,位于区块对中的文档元素可以被渲染零次,一次或N次,这取决于区块对的取值。

  • False或空集合

    隐藏区块中的所有文档元素

  • 非False且不是集合

    显示区块中的文档元素,渲染一次

  • 非空集合

    根据集合的大小,循环渲染区块中的文档元素

循环内置变量

在循环中提供了一些内置变量,这些内置变量只能用于区块对中。

变量 类型 说明
_index int 返回当前迭代从0开始的索引
_is_first boolean 辨别循环项是否是当前迭代的第一项。
_is_last boolean 辨别循环项是否是当前迭代的最后一项。
_has_next boolean 辨别循环项是否是有下一项。
_is_even_item boolean 辨别循环项是否是当前迭代间隔1的奇数项。
_is_odd_item boolean 辨别循环项是否是当前迭代间隔1的偶数项。
#this object 引用当前对象,由于#和已有表格标签标识冲突,所以在文本标签中需要使用=号标识来输出文本。

template.docx(注意:如果标签内要使用运算符,需要开启Spring表达式):

{
   {?produces}}
{
   {_index + 1}}. {
   {=#this}}
{
   {/produces}}
Spring 表达式

Spring Expression Language 是一个强大的表达式语言,支持在运行时查询和操作对象图,可作为独立组件使用,需要引入相应的依赖:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-expression</artifactId>
  <version>5.3.18</version>
</dependency>

开启办法

为了在模板标签中使用SpringEL表达式,需要将标签配置为SpringEL模式:

    /**
     * 导出模板文件
     */
    public void export(String templateId, String userId) throws Exception {
    
        // 支持InputStream传参
        var configBuilder = Configure.builder();
        configBuilder.useSpringEL();
        var config = configBuilder.build();
        var template = XWPFTemplate.compile("template.docx", config);
        template.render(List.of("模拟数据", "模拟数据2"));
        // 可以写入到Byte[]上传到文件存储
        template.write(new FileOutputStream("output.docx"));
    }
{
   {name}} 
{
   {name.toUpperCase()}}  //类方法调用 转大写
{
   {name == 'poi-tl'}} //判断条件
{
   {empty?:'这个字段为空'}} 
{
   {sex ? '男' : '女'}} //三目运算符
{
   {new java.text.SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(time)}}  //类方法调用,时间格式化
{
   {price/10000 + '万元'}} //运算符
{
   {dogs[0].name}} //数组列表使用下标访问
{
   {localDate.format(T(java.time.format.DateTimeFormatter).ofPattern('yyyy年MM月dd日'))}} //使用静态方法 

更多的使用请参考文档:Poi-tl Documentation (deepoove.com)

  • tips

FreeMarker、Velocity文本模板中可以通过三个标签设置图片路径、宽和高:, 但是Word模板不是由简单的文本表示,所以在渲染图片、表格等元素时提供了数据模型,它们都实现了接口 RenderData ,比如图片数据模型 PictureRenderData 包含图片路径、宽、高三个属性

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_38372249/article/details/136936369

智能推荐

Java版WMS系统奇门云网关(奇门仓储)接口实现_奇门wms struct-程序员宅基地

文章浏览阅读4.8k次,点赞2次,收藏9次。基于spring框架 实现的奇门云网关 WMS端 通用API方法:package org.tempuri;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.StringReader;import java.io.Strin..._奇门wms struct

原生应用的开发-flutter、rn - window篇_pc原生应用开发技术-程序员宅基地

文章浏览阅读471次。原生应用开发框架React-Nativefacebook 推出的使用react,js开发的原生框架react官网Weex阿里巴巴开源的使用vue开发的原生框架weex官网Flutterdart语言,类似es6,如果对面向对象有深入理解的话,很快上手,google公司推出的Flutter官网React-Native基于react优雅的架构设计支持热重..._pc原生应用开发技术

faiss学习(二)另外两种基础索引,保存索引_indexivfflat-程序员宅基地

文章浏览阅读9.7k次,点赞2次,收藏8次。在上一篇文章里面的官方demo建立索引方式使用的是最基本的索引,这里在介绍两种基础索引更多索引类别1--更快的检索IndexIVFFlat官方介绍:为了加快搜索速度,可以将数据集分割成几部分。我们在d维空间中定义Voronoi单元格,并且每个数据库矢量都落入其中一个单元格中。在搜索时,只有查询x所在单元中包含的数据库向量y与少数几个相邻查询向量进行比较。(划分搜索空间)这是通过Inde..._indexivfflat

IAR源文件注释中文显示乱码_iar中文乱码-程序员宅基地

文章浏览阅读1.7w次,点赞5次,收藏14次。IAR注释中文显示乱码,在Tools&amp;gt;&amp;gt;Options&amp;gt;&amp;gt;Editor&amp;gt;&amp;gt;Default character 选择正确的编码比如UTF-8,然后关闭文件,再次打开。_iar中文乱码

SLS 智能告警平台最新技术总结_数据中台 告警系统-程序员宅基地

文章浏览阅读1.6k次。本文主要讲述过去一年内可观测平台 SLS 的改进和迭代。_数据中台 告警系统

win7 系统装SQLServer2000 成功_ghost封装sql 2000-程序员宅基地

文章浏览阅读854次。昨天在win7上装SQLServer数据库,写一下体会。首先,如果以前安装的话,要删除干净。我也找了半天的网络资料。1.把原来SQLServer的安装目录 C:\Program Files\Microsoft SQL Server 删除2.所有SQLServer相关的注册表全部删除,保证系统是没有装过SQLServer的状态注册表打开方式:开始--&gt;运行--&gt;rege_ghost封装sql 2000

随便推点

Linux中禁用ctrl alt del快捷键重启_linx 关闭 ctrl alt del-程序员宅基地

文章浏览阅读363次,点赞7次,收藏8次。【代码】Linux中禁用ctrl alt del快捷键重启。_linx 关闭 ctrl alt del

Vue.js动态获取浏览器高度、宽度并进行实时修改DOM元素高度_vue3 dom元素获取距离浏览器工具栏的高度-程序员宅基地

文章浏览阅读4.7k次,点赞2次,收藏7次。需求:项目中有高度、宽度自适应需求,需要适应不同分辨率的高度及宽度,在不同分辨率下效果区别不会很大html代码如下:<template> <div id="home"> <div class="head" > <v-head></v-head> </div&..._vue3 dom元素获取距离浏览器工具栏的高度

在SpringBoot中使用Spring Security实现权限控制_spring-security配置允许访问ip-程序员宅基地

文章浏览阅读6.8k次,点赞2次,收藏6次。以前在Spring框架中使用Spring Security需要我们进行大量的XML配置,但是,Spring Boot在这里依然有惊喜带给我们,我们今天就一起来看看。 毫无疑问,Spring Boot针对Spring Security也提供了自动配置的功能,这些默认的自动配置极大的简化了我们的开发工作,我们今天就来看看这个吧。创建Project并添加相关依赖 配置applicat..._spring-security配置允许访问ip

vmware16,vmware17虚拟机安装以及序列号备份,安装win11,进入启动界面闪退_vm17pro密钥许可证-程序员宅基地

文章浏览阅读737次,点赞9次,收藏8次。检测到hyper-v 时,勾选自动安装。_vm17pro密钥许可证

用sqoop将hive导入mysql中文乱码_sqoop --default-character-set=utf8-程序员宅基地

文章浏览阅读1.5k次。修改/etc/my.cnfcharacter-set-server=utf8[client]default-character-set=utf8注释掉 sql_mode重新新建mysql表在hive的元数据库中执行以下SQL语句,然后重新创建刚才的表即可 。alter table COLUMNS_V2 modify column COMMENT varchar(256) character set utf8;alter table TABLE_PARAMS modify column PAR_sqoop --default-character-set=utf8

python中将xml格式转json格式-程序员宅基地

文章浏览阅读845次。一、简介 在用python写脚本时,通常需要处理xml格式的文件或字符串。由于json格式处理的方便性, 我们可将其转为json格式进行处理。 二、步骤 1、安装工具包xmltodict 在命令行输入:pip install xmltodict 2、在代码使用xmltodict.parse(xml_str)进行处理 如 def load_json(xml_path): #获取xml文件 xml_f..._python xml 转json 格式