poi-tl 生成 word 文件(插入文字、图片、表格、图表)

news2024/11/22 16:21:06

文章说明

本篇文章主要通过代码案例的方式,展示 poi-tl 生成 docx 文件的一些常用操作,主要涵盖以下内容 :

  • 插入文本字符(含样式、超链接)
  • 插入图片
  • 插入表格
  • 引入标签(通过可选文字的方式,这种方式也可以实现插入图片和插入表格)

当然 poi-tl 官方也有很详细的介绍,官网文档地址:https://deepoove.com/poi-tl/

项目初始化【必读】

项目创建好之后第一件事当然是引入依赖啦。

下面是 maven 引入的依赖,如果使用 Gradle 自行转成 Gradle 依赖。

<!-- poi 依赖 -->
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
  <version>5.2.5</version>
</dependency>
<!-- poi-tl -->
<dependency>
  <groupId>com.deepoove</groupId>
  <artifactId>poi-tl</artifactId>
  <version>1.12.2</version>
</dependency>

在 poi-tl 生成 docx 文件时,先搞清楚三个问题:

  1. 定义 docx 模板文件:要生成怎么样的文件,自行创建一个 docx 的模板文件
  2. 定义模板文件的数据:向模板文件中,添加数据
  3. 生成文件位置:实际开发中大多会通过网络的方式传递,这里只展示生成在本地文件

本篇文章展示一些关键代码,为了减少冗余,我们可以定义一个生成 docx 的工具类 PoitlUtils:

import com.deepoove.poi.XWPFTemplate;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

/**
 * @author 17279
 */
public class PoitlUtils {

