当前位置: 首页 > news >正文

使用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模板文档自动填充功能

最近接到一个新的需求&#xff0c;用户创建好模板文件保存到模板库&#xff0c;然后使用在线文档编辑器打开模板时&#xff0c;将系统数据填充到模板文件并生成新的word文件&#xff0c;然后在线编辑&#xff0c;研究使用Apache POI和POI-OOXML实现了这个功能。 Maven依赖 <…...

【HarmonyOS NEXT星河版开发学习】综合测试案例-各平台评论部分

目录 前言 功能展示 整体页面布局 最新和最热 写评论 点赞功能 界面构建 初始数据的准备 列表项部分的渲染 底部区域 index部分 知识点概述 List组件 List组件简介 ListItem组件详解 ListItemGroup组件介绍 ForEach循环渲染 列表分割线设置 列表排列方向设…...

垂直行业数字化表现抢眼 亚信科技全年利润展望乐观

大数据产业创新服务媒体 ——聚焦数据 改变商业 2024年8月14日&#xff0c;亚信科技控股有限公司&#xff08;股票代码&#xff1a;01675.HK&#xff09;公布了公司截至2024年6月30日的中期业绩。 财报数据显示&#xff0c;2024年上半年&#xff0c;亚信科技的营业收入为人民币…...

EmguCV学习笔记 VB.Net 4.1 颜色变换

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 教程VB.net版本请访问&#xff1a;EmguCV学习笔记 VB.Net 目录-CSDN博客 教程C#版本请访问&#xff1a;EmguCV学习笔记 C# 目录-CSD…...

【MySQL进阶之路】表结构的操作

目录 创建表 查看表 查看数据库有哪些表 查看表结构 查看表的详细信息 修改表 表的重命名 添加一列 修改某一列的属性 删除某一列 对列进行重命名 删除表 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 【MySQL进阶之路】MySQL基础——从零认识MySQL-CSDN博客 创…...

3分钟搞定PDF转PPT!你一定要知道的3款转换神器!

在数字办公成为主流的当下&#xff0c;我们每天会收到各类基于数字化方式存储的办公文档&#xff0c;如PDF、PPT、Word、Excel文档等。 日常处理这些文档时&#xff0c;经常需要在不同格式的文档之间进行切换和转换&#xff0c;其中将PDF转换为PPT就是一个非常高频的需求&…...

【EasyExcel】导出excel-设置动态表头并导出数据

需求背景&#xff1a; 导出excel的设置某些表头动态导出(可以根据筛选条件或一些属性的数据量)&#xff0c;方便导出后用户查看想看的信息。 一、技术选型&#xff1a; easyExcel的原生数据处理 二、方案设计&#xff1a; 根据EasyExcel支持的表头List<List<String>…...

深入探索 Elasticsearch 8:新特性与核心原理剖析(上)

深入探索 Elasticsearch 8&#xff1a;新特性与核心原理剖析 目录 一、引言 &#xff08;二&#xff09;版本 8 的重要意义 二、Elasticsearch 8 的新特性 三、Elasticsearch 的核心原理 一、引言 &#xff08;一&#xff09;Elasticsearch 简介 在大数据处理和搜索领域…...

瑜伽馆预约小程序,在线预约,提高商业价值

随着大众生活质量的提高&#xff0c;对休闲运动的关注逐渐加大&#xff0c;瑜伽作为一种身心放松、改善体态的运动&#xff0c;深受女性用户的喜爱。目前&#xff0c;各大瑜伽馆开始结合数字化&#xff0c;建立了新型的线上小程序&#xff0c;帮助大众快速预约体验瑜伽&#xf…...

Python--数据类型转换

在Python中&#xff0c;数据类型的转换是一个常见的操作&#xff0c;涉及将一种数据类型转换为另一种数据类型。Python提供了多种内置函数用于执行这种转换&#xff0c;如 int()、str()、float()、list()、tuple()、set()、dict() 等。下面详细讨论Python的基本数据类型及它们之…...

域控ntdsutil修改架构、域命名、PDC、RID、结构主机

