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

文章说明

本篇文章主要通过代码案例的方式,展示 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>() {{// 直接插入 Stringput("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.mzph.cn/diannao/37865.shtml

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

相关文章

俄罗斯防空系统

俄罗斯的S系列防空系统是一系列先进的地对空导弹系统&#xff0c;旨在防御各类空中威胁&#xff0c;包括飞机、无人机、巡航导弹和弹道导弹。以下是几种主要的S系列防空系统&#xff1a; 1. **S-300系统**&#xff1a; - **S-300P**&#xff1a;最早期的版本&#xff0c;用…

翻译造句练习

翻译练习 翻译 1&#xff1a;经常做运动会提高人的自信 翻译 2&#xff1a;教学的质量对学生成绩有很大的影响。 翻译 3&#xff1a;家长和老师应该努力去减少小孩看电视的时间。 翻译 4&#xff1a;经济的下滑&#xff08;economic slowdown&#xff09;导致失业率的上升 翻译…

大模型和数据库最新结合进展

写在前面 本文主要内容是上次接受 infoQ 访谈&#xff0c;百度智能云朱洁老师介绍了大模型和 AI 结合相关话题&#xff0c;这次整体再刷新下&#xff0c;给到对这个领域感兴趣的同学。 当前&#xff0c;百度智能云云数据库特惠专场开始&#xff01;热销规格新用户免费使用&am…

Android中ViewModel+LiveData+DataBinding的配合使用(kotlin)

Android 中 ViewModel、LiveData 和 Data Binding 的配合使用&#xff08;Kotlin&#xff09; 摘要 本文将介绍如何在 Android 开发中结合使用 ViewModel、LiveData 和 Data Binding 进行数据绑定和状态更新。我们将详细探讨这三者之间的关系&#xff0c;并展示如何在 Kotlin…

最逼真的简易交通灯设计

最逼真的简易交通灯设计 需要资料的请在文章末尾获取&#xff08;有问题可以私信我哦~~&#xff09; 01 资料内容 Proteus仿真文件程序源码实物制作&#xff0c;代码修改&#xff0c;功能定制&#xff08;需额外收费&#xff0c;价格实惠&#xff0c;欢迎咨询&#xff09; …

实验场:在几分钟内使用 Elasticsearch 进行 RAG 应用程序实验

作者&#xff1a;来自 Elastic Joe McElroy, Serena Chou 什么是 Playground&#xff08;实验场&#xff09;&#xff1f; 我们很高兴发布我们的 Playground 体验 —- 一个低代码界面&#xff0c;开发人员可以在几分钟内使用自己的私人数据探索他们选择的 LLM。 在对对话式搜…

41割队伍

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/387 题目描述 给定 𝑛n 个数字 𝑎1,�…

一周小计(1):实习初体验

实习的第一周&#xff0c;从最开始的配环境做好准备工作&#xff0c;到拉项目熟悉项目&#xff0c;然后自己去写需求&#xff0c;每一步都有很大收获&#xff0c;得到很多人帮助真的好感谢&#xff0c;以下是个人这几天的记录与感想。 &#xff08;这个其实是我写的周报&#x…

Hi3861 OpenHarmony嵌入式应用入门--LiteOS Semaphore做同步使用

信号量作为同步使用 创建一个Semaphore对象&#xff0c;并指定一个初始的计数值&#xff08;通常称为“许可”或“令牌”的数量&#xff09;。这个计数值表示当前可用的资源数量或可以同时访问共享资源的线程数。当一个线程需要访问共享资源时&#xff0c;它会尝试从Semaphore…

加油站可视化:打造智能化运营与管理新模式

智慧加油站可视化通过图扑 HT 构建仿真的三维模型&#xff0c;将加油站的布局、设备状态、人员活动等信息动态呈现。管理者可以通过直观的可视化界面实时监控和分析运营状况&#xff0c;快速做出决策&#xff0c;提高管理效率和安全水平&#xff0c;推动加油站向智能化管理转型…

后端之路第三站(Mybatis)——结合案例讲Mybatis怎么操作sql

先讲一下准备工作整体流程要做什么 我们要基于一个员工管理系统作为案例&#xff0c;进行员工信息的【增、删、改、查】 原理就是用Mybatis通过java语言来执行sql语句&#xff0c;来达到【增、删、改、查】 一、准备工作 1、引入数据库数据 首先我们把一个员工、部门表的数…

【51单片机入门】速通定时器

文章目录 前言定时器是什么初始化定时器初始化的大概步骤TMOD寄存器C/T寄存器 触发定时器中断是什么中断函数定时器点亮led 总结 前言 在嵌入式系统的开发中&#xff0c;定时器是一个非常重要的组成部分。它们可以用于产生精确的时间延迟&#xff0c;或者在特定的时间间隔内触…

对外发布的PDF文档进行数字证书签名的重要性?

对外发布的PDF文档进行数字证书签名具有以下几个重要性&#xff1a; 身份验证&#xff1a;数字签名可以证明文档的来源&#xff0c;即确认文档的签署者身份。这如同在纸质文档上手写签名或加盖公章&#xff0c;但更安全可靠&#xff0c;因为数字签名是基于加密技术&#xff0c;…

Java--常用类APl(复习总结)

前言: Java是一种强大而灵活的编程语言&#xff0c;具有广泛的应用范围&#xff0c;从桌面应用程序到企业级应用程序都能够使用Java进行开发。在Java的编程过程中&#xff0c;使用标准类库是非常重要的&#xff0c;因为标准类库提供了丰富的类和API&#xff0c;可以简化开发过…

【接口自动化测试】第三节.实现项目核心业务接口自动化

文章目录 前言一、实现登录接口对象封装和调用 1.0 登录接口的接口测试文档 1.1 接口对象层&#xff08;封装&#xff09; 1.2 测试脚本层&#xff08;调用&#xff09;二、课程新增接口对象封装和调用 2.0 课程新增接口的接口测试文档 2.1 接口对象层…

AVL树模拟

1.概念 虽然二叉搜索树可以缩短查找的效率&#xff0c;但如果数据有序或者接近有序时二叉搜索树树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。AVL 树是具有一下性质的二叉搜索树&#xff1a; 1.它的左右子树都是AVL树 2.左右子…

Mac 如何安装 wget

1.安装 Homebrew2.安装 wget3.检测 wget 是否安装成功 1.安装 Homebrew 在安装 wget 之前需要安装一个适用于 mac 的包管理器 Homebrew&#xff0c;打开 mac 终端执行如下命令进行安装&#xff1a; /usr/bin/ruby -e "$(curl -fsSL https://cdn.jsdelivr.net/gh/ineo6/h…

【Git】GitIgnore不生效

这里可能有两种原因&#xff0c;一个没有刷新Git缓存&#xff0c;二是Git忽略规则有问题 更新Git缓存 git rm -r --cached . git add . git commit -m "modify git ignore rule"Ignore规则 检查下忽略文件的目录表示是否正确 XXX忽略任意目录下名为XXX的文件 …

新手第一个漏洞复现:MS17-010(永恒之蓝)

文章目录 漏洞原理漏洞影响范围复现环境复现步骤 漏洞原理 漏洞出现在Windows SMB v1中的内核态函数srv!SrvOs2FeaListToNt在处理FEA&#xff08;File Extended Attributes&#xff09;转换时。该函数在将FEA list转换成NTFEA&#xff08;Windows NT FEA&#xff09;list前&am…

【Golang - 90天从新手到大师】Day14 - 方法和接口

一&#xff0e; go方法 go方法&#xff1a;在函数的func和函数名间增加一个特殊的接收器类型&#xff0c;接收器可以是结构体类型或非结构体类型。接收器可以在方法内部访问。创建一个接收器类型为Type的methodName方法。 func (t Type) methodName(parameter list) {}go引入…