  /**
    * @param templateData 生成模板文件所需的所有数据
    * @param templateFilePath 模板文件路径(这里读取的是 resources 下的文件)
    * @param outputFilePath 模板文件输入的地址
    */
  public static void generateWordFile(Map<String, Object> templateData, String templateFilePath, String outputFilePath) {
    // 读取模板文件
    try (InputStream templateIn = PoitlUtils.class.getResourceAsStream(templateFilePath)) {
      // 生成模板文件
      XWPFTemplate template = XWPFTemplate.compile(templateIn).render(templateData);
      template.writeAndClose(new FileOutputStream(outputFilePath));
      // 这个目的是:生成文件之后调用 cmd 打开本地文件,实际生产不需要该操作
      // Runtime.getRuntime().exec(String.format("cmd /c %s", outputFilePath));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

这里使用的所有 docs 模板文件,我都存放在 resources 的目录下。

在这里插入图片描述

插入文本

str_demo.docx 文件,文本使用 {{xxx}} 设置占位符:

{{str1}}	
{{str2}}
{{str3}}
{{str4}}
{{?strArr1}}{{=#this}} {{/strArr1}}

案例代码:

// 模板文件
String templateFilePath = "/word_template/str_demo.docx";
// 输出文件
String outputFilePath = "D:/output.docx";
// 插入文本数据
Map<String, Object> templateData = new HashMap<String, Object>() {{
  // 直接插入 String
  put("str1", "直接插入 String");
  // 插入含有样式的文本
  put("str2", Texts.of("插入含有样式的文").color("ff0000").create());
  // 插入含超链接的文本
  put("str3", Texts.of("插入含有样式的文").link("http://www.shijialeya.top/").create());
  // 传入一个对象
  put("str4", Arrays.asList("键盘敲破", "工资过万"));
  // 遍历文本
  put("strArr1", Arrays.asList("派大星", "瘸老板", "海绵宝宝", "章鱼哥", "蟹老板"));
}};
// 文件生成
PoitlUtils.generateWordFile(templateData, templateFilePath, outputFilePath);

文档效果:

在这里插入图片描述

要注意 docx 文件上的 {{xxx}} xxx 的前后不要有空格,如果将外面的文字复制到 word 可能会自动加空格。

插入图片

img_demo.docx 文件,图片通过 {{@xxx}} 设置占位符:

{{@img1}}

{{@img2}}

{{@img3}}

{{@img4}}

{{?imgArr1}}{{@#this}}  {{/imgArr1}}

案例代码:

// 模板文件
String templateFilePath = "/word_template/img_demo.docx";
// 输出文件
String outputFilePath = "D:/output.docx";
// 插入文本数据
Map<String, Object> templateData = new HashMap<String, Object>() {{
  // 直接插入本地图片(默认图片的宽度与文档的宽度一致)
  // put("img1", "C:/Users/17279/Pictures/head.jpg");
  // 插入本地图片,并设置图片大小
  put("img1", Pictures.ofLocal("C:/Users/17279/Pictures/head.jpg").size(100, 100).create());
  // 通过流的形式写入图片
  put("img2", Pictures.ofStream(new FileInputStream("C:/Users/17279/Pictures/head.jpg"), PictureType.JPEG).size(150, 150).create());
  // 写入网络图片
  put("img3", Pictures.ofUrl("http://file.shijialeya.top/head.jpg", PictureType.JPEG).size(170, 170).create());
  // 写入通过 Java 生成的图片
  put("img4", Pictures.ofBufferedImage(new BufferedImage(190, 190, BufferedImage.TYPE_BYTE_GRAY), PictureType.PNG).size(190, 190).create());

  // 遍历图片
  put("imgArr1", new ArrayList<Object>() {{
    add(Pictures.ofLocal("C:/Users/17279/Pictures/head.jpg").size(100, 100).create());
    add(Pictures.ofLocal("C:/Users/17279/Pictures/head.jpg").size(100, 100).create());
    add(Pictures.ofLocal("C:/Users/17279/Pictures/head.jpg").size(100, 100).create());
  }});
}};
// 文件生成
PoitlUtils.generateWordFile(templateData, templateFilePath, outputFilePath);

文档效果:

在这里插入图片描述

插入表格

tab_demo.docx 文件,图片通过 {{#xxx}} 设置占位符:

{{#tab1}}

{{#tab2}}

{{#tab3}}

合同名称	{{tab4.contractName}}
合同时间	{{tab4.contractDate}}	合同金额	{{tab4.money}}
合同公司	{{tab4.company}}

在这里插入图片描述

案例代码:

// 模板文件
String templateFilePath = "/word_template/tab_demo.docx";
// 输出文件
String outputFilePath = "D:/output.docx";
// 插入文本数据
Map<String, Object> templateData = new HashMap<String, Object>() {{
  // 插入一个基础表格
  String[][] tabData1 = {
    new String[]{"姓名", "性别", "年龄"},
    new String[]{"派大星", "16", "男"},
    new String[]{"章鱼哥", "35", "男"}
  };
  put("tab1", Tables.of(tabData1).create());

  // 插入一个含有样式的表格
  Tables.TableBuilder tabData2 = Tables
    // 创建一个指定宽度的表格(docx 文档的 80% 宽度)
    .ofPercentWidth("80%")
    // 表格设为水平居中
    .center()
    // 设置表格边框
    .border(BorderStyle.builder()
            // 边框样式
            .withType(XWPFTable.XWPFBorderType.DOUBLE)
            // 边框颜色
            .withColor("ff0000")
            // 边框粗细(边框为线条类型才会有效)
            .withSize(12)
            .build()
           );
  tabData2.addRow(Rows.of("姓名", "性别", "年龄")
                  // 设置文字颜色
                  .textColor("FFFFFF")
                  // 设置对应表格的背景颜色
                  .bgColor("4472C4")
                  // 文字居中
                  .center()
                  .create()
                 );
  tabData2.addRow(Rows.of("派大星", "16", "男").create());
  put("tab2", tabData2.create());

  // 合并单元格
  String[][] tabData3 = {
    new String[]{"姓名", "性别", "年龄"},
    new String[]{"派大星", "16", "男"},
    new String[]{"章鱼哥", "35", "男"},
    new String[]{"共2人", null, null},
  };
  put("tab3", Tables.of(tabData3)
      // 添加单元格合并规则
      .mergeRule(MergeCellRule
                 .builder()
                 // [纵坐标, 横坐标] 索引从零开始,合并 [3, 0] 到 [3, 2] 位置的表格
                 .map(MergeCellRule.Grid.of(3, 0), MergeCellRule.Grid.of(3, 2))
                 .build()
                )
      .create()
     );

  // 对应格式一定的表格,直接采用字符串替换即可
  put("tab4", new HashMap<String, Object>() {{
    put("contractName", "第一季度财务报告");
    put("contractDate", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
    put("company", "xxx有限责任公司");
    put("money", 10089.33);
  }});
}};
// 文件生成
PoitlUtils.generateWordFile(templateData, templateFilePath, outputFilePath);

文档效果:在这里插入图片描述

引入标签

插入图片

上面也有插入图片的方式,但是通过引入标签的方式插入图片时,可以先在 word 模板文件中提前编辑好图片的样式,通过替换图片的方式,会保留原本设置好的样式。

在 docx 模板文件中先插入一张图片,并且调整好图片的样式,之后右键图片选择【查看可选文字】,在可选文字中通过 {{xxx}} 的方式填写属性名称。

【特别提醒】貌似 WPS 没有可选文字的功能,不确定是不是 WPS 版本的原因,反正我没找到可选文字。

因此我特地把 WPS 卸载之后换成了 Office 工具。

在这里插入图片描述

案例代码:

// 模板文件
String templateFilePath = "/word_template/quote_demo01.docx";
// 输出文件
String outputFilePath = "D:/output.docx";
// 插入文本数据
Map<String, Object> templateData = new HashMap<String, Object>() {{
  // 直接插入本地图片,这里会保留模板文件的图片样式
  put("label1", Pictures.ofLocal("C:/Users/17279/Pictures/head.jpg").create());
}};
// 文件生成
PoitlUtils.generateWordFile(templateData, templateFilePath, outputFilePath);

文档效果:

在这里插入图片描述

插入单系列图表

单系列图表指的是饼图(3D饼图)、圆环图等。

同引入标签插入图片一样,在插入图表的时候,需要在 docx 模板中创建一个单系列的图表,设置好样式,之后右键图表选择【查看可选文字】,在可选文字中通过 {{xxx}} 的方式填写属性名称。

在这里插入图片描述

案例代码:

// 模板文件
String templateFilePath = "/word_template/quote_demo02.docx";
// 输出文件
String outputFilePath = "D:/output.docx";
// 插入文本数据
Map<String, Object> templateData = new HashMap<String, Object>() {{
  // 添加单系列图表的表格数据
  put("label2", Charts
      .ofSingleSeries("商品类型", new String[]{"电器类", "数码类", "生活用品类", "食品类", "其他"})
      .series("数量", new Integer[]{30, 8, 25, 11, 3})
      .create());
}};
// 文件生成
PoitlUtils.generateWordFile(templateData, templateFilePath, outputFilePath);

文档效果:

在这里插入图片描述

插入多系列图表

多系列图表指的是条形图(3D条形图)、柱形图(3D柱形图)、面积图(3D面积图)、折线图(3D折线图)、雷达图、散点图等。

模板文件如下:

在这里插入图片描述

案例代码:

// 模板文件
String templateFilePath = "/word_template/quote_demo03.docx";
// 输出文件
String outputFilePath = "D:/output.docx";
// 插入文本数据
Map<String, Object> templateData = new HashMap<String, Object>() {{
  // 添加单系列图表的表格数据
  put("label3", Charts
      .ofMultiSeries("销售额", new String[]{"第一季度", "第二季度", "第三季度", "第四季度"})
      .addSeries("电器类", new Integer[]{22, 25, 28, 25})
      .addSeries("数码类", new Integer[]{5, 10, 8, 4})
      .addSeries("其他", new Integer[]{30, 42, 22, 33})
      .create());
}};
// 文件生成
PoitlUtils.generateWordFile(templateData, templateFilePath, outputFilePath);

文档效果:在这里插入图片描述

插入组合图表

组合图表指的是由多系列图表(柱形图、折线图、面积图)组合而成的图表。

模板文件如下:

在这里插入图片描述

案例代码:

// 模板文件
String templateFilePath = "/word_template/quote_demo04.docx";
// 输出文件
String outputFilePath = "D:/output.docx";
// 插入文本数据
Map<String, Object> templateData = new HashMap<String, Object>() {{
  // 添加单系列图表的表格数据
  put("label4", Charts
      .ofComboSeries("汽车销售额", new String[]{"第一季度", "第二季度", "第三季度", "第四季度"})
      // 添加柱状图数据
      .addBarSeries("比亚迪", new Double[]{12.3, 11.5, 9.7, 12.0})
      .addBarSeries("广汽", new Double[]{6.2, 5.8, 5.7, 6.6})
      .addBarSeries("小米", new Double[]{0.0, 0.0, 10.2, 11.2})
      // 添加折线图数据
      .addLineSeries("国内均值", new Double[]{10.0, 12.2, 11.2, 9.8})
      .addLineSeries("全球均值", new Double[]{8.3, 10.2, 10.0, 8.8})
      .create());
}};
// 文件生成
PoitlUtils.generateWordFile(templateData, templateFilePath, outputFilePath);

文档效果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1878060.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

昇思MindSpore学习笔记3--张量 Tensor

一、张量Tensor概念 矢量、标量和其他张量的计算函数&#xff0c;有内积、外积、线性映射以及笛卡儿积等 张量坐标在 n 维空间内&#xff0c;有 nr 个分量 每个分量都是坐标的函数,变换时每个坐标分量都按规则作线性变换 张量是一种特殊的数据结构&#xff0c;类似于数组和…

haproxy实现代理和负载均衡

HaProxy介绍&#xff1a; haproxy是法国开发者威利塔罗在2000年使用C语言开发的一个开源软件&#xff0c;是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器&#xff0c;支持基于cookie的持久性&#xff0c;自动故障切换&#xff0c;支持正则表达式及web状态统计&…

狼人杀系列

目录 杀人游戏&#xff08;天黑请闭眼&#xff09; &#xff08;1&#xff09;入门版 &#xff08;2&#xff09;标准版 &#xff08;3&#xff09;延伸版——百度百科 &#xff08;3.1&#xff09;引入医生和秘密警察 &#xff08;3.2&#xff09;引入狙击手、森林老人和…

学习gateway网关路由时遇到的问题

遇到这个问题先别慌&#xff0c;我们首先要检查是哪里出问题了&#xff0c;从报错信息中我们可以看到&#xff0c;他说 Unable to find GatewayFilterFactory with name -AddRequestHeader 找不到这个路由过滤器&#xff0c;所以导致网关设置失败&#xff0c;从这条信息上我…

Mac可以读取NTFS吗 Mac NTFS软件哪个好 mac ntfs读写工具免费

在跨操作系统环境下使用外部存储设备时&#xff0c;特别是当Windows系统的U盘被连接到Mac电脑时&#xff0c;常常会遇到文件系统兼容性的问题。由于Mac OS原生并不完全支持对NTFS格式磁盘的读写操作&#xff0c;导致用户无法直接在Mac上向NTFS格式的U盘或硬盘写入数据。下面我们…

web学习笔记(六十九)vue2

目录 1. vue2创建脚手架项目 2.vue2如何关闭eslint 1. vue2创建脚手架项目 &#xff08;1&#xff09;在cmd窗口输入npm install -g vue/cli命令行&#xff0c;快速搭建脚手架。 &#xff08;2&#xff09; 创建vue2项目 &#xff08;3&#xff09; 选择配置项目&#xff0c…

ic基础|功耗篇04:门级低功耗技术

大家好&#xff0c;我是数字小熊饼干&#xff0c;一个练习时长两年半的IC打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结&#xff0c;并通过汇总成文章的形式进行输出&#xff0c;相信无论你是在职的还是…

pdf合并,pdf合并成一个pdf,pdf合并在线网页版

在处理pdf文件的过程中&#xff0c;有时我们需要将多个pdf文件合并成一个pdf文件。作为一名有着丰富计算机应用经验的技术博主&#xff0c;我将为您详细介绍如何将多个pdf文件合并成一个pdf文件。 pdf合并方法&#xff1a;使用&#xff0c; “轻云处理pdf官网” 打开 “轻云处…

mysql_config 命令, 可以查看mysqlclient库的位置在/usr/lib64/mysql下

好吧&#xff0c;其实我是从这里知道了 -l 后面加的库名和so文件这种名不一样&#xff0c;因为库文件实际叫下面这个名&#xff08;前面有lib)。

昇思MindSpore学习笔记1--基本介绍

昇思MindSpore是一个全场景深度学习框架。 一、框架组成 1. 模型库ModelZoo 提供深度学习算法网络。 2. 扩展库MindSpore Extend 拓展领域场景&#xff0c;如GNN/深度概率编程/强化学习等。 3. 科学计算MindSpore Science 科学计算套件。 包含数据集、基础模型、预置高精度模…

Mybatis从源码分析——启动到解析配置文件再到执行SQL语句过程

文章目录 前言解析配置文件解析源码Mapper文件解析过程二级缓存解析过程SQL的解析 SQL执行流程openSession()流程Executor执行器二级缓存查询数据流程 插件使用原理 前言 mybatis的体系结构&#xff1a; public class App {public static void main(String[] args) {String re…

【Java】解决Java报错:UnsupportedOperationException in Collections

文章目录 引言一、UnsupportedOperationException的定义与概述1. 什么是UnsupportedOperationException&#xff1f;2. UnsupportedOperationException的常见触发场景3. 示例代码 二、解决方案1. 使用适当的集合类型2. 创建可变副本3. 使用合适的集合工厂方法4. 使用不可变集合…

win11 (将星x17promax) 安装WSL 子系统

最初只是想着在win11系统下挂载ext4盘符&#xff0c;方便使用。 目录 0. 简介1.安装WSL子系统1.1 环境确认1.1.1 虚拟化设置1.1.2 系统设置1.1.3 开启开发者模式&#xff08;此项有必要&#xff1f;&#xff09;1.1.4 安装WSL子系统 2.WSL操作指令2.0 WSL相关命令2.1 WSL重置2.…

《概率论与数理统计》期末复习笔记_上

目录 第1章 随机事件与概率 1.1 随机事件 1.2 事件的关系与运算 1.3 概率的定义与性质 1.4 古典概型_重点 1.5 几何概型 1.6 条件概率与乘法公式 1.7 全概率公式与贝叶斯公式_重点 1.8 事件的独立性_重点 1.9 伯努利概型_重难点 第2章 随机变量及其分布 2.1 随机变…

MySQL之可扩展性(三)

可扩展性 向外扩展 可以把向外扩展(有时也称为横向扩展或水平扩展)策略划分为三个部分:复制、拆分以及数据分片(sharding).最简单也最常见的向外扩展的方法是通过复制将数据分发到多个服务器上&#xff0c;然后将备库用于读查询。这种技术对于以读为主的应用很有效。它也有一…

【乐吾乐2D可视化组态编辑器】自定义图形库

乐吾乐2D可视化组态软件图形库是一种可扩展、开放性的图形库&#xff0c;可根据不同的需求定制各种酷炫的组件效果和场景。 常用的方式有&#xff1a;①原生代码图形库、②字体图形库、③svg 图形库、④图片、⑤组合图形&#xff0c;以下主要从性能和开发成本维度考量&#xf…

内网渗透:端口转发(SSH隧道)

SSH&#xff1a;两台设备之间进行远程登录的协议&#xff08;SSH本身就是一个隧道协议&#xff09; 远程文件传输scp命令&#xff08;scp是基于SSH的&#xff09; 拓扑&#xff1a; SSH隧道搭建的条件 1.获取到跳板机权限 2.跳板机中SSH服务启动 SSH端口转发分类&#xff1…

锁机制 -- 概述篇

锁机制 1、概述 ​  加锁是为了解决并发场景下&#xff0c;多个线程对同一资源同时进行操作&#xff0c;而导致同一线程多次操作出现结果不唯一的情况&#xff08;一次操作包含多条指令&#xff09;。结果不唯一发生的原因在于指令的错乱&#xff0c;前提条件是多线程环境及…

模版总结小全

BFS 最短步数问题 #include<iostream> #include<queue> #include<cstring> using namespace std;const int N 50; char g[N][N],d[N][N]; int dx[] {-1,0,1,0}; int dy[] {0,1,0,-1}; int n,m;int bfs(int x,int y){queue<pair<int,int> > q…

ardupilot开发 --- 坐标变换 篇

Good Morning, and in case I dont see you, good afternoon, good evening, and good night! 0. 一些概念1. 坐标系的旋转1.1 轴角法1.2 四元素1.3 基于欧拉角的旋转矩阵1.3.1 单轴旋转矩阵1.3.2 多轴旋转矩阵1.3.3 其他 2. 齐次变换矩阵3. visp实践 0. 一些概念 相关概念&am…