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 文件时,先搞清楚三个问题:
- 定义 docx 模板文件:要生成怎么样的文件,自行创建一个 docx 的模板文件
- 定义模板文件的数据:向模板文件中,添加数据
- 生成文件位置:实际开发中大多会通过网络的方式传递,这里只展示生成在本地文件
本篇文章展示一些关键代码,为了减少冗余,我们可以定义一个生成 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);
文档效果:

相关文章:
poi-tl 生成 word 文件(插入文字、图片、表格、图表)
文章说明 本篇文章主要通过代码案例的方式,展示 poi-tl 生成 docx 文件的一些常用操作,主要涵盖以下内容 : 插入文本字符(含样式、超链接)插入图片插入表格引入标签(通过可选文字的方式,这种方…...
centos上部署Ollama平台,实现语言大模型本地部署
网上有很多大模型,很多都是远程在线调用ChatGPT的api来实现的,自己本地是没有大模型的,这里和大家分享一个大模型平台,可以实现本地快速部署大模型。 Ollama是一个开源项目,它提供了一个平台和工具集,用于部…...
Java学习 - Redis Redigo简单介绍
Redigo 驱动下载 go get github.com/garyburd/redigo/redis获取redis服务器连接 c, err : redis.Dial("tcp", "127.0.0.1:6379")if err ! nil {panic(err) }defer c.Close()命令使用 v, err : c.Do("SET","hello","world&quo…...
【鸿蒙学习笔记】ArkTS组件 Blank
官方文档:Blank 目录标题...
如何使用Spring Boot进行单元测试
如何使用Spring Boot进行单元测试 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨如何在Spring Boot项目中进行单元测试,确保代码质量…...
2024steam夏促商店打不开、steam活动加载不了解决方法一览
今年的夏促终于开始了!目前可以看到很多精品小游戏在促销列表内,活动正式开启后还不知道又会是怎样的一幅场景。因为每年夏促都会有不少刚高考完的新手加入,遇到常见的steam商店打不开、活动页面不加载等问题不知道怎么解决。所以这里给大家准备了几种常…...
IPC进程通信:QNX
引言 在现代操作系统中,进程间通信(IPC)机制是实现进程间数据交换和同步的关键技术。IPC允许多个进程共享信息和资源,从而协同工作完成复杂任务。在QNX Neutrino系统中,IPC尤为重要,因为QNX主要面向实时系…...
OpenCV学习之cv2.imshow()函数
OpenCV学习之cv2.imshow()函数 一、简介 cv2.imshow 是 OpenCV 库中用于显示图像的基本函数之一。在图像处理和计算机视觉的过程中,使用该函数可以快速预览处理后的图像,便于调试和结果展示。 二、基本语法 cv2.imshow(WindowName, Imgmat)三、参数说…...
Oracle、MySQL、PostGreSQL、SQL Server-空值
Oracle、MySQL、PostGreSQL、SQL Server-null value 最近几年数据库市场百花齐放,在做跨数据库迁移的数据库选型时,除了性能、稳定、安全、运维、功能、可扩展外,像开发中对于值的处理往往容易被人忽视, 之前写过一篇关于PG区别O…...
python pip详解1
一、简介 pip是python的一个软件包管理工具,同yum,apt作用一致,pip有两种使用方式:pip模块和pip命令,示例如下: python -m pip install package pip install package二、命令行详解 python -m pip --hel…...
Linux常用命令大全(超详细!!!)
文章目录 1.Linux是什么1.1 关于Linux我们主要学习什么1.1 学习Linux常见命令的前置知识 2. Linux常见命令2.1 ls命令2.2 cd命令2.3 pwd命令2.4 touch命令2.5 cat命令2.6 echo命令2.7 vim命令2.8 mkdir 命令2.9 rm命令2.10 cp命令2.11 mv命令2.12 grep命令2.13 ps命令2.14 nets…...
TDD测试驱动开发
为什么需要TDD? 传统开发方式,带来大量的低质量代码,而代码质量带来的问题: 1.在缺陷的泥潭中挣扎 开发长时间投入在缺陷的修复中,修复完依赖测试做长时间的回归测试 2.维护困难,开发缓慢 比如重复代码&am…...
huggingface镜像站
huggingface下载太慢,大模型文件太大。用huggingface_hub镜像。 pip install -U huggingface_hub pip install huggingface-cli export HF_ENDPOINThttps://hf-mirror.com huggingface-cli download --resume-download shenzhi-wang/Llama3-8B-Chinese-Chat --loc…...
Java中如何实现数据库连接池优化?
Java中如何实现数据库连接池优化? 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨在Java应用程序中如何实现数据库连接池优化&am…...
002 SpringMVC入门项目搭建
文章目录 HelloController.javaspringmvc.xmlweb.xmlpom.xmlhello.jsp http://localhost:8080/showView http://localhost:8080/showData HelloController.java package com.springmvc.controller;import org.springframework.stereotype.Controller; import org.springframewo…...
为什么要使用多线程(并发编程)
目录 1.上下文的切换 1.1 什么是上下文切换 2. 并发编程的死锁问题 2.1 死锁产生的原因 2.2 避免死锁的方法 3.资源限制的挑战3.1 什么是资源限制 并发编程的目的是为了让程序更快,大家都知道并不是开启的线程越多越快,因为开启的线程越多随即面临…...
Unity编辑器工具---版本控制与自动化打包工具
Unity - 特殊文件夹【作用与是否会被打包到build中】 Unity编辑器工具—版本控制与自动化打包工具: 面板显示:工具包含一个面板,用于展示软件的不同版本信息。版本信息:面板上显示主版本号、当前版本号和子版本号。版本控制功能…...
amis-editor 注册自定义组件
建议先将amis文档从头到尾,仔细看一遍。 参考:amis - 低代码前端框架 amis 的渲染过程是将 json 转成对应的 React 组件。先通过 json 的 type 找到对应的 Component,然后把其他属性作为 props 传递过去完成渲染。 import * as React from …...
(上位机APP开发)调用华为云命令API接口给设备下发命令
一、功能说明 通过调用华为云IOT提供的命令下发API接口,实现下面界面上相同的功能。调用API接口给设备下发命令。 二、JavaScript代码 function sendUnlockCommand() {var requestUrl = "https://9bcf4cfd30.st1.iotda-app.cn-north-4.myhuaweicloud.com:443/v5/iot/60…...
排序算法系列一:选择排序、插入排序 与 希尔排序
目录 零、说在前面 一、理论部分 1.1:选择排序 1.1.1:算法解读: 1.1.2:时间复杂度 1.1.3:优缺点: 1.1.4:代码: 1.2:插入排序 1.2.1:算法解读&#x…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
