使用Apache POI和POI-OOXML实现word模板文档自动填充功能
最近接到一个新的需求,用户创建好模板文件保存到模板库,然后使用在线文档编辑器打开模板时,将系统数据填充到模板文件并生成新的word文件,然后在线编辑,研究使用Apache POI和POI-OOXML实现了这个功能。
Maven依赖
<!-- Apache POI 和 POI-OOXML --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency>
自动填充的接口
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
@RequestMapping("/fill")
public class WordFillController {@PostMapping("/wordFill")public ResponseEntity<?> wordFill() {String templatePath = "E:\\word\\template.docx";String outputPath = "E:\\word\\output.docx";// 待填充进模板的数据Map<String, String> data = new HashMap<>();data.put("name", "张三");data.put("sex", "男");data.put("age", "18");Map<String, String> data1 = new HashMap<>();data1.put("name", "张三1");data1.put("sex", "男1");data1.put("age", "20");Map<String, String> data2 = new HashMap<>();data2.put("name", "李四");data2.put("sex", "男");data2.put("age", "21");Map<String, String> data3 = new HashMap<>();data3.put("name", "王五");data3.put("sex", "女");data3.put("age", "45");List<Map<String, String>> dataList = Arrays.asList(data1, data2, data3);try (// 从模板文件创建word文档对象XWPFDocument doc = new XWPFDocument(Files.newInputStream(Paths.get(templatePath)));// 文件输出流FileOutputStream fos = new FileOutputStream(outputPath)) {replacePlaceholders(doc, data);// 替换占位符fillTable(doc, dataList);// 填充表格// 将文档写入输出流doc.write(fos);// 刷新输出流fos.flush();return ResponseEntity.ok().build();} catch (IOException e) {e.printStackTrace();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());}}private void replacePlaceholders(XWPFDocument doc, Map<String, String> data) {// 遍历文档中的段落,替换占位符doc.getParagraphs().forEach(paragraph -> {// 遍历段落中的文本,替换占位符paragraph.getRuns().forEach(run -> {// 获取文本内容String text = run.getText(0);// 判断文本是否包含占位符,如果包含,则替换占位符if (text != null && text.contains("${")) {for (Map.Entry<String, String> entry : data.entrySet()) {text = text.replace("${" + entry.getKey() + "}", entry.getValue());}// 设置替换后的文本run.setText(text, 0);}});});}private void fillTable(XWPFDocument doc, List<Map<String, String>> dataList) {XWPFTable table = doc.getTables().get(0); // 获取第一个表格// 获取表格的模板行(假设表格的第一行是标题行,第二行为模板行)XWPFTableRow templateRow = table.getRow(1);// 添加新的行,并删除模板行for (Map<String, String> data : dataList) {XWPFTableRow newRow = table.createRow();// 手动创建每个单元格,并复制模板行的样式for (int i = 0; i < templateRow.getTableCells().size(); i++) {XWPFTableCell templateCell = templateRow.getCell(i);XWPFTableCell newCell = newRow.getCell(i);if (newCell == null) {newCell = newRow.createCell();}// 复制模板行单元格的样式,不复制内容copyCellStyleWithoutText(templateCell, newCell);// 填充数据switch (i) {case 0:newCell.setText(data.get("name"));break;case 1:newCell.setText(data.get("sex"));break;case 2:newCell.setText(data.get("age"));break;}}}// 删除模板行table.removeRow(1);}private void copyCellStyleWithoutText(XWPFTableCell sourceCell, XWPFTableCell targetCell) {// 复制单元格的样式,但不复制文本内容targetCell.getParagraphs().forEach(paragraph -> {XWPFParagraph sourceParagraph = sourceCell.getParagraphs().get(0);paragraph.setAlignment(sourceParagraph.getAlignment());paragraph.setVerticalAlignment(sourceParagraph.getVerticalAlignment());if (!sourceParagraph.getRuns().isEmpty()) {XWPFRun sourceRun = sourceParagraph.getRuns().get(0);XWPFRun targetRun = paragraph.createRun();targetRun.setBold(sourceRun.isBold());targetRun.setItalic(sourceRun.isItalic());targetRun.setFontFamily(sourceRun.getFontFamily());targetRun.setFontSize(sourceRun.getFontSize());}});// 复制单元格背景色等样式targetCell.setColor(sourceCell.getColor());targetCell.setVerticalAlignment(sourceCell.getVerticalAlignment());}
}
word模板

调用接口后生成的新文件

相关文章:
使用Apache POI和POI-OOXML实现word模板文档自动填充功能
最近接到一个新的需求,用户创建好模板文件保存到模板库,然后使用在线文档编辑器打开模板时,将系统数据填充到模板文件并生成新的word文件,然后在线编辑,研究使用Apache POI和POI-OOXML实现了这个功能。 Maven依赖 <…...
【HarmonyOS NEXT星河版开发学习】综合测试案例-各平台评论部分
目录 前言 功能展示 整体页面布局 最新和最热 写评论 点赞功能 界面构建 初始数据的准备 列表项部分的渲染 底部区域 index部分 知识点概述 List组件 List组件简介 ListItem组件详解 ListItemGroup组件介绍 ForEach循环渲染 列表分割线设置 列表排列方向设…...
垂直行业数字化表现抢眼 亚信科技全年利润展望乐观
大数据产业创新服务媒体 ——聚焦数据 改变商业 2024年8月14日,亚信科技控股有限公司(股票代码:01675.HK)公布了公司截至2024年6月30日的中期业绩。 财报数据显示,2024年上半年,亚信科技的营业收入为人民币…...
EmguCV学习笔记 VB.Net 4.1 颜色变换
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客 教程C#版本请访问:EmguCV学习笔记 C# 目录-CSD…...
【MySQL进阶之路】表结构的操作
目录 创建表 查看表 查看数据库有哪些表 查看表结构 查看表的详细信息 修改表 表的重命名 添加一列 修改某一列的属性 删除某一列 对列进行重命名 删除表 个人主页:东洛的克莱斯韦克-CSDN博客 【MySQL进阶之路】MySQL基础——从零认识MySQL-CSDN博客 创…...
3分钟搞定PDF转PPT!你一定要知道的3款转换神器!
在数字办公成为主流的当下,我们每天会收到各类基于数字化方式存储的办公文档,如PDF、PPT、Word、Excel文档等。 日常处理这些文档时,经常需要在不同格式的文档之间进行切换和转换,其中将PDF转换为PPT就是一个非常高频的需求&…...
【EasyExcel】导出excel-设置动态表头并导出数据
需求背景: 导出excel的设置某些表头动态导出(可以根据筛选条件或一些属性的数据量),方便导出后用户查看想看的信息。 一、技术选型: easyExcel的原生数据处理 二、方案设计: 根据EasyExcel支持的表头List<List<String>…...
深入探索 Elasticsearch 8:新特性与核心原理剖析(上)
深入探索 Elasticsearch 8:新特性与核心原理剖析 目录 一、引言 (二)版本 8 的重要意义 二、Elasticsearch 8 的新特性 三、Elasticsearch 的核心原理 一、引言 (一)Elasticsearch 简介 在大数据处理和搜索领域…...
瑜伽馆预约小程序,在线预约,提高商业价值
随着大众生活质量的提高,对休闲运动的关注逐渐加大,瑜伽作为一种身心放松、改善体态的运动,深受女性用户的喜爱。目前,各大瑜伽馆开始结合数字化,建立了新型的线上小程序,帮助大众快速预约体验瑜伽…...
Python--数据类型转换
在Python中,数据类型的转换是一个常见的操作,涉及将一种数据类型转换为另一种数据类型。Python提供了多种内置函数用于执行这种转换,如 int()、str()、float()、list()、tuple()、set()、dict() 等。下面详细讨论Python的基本数据类型及它们之…...
域控ntdsutil修改架构、域命名、PDC、RID、结构主机
#笔记记录# FSMO盒修改 1、提示访问特权不够,不能执行该操作,0x2098 清除缓存账号密码并修改新架构管理员账号密码即可。 背景:更替架构主机、域命名主机 C:\Windows\system32>ntdsutil ntdsutil: roles fsmo maintenance: ?? …...
解决 Swift 6 全局变量不能满足并发安全(concurrency-safe)读写的问题
概述 WWDC 24 终于在 Swift 十岁生日发布了全新的 Swift 6。这不仅意味着 Swift 进入了全新的“大”版本时代,而且 Swift 编译器终于做到了并发代码执行的“绝对安全”。 不过,从 Swift 5 一步迈入“新时代”的小伙伴们可能对新的并发检查有些许“水土不…...
迈入退休生活,全职开发ue独立游戏上架steam
决定退休了。算了算睡后收入,也可以达到每月一万一,正好可以养家糊口。 既然退休了,那就做些想做的事情,别人养花养草,而我打算开发独立游戏上架steam。 一,盘点下目前的技术体系。 1,图形学底…...
什么是光伏气象站——仁科测控
【仁科测控,品质保障】光伏气象站,这一专门为光伏发电系统设计的监测设备,其核心能力在于精确且实时地捕捉那些对光伏发电效率产生关键影响的气象因素。这些数据不仅为评估光伏电站的发电性能提供了重要依据,更是优化运维…...
webshell免杀--免杀入门
前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要整理webshell免杀的一些基础思路 入门级,不是很深入,主要是整理相关概念 免杀对象 1.各类杀毒软件 类似360,火绒等,查杀己方webshell的软件。 2.各类流量…...
Linux---02---系统目录及文件基本操作命令
课程回顾 操作系统 虚拟机安装 本章重点 Linux系统目录结构 常用命令 熟练区分Linux下各层目录的作用 熟练掌握Linux的常用命令(文件命令、时间命令等) 一、Linux系统目录结构 1.1 目录结构 /: 根目录,一般根目录下只存放…...
CSP-J/S第一轮初赛模拟赛试题
本模拟试题为本人自创,由于发布在 LG 所以就直接放入链接。 非经允许,不得转载。 本套模拟题只供大家练习使用,不保证难度与真实 CSP-J/S 完全符合。 本模拟赛为专业CSP类型的模拟赛,不存在错题、超出知识的题目。 CSP-J/S 20…...
LangGPT结构化提示词
LangGPT是Language For GPT-like LLMs的简称,中文名为结构化提示词,LangGPT是一个帮助你编写高质量提示词的工具,理论基础是我们提出的一套模块化、标准化的提斯提编写方法论——结构化提示词。我们希望揭开提示工程的神秘面纱,为…...
如何为个人网站更换ssl证书
关键步骤 1,确认服务器类型并下载对应证书(这个超级简单,阿里云现在可以下3月免费的); 2,本文以nginx服务为例,主打的就是一个简单且快速让你搞清楚实操流程; linux命令 ps-ef|gr…...
RabbitMQ-消息队列延迟队列一
1、安装rabbitmq 怎么安装rabbitmq请查看之前课程,如果已经安装,请略过此步。 2、创建vendor文件夹或是直接采用PHP框架 mkdir vendor 3、进入文件 cd vendor 4、安装php扩展 composer require php-amqplib/php-amqplib 5、进入上级创建dead文件…...
从Provisional headers are shown到证书过期:uniapp请求无响应的幕后真相
从Provisional headers are shown到证书过期:uniapp请求无响应的深度排查指南 当你正在调试一个运行良好的uniapp项目时,突然发现所有网络请求在真机上毫无征兆地停止工作——没有错误提示,没有响应数据,只有开发者工具中冷冰冰的…...
英飞凌IPOSIM在线仿真平台保姆级入门:从注册到生成第一份功率损耗报告
英飞凌IPOSIM在线仿真平台零基础实战指南:三步完成功率模块热评估 在电力电子设计领域,精确的功率损耗计算往往决定着系统可靠性。我曾见过一个光伏逆变器项目因热设计失误导致批量返修,仅仅因为工程师低估了IGBT模块在高温环境下的导通损耗。…...
FLUX.1-dev实战教程:像素幻梦中多LoRA叠加与风格混合生成技巧
FLUX.1-dev实战教程:像素幻梦中多LoRA叠加与风格混合生成技巧 1. 像素幻梦工坊简介 Pixel Dream Workshop(像素幻梦工坊)是基于FLUX.1-dev扩散模型构建的专业像素艺术生成工具。与传统AI绘图工具不同,它专为像素艺术创作优化&am…...
实时交易系统架构设计:从事件驱动到向量化框架的终极指南
实时交易系统架构设计:从事件驱动到向量化框架的终极指南 【免费下载链接】awesome-systematic-trading A curated list of insanely awesome libraries, packages and resources for systematic trading. Crypto, Stock, Futures, Options, CFDs, FX, and more | 量…...
从手忙脚乱到从容不迫:DouyinLiveRecorder如何用智能代理池解决多平台直播录制难题
从手忙脚乱到从容不迫:DouyinLiveRecorder如何用智能代理池解决多平台直播录制难题 【免费下载链接】DouyinLiveRecorder 项目地址: https://gitcode.com/gh_mirrors/do/DouyinLiveRecorder 你是否曾经为了录制不同平台的直播内容而疲于奔命?当抖…...
OpenClaw多模态飞书助手:Qwen3-VL:30B实战指南
OpenClaw多模态飞书助手:Qwen3-VL:30B实战指南 1. 为什么我们需要多模态飞书助手? 去年夏天,我负责一个跨部门协作项目时,每天要处理上百条飞书消息和几十份文档。最头疼的是同事发来的截图——有时是数据图表,有时是…...
Java 设计模式・策略模式篇:从思想到代码实现
一、行为型模式 在面向对象的世界里,如何优雅地组织对象间的交互、分配职责,是每一位开发者都会反复思考的问题。直接硬编码交互逻辑固然简单,但当业务复杂度上升、对象协作关系变得错综复杂时,这种方式就会让代码变得僵化、难以…...
降AIGC哪家强?2026零成本保姆级教程:DeepSeek/Kimi/豆包专属降重指令实测与差异解析
很多时候大学生写论文逻辑太严谨、话术太规范,反而会导致AI率过高,且一旦AI率过高,轻则退回重改,重则取消答辩资格,这后果谁都担不起。 为了帮大家有效降低aigc率,这周我专门针对目前市面上最主流的三款大…...
3类被90%开发者忽略的农田图像噪声——基于ISO 17202-2标准的Python去噪实战手册
第一章:农田图像噪声的认知革命与ISO 17202-2标准全景解读传统农业视觉系统长期将图像噪声视为需“压制”的干扰项,而ISO 17202-2:2023《农业遥感图像质量评估—第2部分:噪声建模与语义敏感性分级》首次确立噪声作为农田场景的**可解释性特征…...
揭秘联发科设备Bootloader解锁:mtkclient-gui实战指南与深度解析
揭秘联发科设备Bootloader解锁:mtkclient-gui实战指南与深度解析 【免费下载链接】mtkclient-gui GUI tool for unlocking bootloader and bypassing authorization on Mediatek devices (Not maintained anymore) 项目地址: https://gitcode.com/gh_mirrors/mt/m…...
