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

Java后端使用XWPFDocument生成word文档,踩坑

以下都是借鉴网上内容:
环境 纯后端, java, spring项目 maven管理.

maven内容:

		<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.16</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>3.16</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>ooxml-schemas</artifactId><version>1.3</version></dependency>

运行时候如果报错: XmlOptions.setEntityExpansionLimit ( ) 方法找不到,那就是xmlbeans版本太低 升级以下:
就可以解决找不到方法:问题 如果没报错 ( 就把改依赖忽略),

 	<dependency><groupId>org.apache.xmlbeans</groupId><artifactId>xmlbeans</artifactId><version>3.1.0</version></dependency>

代码如下 工具类一 :

package com.bsoft.hesp.utils.word;import java.util.*;import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;public class WordExportUtil {private WordExportUtil() {}/*** 替换文档中段落文本** @param document docx解析对象* @param textMap  需要替换的信息集合*/public static void changeParagraphText(XWPFDocument document, Map<String, String> textMap) {//获取段落集合List<XWPFParagraph> paragraphs = document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {//判断此段落是否需要进行替换String text = paragraph.getText();if (checkText(text)) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {//替换模板原来位置String textValue = changeValue(run.toString(), textMap);if (run.toString().toLowerCase().indexOf("checkbox_") != -1) {// 复选框填充值run.setFontFamily("SimSun");String[] tArr = textValue.split("@@@");for (int i = 0; i < tArr.length; i++) {if (i == 0) {run.setText(tArr[i], 0);} else {run.setText(tArr[i]);}if (i != tArr.length - 1) {run.addBreak();//换行}}} else {run.setText(textValue, 0);}}}}}/*** 复制表头 插入行数据,这里样式和表头一样** @param document    docx解析对象* @param tableList   需要插入数据集合*                    tableIndex表格索引,在word表格对象集合中是第几个表格,从0开始* @param headerIndex 表头的行索引,从0开始*/public static void copyHeaderInsertText(XWPFDocument document, List<Map<String, String>> tableList, String[] fields, int tableindex, int headerIndex) {if (null == tableList || null == fields) {return;}//获取表格对象集合List<XWPFTable> tables = document.getTables();XWPFTableRow copyRow = tables.get(tableindex).getRow(headerIndex);List<XWPFTableCell> cellList = copyRow.getTableCells();if (null == cellList) {return;}//遍历要添加的数据的listfor (int i = 0; i < tableList.size(); i++) {//插入一行XWPFTableRow targetRow = tables.get(tableindex).insertNewTableRow(headerIndex + i);//复制行属性targetRow.getCtRow().setTrPr(copyRow.getCtRow().getTrPr());Map<String, String> map = tableList.get(i);// 字段匹配后,插入单元格并赋值for (String field : fields) {int idx = 0;for (Map.Entry<String, String> entry : map.entrySet()) {if (!field.equals(entry.getKey())) continue;XWPFTableCell sourceCell = cellList.get(idx);//插入一个单元格XWPFTableCell targetCell = targetRow.addNewTableCell();//复制列属性targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());//targetCell.setText(entry.getValue());/** XWPFTableCell 无法直接设置字体样式,故换一种方式 **///获取 XWPFTableCell 的CTTcCTTc ctTc = targetCell.getCTTc();//获取 CTPCTP ctP = (ctTc.sizeOfPArray() == 0) ? ctTc.addNewP() : ctTc.getPArray(0);//getParagraph(ctP) 获取 XWPFParagraphXWPFParagraph par = targetCell.getParagraph(ctP);//XWPFRun   设置格式XWPFRun run = par.createRun();String textValue = entry.getValue();// 复选框填充值if (field.toLowerCase().indexOf("checkbox_") != -1) {run.setFontFamily("SimSun");String[] tArr = textValue.split("@@@");for (int j = 0; j < tArr.length; j++) {if (j == 0) {run.setText(tArr[j], 0);} else {run.setText(tArr[j]);}if (j != tArr.length - 1) {run.addBreak();//换行}}} else {run.setText(textValue, 0);}idx++;};}}if (tableList.size() > 0) {List<XWPFTableRow> rows = tables.get(tableindex).getRows();int rowLength = rows.size();deleteTable(tables.get(tableindex), tableList.size() + headerIndex, rowLength);}}/*** 删除表格行** @param table     表格对象* @param fromIndex 从第几行,从0开始* @param toIndex   到第几行,从0开始*/public static void deleteTable(XWPFTable table, int fromIndex, int toIndex) {for (int i = fromIndex; i < toIndex; i++) {table.removeRow(fromIndex);}}/*** 替换表格对象方法** @param document docx解析对象* @param textMap  需要替换的信息集合*/public static void changeTableText(XWPFDocument document, Map<String, String> textMap) {//获取表格对象集合List<XWPFTable> tables = document.getTables();for (int i = 0; i < tables.size(); i++) {//只处理行数大于等于2的表格XWPFTable table = tables.get(i);/*if (table.getRows().size() > 1) {//判断表格是需要替换还是需要插入,判断逻辑有$为替换if (checkText(table.getText())) {List<XWPFTableRow> rows = table.getRows();//遍历表格,并替换模板eachTable(rows, textMap);}}*///判断表格是需要替换还是需要插入,判断逻辑有$为替换if (checkText(table.getText())) {List<XWPFTableRow> rows = table.getRows();//遍历表格,并替换模板eachTable(rows, textMap);}}}/*** 遍历表格,并替换模板** @param rows    表格行对象* @param textMap 需要替换的信息集合*/public static void eachTable(List<XWPFTableRow> rows, Map<String, String> textMap) {for (XWPFTableRow row : rows) {List<XWPFTableCell> cells = row.getTableCells();for (XWPFTableCell cell : cells) {//判断单元格是否需要替换if (checkText(cell.getText())) {List<XWPFParagraph> paragraphs = cell.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {fillCheckBox(run, textMap);}}}}}}public static void fillCheckBox(XWPFRun run, Map<String, String> textMap) {String textValue = changeValue(run.toString(), textMap);if (run.toString().toLowerCase().indexOf("checkbox_") != -1) {// 复选框填充值run.setFontFamily("SimSun");String[] tArr = textValue.split("@@@");for (int i = 0; i < tArr.length; i++) {if (i == 0) {run.setText(tArr[i], 0);} else {run.setText(tArr[i]);}/*if (i != tArr.length - 1) {run.addBreak();//换行}*/}} else {run.setText(textValue, 0);}}/*** 匹配传入信息集合与模板** @param value   模板需要替换的区域* @param textMap 传入信息集合* @return 模板需要替换区域信息集合对应值*/public static String changeValue(String value, Map<String, String> textMap) {Set<Map.Entry<String, String>> textSets = textMap.entrySet();for (Map.Entry<String, String> textSet : textSets) {//匹配模板与替换值 格式${key}String key = "${" + textSet.getKey() + "}";if (value.indexOf(key) != -1) {value = textSet.getValue();}}//模板未匹配到区域替换为空if (checkText(value)) {value = "";}return value;}/*** 判断文本中是否包含$** @param text 文本* @return 包含返回true, 不包含返回false*/public static boolean checkText(String text) {boolean check = false;if (text.indexOf("$") != -1) {check = true;}return check;}
}
package com.bsoft.hesp.utils.word;import org.apache.http.HttpHeaders;
import org.apache.poi.xwpf.usermodel.XWPFDocument;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;/*** Author: * Date: 2023/11/27 15:05**/
public class WordGenerate {/*** word生成* @throws FileNotFoundException*/public static void generateWord(List<Map<String, String>> list, Map<String, String> fileAddress, HttpServletResponse response) throws FileNotFoundException {XWPFDocument document = null;try {for (Map<String, String> tableMap : list) {String classpath = WordGenerate.class.getResource("").getPath();File f = new File(classpath+"/模板20231124.docx");FileInputStream fileInputStream = new FileInputStream(new File(f.getPath()));FileOutputStream fileOutStream = new FileOutputStream("E:\\" + tableMap.get("fileName") + ".docx");try {/**解析docx模板并获取document对象**/document = new XWPFDocument(fileInputStream);/**替换docx table中文本字段**/WordExportUtil.changeTableText(document, tableMap);document.write(fileOutStream);} catch (IOException e) {e.printStackTrace();} finally {if (document != null) {try {document.close();} catch (IOException e) {e.printStackTrace();}}if (null != fileInputStream) {try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}if (null != fileOutStream) {try {fileOutStream.close();} catch (IOException e) {e.printStackTrace();}}}}} catch (Exception e) {e.printStackTrace();}}
}

相关文章:

Java后端使用XWPFDocument生成word文档,踩坑

以下都是借鉴网上内容: 环境 纯后端, java, spring项目 maven管理. maven内容: <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.16</version></dependency><dependency>…...

asp.net core HttpContextAccessor类

在 ASP.NET Core 中 &#xff0c;HttpContextAccessor 是一个用于访问当前 HTTP 请求的工具类。它通常用于在应用程序中获取当前 HTTP 请求的上下文信息&#xff0c;例如请求的路由、头部信息、用户身份验证状态等。 HttpContextAccessor 类通常在需要访问当前 HTTP 请求上下文…...

微服务--04--SpringCloudGateway 网关

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.网关路由1.1 认识网关在SpringCloud当中&#xff0c;提供了两种网关实现方案&#xff1a; 1.2.快速入门1.3.路由过滤 2.网关登录校验2.1.鉴权思路分析2.2.网关过滤…...

Java程序连接 nacos集群

我们在bootstrap.yml文件里可以直接连一个nacos集群的. 架构如下 没错,我们程序直连的是通过Nginx的,利用nginx的反向代理来做到连接nacos集群. 我们先把nginx的配置贴上来 upstream cluster{server 127.0.0.1:8848;server 127.0.0.1:8849;server 127.0.0.1:8850; }server{l…...

【深度学习】参数优化和训练技巧

寻找合适的学习率(learning rate) 学习率是一个非常非常重要的超参数&#xff0c;这个参数呢&#xff0c;面对不同规模、不同batch-size、不同优化方式、不同数据集&#xff0c;其最合适的值都是不确定的&#xff0c;我们无法光凭经验来准确地确定lr的值&#xff0c;我们唯一可…...

CeresPCL 曲线拟合之三次多项式

文章目录 一、简介2.1 实现步骤二、实现代码三、实现效果参考资料一、简介 2.1 实现步骤 (1)构建代价函数。假设我们得到了一组数据,也知晓该数据是用曲线方程: y = a x 3 + b x 2 + c x +...

小白备战蓝桥杯:Java基础语法

一、注释 IDEA注释快捷键&#xff1a;Ctrl / 单行注释&#xff1a; //注释信息 多行注释&#xff1a; /* 注释信息 */ 二、字面量 常用数据&#xff1a;整数、小数、字符串&#xff08;双引号&#xff09;、字符&#xff08;单引号&#xff09;、布尔值&#xff08;tr…...

C#面向对象

过程类似函数只能执行没有返回值 函数不仅能执行&#xff0c;还可以返回结果 1、面向过程 a 把完成某一需求的所有步骤 从头到尾 逐步实现 b 根据开发需求&#xff0c;将某些 功能独立 的代码 封装 成一个又一个 函数 c 最后完成的代码就是顺序的调用不同的函数 特点 1、…...

智能优化算法应用:基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝙蝠算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…...

【栈和队列(1)(逆波兰表达式)】

文章目录 前言什么是栈(Stack)栈方法栈的模拟实现链表也可以实现栈逆波兰表达式逆波兰表达式在栈中怎么使用 前言 什么是栈(Stack) 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0…...

Blazor Table 实现获取当前选中行的功能

这里需要使用到OnClickRowCallBack事件 后台使用案例...

Flask Echarts 实现历史图形查询

Flask前后端数据动态交互涉及用户界面与服务器之间的灵活数据传递。用户界面使用ECharts图形库实时渲染数据。它提供了丰富多彩、交互性强的图表和地图&#xff0c;能够在网页上直观、生动地展示数据。ECharts支持各种常见的图表类型&#xff0c;包括折线图、柱状图、饼图、散点…...

【漫谈】信创

近些年来&#xff0c;自主创新绝对是高频词汇。 以往是供应链、芯片领域&#xff0c;现在终于到了信息领域。 近期&#xff0c;从上至下、从中央到地方、从政府到国企&#xff0c;各层面、各行业、各领域都在提及“信创”。 信创是个大工程&#xff0c;从计算机通用处理器、…...

linux wget --no-check-certificate

如果您希望每次使用wget命令时都跳过SSL证书检查&#xff0c;可以将–no-check-certificate参数添加到wget的默认配置文件中。 请按照以下步骤进行操作&#xff1a; vi ~/.wgetrc# 插入内容 check_certificate off保存并关闭文件。 现在&#xff0c;wget命令将在每次使用时自…...

mysql命令行连接数据库

有时项目连接不上数据库&#xff0c;报错鉴权失败&#xff0c;先用mysql工具连接下&#xff0c;容易发现问题。 直接输入mysql看是否已安装&#xff0c;如果没有就安装下。 # 注&#xff1a;直接mysql就行&#xff0c;不用-cli也不用-client&#xff0c;也不用-server&#xf…...

计算机丢失vcomp140.dll是什么意思,如何解决与修复(附教程)

vcomp140.dll缺失的5种解决方法以及vcomp140.dll缺失原因 引言&#xff1a; 在日常使用电脑的过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“vcomp140.dll缺失”。这个错误提示通常出现在运行某些程序或游戏时&#xff0c;给使用者带来了困扰。本文…...

基于SSM实现的叮当书城

一、系统架构 前端&#xff1a;jsp | jquery | layui 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.7以上 | mysql | maven 二、代码与数据库 三、功能介绍 01. 系统首页 02. 商品分类 03. 热销 04. 新品 05. 注册 06. 登录 07. 购物车 08. 后台-首页 …...

python基础练习题库实验5

文章目录 题目1代码实验结果题目2代码实验结果题目3代码实验结果![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6058fb4b66994aed838f920f7fe75706.png)题目4代码实验结果题目总结题目1 编写一个程序,使用while循环语句和字符串格式显示以下精确输出。 例如: …...

JS手写instanceof(内含源码与详解)

前言 本文主要讲解JavaScript如何手写一个简易的instanceof,从而实现数据类型判断的作用.那么好,本文正式开始. instanceof作用 instanceOf的作用就是用来判断JavaScript中的数据类型是否是开发所输入的那种, 语法格式:obj instanceof objtype 左侧就是要判断的数据,而右侧就…...

无公网IP下,如何实现公网远程访问MongoDB文件数据库

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 前言 MongoDB是一个基于分布式文件存储的数…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化

iOS 应用的发布流程一直是开发链路中最“苹果味”的环节&#xff1a;强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说&#xff0c;这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发&#xff08;例如 Flutter、React Na…...