#笔记记录# FSMO盒修改 1、提示访问特权不够&#xff0c;不能执行该操作&#xff0c;0x2098 清除缓存账号密码并修改新架构管理员账号密码即可。 背景&#xff1a;更替架构主机、域命名主机 C:\Windows\system32>ntdsutil ntdsutil: roles fsmo maintenance: ?? …...

解决 Swift 6 全局变量不能满足并发安全(concurrency-safe)读写的问题

概述 WWDC 24 终于在 Swift 十岁生日发布了全新的 Swift 6。这不仅意味着 Swift 进入了全新的“大”版本时代&#xff0c;而且 Swift 编译器终于做到了并发代码执行的“绝对安全”。 不过&#xff0c;从 Swift 5 一步迈入“新时代”的小伙伴们可能对新的并发检查有些许“水土不…...

迈入退休生活,全职开发ue独立游戏上架steam

决定退休了。算了算睡后收入&#xff0c;也可以达到每月一万一&#xff0c;正好可以养家糊口。 既然退休了&#xff0c;那就做些想做的事情&#xff0c;别人养花养草&#xff0c;而我打算开发独立游戏上架steam。 一&#xff0c;盘点下目前的技术体系。 1&#xff0c;图形学底…...

什么是光伏气象站——仁科测控

【仁科测控&#xff0c;品质保障】光伏气象站&#xff0c;‌这一专门为光伏发电系统设计的监测设备&#xff0c;‌其核心能力在于精确且实时地捕捉那些对光伏发电效率产生关键影响的气象因素。‌这些数据不仅为评估光伏电站的发电性能提供了重要依据&#xff0c;‌更是优化运维…...

webshell免杀--免杀入门

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要整理webshell免杀的一些基础思路 入门级&#xff0c;不是很深入&#xff0c;主要是整理相关概念 免杀对象 1.各类杀毒软件 类似360&#xff0c;火绒等&#xff0c;查杀己方webshell的软件。 2.各类流量…...

Linux---02---系统目录及文件基本操作命令

课程回顾 操作系统 虚拟机安装 本章重点 Linux系统目录结构 常用命令 熟练区分Linux下各层目录的作用 熟练掌握Linux的常用命令&#xff08;文件命令、时间命令等&#xff09; 一、Linux系统目录结构 1.1 目录结构 /&#xff1a; 根目录&#xff0c;一般根目录下只存放…...

CSP-J/S第一轮初赛模拟赛试题

本模拟试题为本人自创&#xff0c;由于发布在 LG 所以就直接放入链接。 非经允许&#xff0c;不得转载。 本套模拟题只供大家练习使用&#xff0c;不保证难度与真实 CSP-J/S 完全符合。 本模拟赛为专业CSP类型的模拟赛&#xff0c;不存在错题、超出知识的题目。 CSP-J/S 20…...

LangGPT结构化提示词

LangGPT是Language For GPT-like LLMs的简称&#xff0c;中文名为结构化提示词&#xff0c;LangGPT是一个帮助你编写高质量提示词的工具&#xff0c;理论基础是我们提出的一套模块化、标准化的提斯提编写方法论——结构化提示词。我们希望揭开提示工程的神秘面纱&#xff0c;为…...

如何为个人网站更换ssl证书

关键步骤 1&#xff0c;确认服务器类型并下载对应证书&#xff08;这个超级简单&#xff0c;阿里云现在可以下3月免费的&#xff09;&#xff1b; 2&#xff0c;本文以nginx服务为例&#xff0c;主打的就是一个简单且快速让你搞清楚实操流程&#xff1b; linux命令 ps-ef|gr…...

RabbitMQ-消息队列延迟队列一

1、安装rabbitmq 怎么安装rabbitmq请查看之前课程&#xff0c;如果已经安装&#xff0c;请略过此步。 2、创建vendor文件夹或是直接采用PHP框架 mkdir vendor 3、进入文件 cd vendor 4、安装php扩展 composer require php-amqplib/php-amqplib 5、进入上级创建dead文件…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...