java 解析word模板(2024-01-25)
本文主要功能是解析word模板
这是一个word解析类,因为我做的系统用到了而且没有可用的帮助类,只能自己写。之前的实现方式是freemarker 模板解析。但是这次要求用poi不在使用freemarker。实现功能比较少,主要是满足开发需求即可,没有实现其它功能。实现功能如下:
1、word内文本内容解析
2、word内表格内容解析
3、word内图片内容解析
4、word脚注内容解析
功能实现的比较匆忙没有好好设计,如果可以将图标,图片,脚注等设置为实体类,便于配置管理。
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Base64;
import java.util.List;
import java.util.Properties;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFFootnote;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
import org.springframework.util.PropertyPlaceholderHelper;
import com.alibaba.cloud.commons.lang.StringUtils;
/**
* 通过word模板生成新的word工具类
**
*/
public class WordUtil {
public static final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}");
/**
* 根据模板生成新word文档 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
*
* @param textMap 需要替换的信息集合
* @return 成功返回true,失败返回false
*/
public static void changWord(InputStream inputStream, Properties properties, int height, int width) {
// InputStream in = null;
try {
// 获取docx解析对象
XWPFDocument document = new XWPFDocument(inputStream);
// 解析替换文本段落对象
WordUtil.changeText(document, properties);
// 解析替换表格对象
WordUtil.changeTable(document, properties);
// 替换文本中的图片
WordUtil.changePicture(document, properties, height, width);
// 脚注/尾注解析 footnote
WordUtil.changeFootNote(document, properties);
File file = new File("I://实体文件.docx");
FileOutputStream stream = new FileOutputStream(file);
document.write(stream);
stream.close();
document.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 尾注解析
*
* @param document
* @param properties
*/
public static void changeFootNote(XWPFDocument document, Properties properties) {
List<XWPFFootnote> footNoteList = document.getFootnotes();
for (XWPFFootnote footnote : footNoteList) {
List<XWPFParagraph> paragraphs = footnote.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
String text = paragraph.getText();
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
String key = keyParam(runs);
for (XWPFRun run : runs) {
run.setText("", 0);
}
// 替换模板原来位置
String value = changeValue(key, properties);
// 字符串中有可能是图片转换的字符串
if (StringUtils.isNotEmpty(value)) {
runs.get(0).setText(value, 0);
}
}
}
}
}
/***
* 指定替换模板中的图片
*
* @param document
* @param filePath
* @param height
* @param width
*/
public static void changePicture(XWPFDocument document, Properties properties, Integer height, Integer width) {
// 获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
// 判断此段落时候需要进行替换
String text = paragraph.getText();
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
String key = keyParam(runs);
for (XWPFRun run : runs) {
// 字符串中有可能是图片转换的字符串
String value = changeValue(key, properties);
if (value.startsWith("data:image")) {
byte[] imageBytes = Base64.getDecoder().decode(value.split(",")[1]); // 获取Base64编码后的图像数据部分
try(ByteArrayInputStream in = new ByteArrayInputStream(imageBytes); ){// 创建ByteArrayInputStream对象
// 添加图片
XWPFPicture xwpfPicture = run.addPicture(in, XWPFDocument.PICTURE_TYPE_JPEG, "图片1.jpg",
Units.toEMU(width), Units.toEMU(height));
// 为图片添加边框
xwpfPicture.getCTPicture().getSpPr().addNewLn().addNewSolidFill().addNewSchemeClr()
.setVal(STSchemeColorVal.Enum.forString("tx1"));
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
}
}
public static String keyParam(List<XWPFRun> runs) {
if (runs.isEmpty()) {
return "";
}
StringBuffer st = new StringBuffer();
// 转换为一个字符串 [${E_002, 1, }${E_002, 2, }${E_002, 3, }]
for (XWPFRun run : runs) {
st.append(run.text());
}
return st.toString().replace(",", "");
}
/**
* 替换段落文本
*
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
public static void changeText(XWPFDocument document, Properties properties) {
// 获取段落集合
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 value = changeValue(run.toString(), properties);
// 字符串中有可能是图片转换的字符串
if (StringUtils.isNotEmpty(value) && !value.startsWith("data:image")) {
run.setText(value, 0);
}
}
}
}
}
/**
* 替换表格对象方法
*
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
public static void changeTable(XWPFDocument document, Properties properties) {
// 获取表格对象集合
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, properties);
}
}
}
}
/**
* 遍历表格
*
* @param rows 表格行对象
* @param textMap 需要替换的信息集合
*/
public static void eachTable(List<XWPFTableRow> rows, Properties properties) {
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
// 判断单元格是否需要替换
if (checkText(cell.getText())) {
// 基本一个单元格,都是size=1,如果预防意外,可以增加判断,或者添加循环
List<XWPFParagraph> paragraphs = cell.getParagraphs();
// System.out.println(String.format("text:%s,paragraphs:%d",cell.getText(),
// paragraphs.size()));
// for (XWPFParagraph paragraph : paragraphs) {
// List<XWPFRun> runs = paragraph.getRuns();
// 替换模板原来位置
XWPRunValue(paragraphs.get(0).getRuns(), properties);
// }
}
}
}
}
/**
* 这个方法是一次处理一个单元格,一个单元格内,被解析成了 XWPFRun, 只给第一个 XWPFRun赋值即可,其它都赋值""
*
* @param runs
* @param textMap
*/
public static void XWPRunValue(List<XWPFRun> runs, Properties properties) {
if (runs.size() == 1) {
runs.get(0).setText(changeValue(runs.get(0).toString(), properties), 0);
return;
}
StringBuffer st = new StringBuffer();
// 转换为一个字符串 [${E_002, 1, }${E_002, 2, }${E_002, 3, }]
for (XWPFRun run : runs) {
//
st.append(run.text());
run.setText("", 0);
}
String value = st.toString().replace(",", "");
value = changeValue(value, properties);
// 一次性替换全部的值
runs.get(0).setText(value, 0);
}
/**
* 判断文本中时候包含$
*
* @param text 文本
* @return 包含返回true,不包含返回false
*/
public static boolean checkText(String text) {
return (text.indexOf("$") != -1);
}
/**
* 匹配传入信息集合与模板
*
* @param value 模板需要替换的区域
* @param textMap 传入信息集合
* @return 模板需要替换区域信息集合对应值
*/
public static String changeValue(String value, Properties properties) {
if (!checkText(value)) {
return value;
}
return helper.replacePlaceholders(value, properties);
}
public static void main(String[] args) throws Exception {
// 从FTP读取文件模板
InputStream is = new FileInputStream(new File("I://模板文件.docx"));
// 填充文本和表格需要替换的数据
Properties properties = new Properties();
properties.put("E_0001", "2000年01月01日");
properties.put("E_0002", "第一行");
properties.put("E_0003", "脚注解析异常");
// 图片字符串
properties.put("P01", "data:image/jpg;base64,"+"图片转换的字符串") ;
WordUtil.changWord(is, properties, 140, 400);
}
}
相关文章:
java 解析word模板(2024-01-25)
本文主要功能是解析word模板 这是一个word解析类,因为我做的系统用到了而且没有可用的帮助类,只能自己写。之前的实现方式是freemarker 模板解析。但是这次要求用poi不在使用freemarker。实现功能比较少,主要是满足开发需求即可,没…...
flutter-相关个人记录
1、flutter 安卓打包打包报错 flutter build apk -v --no-tree-shake-icons 2、获取华为指纹证书命令 keytool -list -v -keystore ***.jks 3、IOS项目中私有方法查找隐藏文件中 1、cd 项目目录地址 2、grep -r xerbla. "xerbla"为需要查找的关键字 3…...
互斥锁/读写锁(Linux)
一、互斥锁 临界资源概念: 不能同时访问的资源,比如写文件,只能由一个线程写,同时写会写乱。 比如外设打印机,打印的时候只能由一个程序使用。 外设基本上都是不能共享的资源。 生活中比如卫生间,同一…...
Jackson序列化Bean额外属性附加--@JsonAnyGetter、@JsonUnwrapped用户
1. 场景 有一项工作,需要将数据从一个服务S中读取出来(得到的是一个JSON),将数据解析转换以后构造成一个数组的类型A的对象,写入到一个服务T中。 A.class Data public class A {String f0 ;String f1 ; }在发现需要…...
排序算法——冒泡排序算法详解
冒泡排序算法详解 1.引言2.算法概览2.1输入处理2.2核心算法步骤2.3数据结构2.4复杂度分析 3.算法优化4.边界条件和异常处理5.实验和测试6.应用和扩展7.代码示例8.总结 1.引言 冒泡排序是一种简单而直观的比较排序算法,它通过多次遍历数组,比较相邻元素并…...
宋仕强论道之华强北的缺货潮(十六)
始于2019年缺货潮让华强北又生产一大批亿万富翁,缺货的原因主要是:首先,疫情封控导致大量白领在家远程办公,需要购买电脑、打印机等办公设备,同时孩子们也要在家上网课,进一步增加对电子智能终端产品的需求…...
登录注册页面
前提:基于element-ui环境 模态登录组件 分析Login.vue <template><div class"login"><span click"handleClose">X</span></div> </template><script> export default {name: "Login",m…...
视频美颜SDK详解:动态贴纸技术的前沿探索
当下,美颜SDK的动态贴纸技术作为视频美颜的独特亮点,吸引了越来越多开发者和用户的关注。 一、技术详解 动态贴纸技术是视频美颜SDK中的一项创新性功能,它通过在实时视频中添加各种动态效果,为用户提供更加生动有趣的拍摄体验。…...
vue3 实现上传图片裁剪
在线的例子以及代码,请点击访问链接...
flink1.18 广播流 The Broadcast State Pattern 官方案例scala版本
对应官网 https://nightlies.apache.org/flink/flink-docs-master/docs/dev/datastream/fault-tolerance/broadcast_state/ 测试数据 * 广播流 官方案例 scala版本* 广播状态* https://nightlies.apache.org/flink/flink-docs-master/docs/dev/datastream/fault-tolerance…...
vueRouter中scrollBehavior实现滚动固定位置
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。 注意: 这个功能只在 HTML5 h…...
解决WinForms跨线程操作控件的问题
解决WinForms跨线程操作控件的问题 介绍 在构建Windows窗体应用程序时,我们通常会遇到需要从非UI线程更新UI元素的场景。由于WinForms控件并不是线程安全的,直接这样做会抛出一个异常:“控件’control name’是从其他线程创建的,…...
从零开始:Git 上传与使用指南
Git 是一种非常强大的版本控制系统,它可以帮助您在多人协作开发项目中更好地管理代码版本,并确保每个团队成员都能及时地获取最新的代码更改。在使用 Git 进行版本控制之前,您需要先进行一些设置,以确保您的代码能够顺利地与远程仓…...
Docker compose部署Golang服务
Docker Compose 部署 在使用docker部署时,除了使用--link的方式来关联容器之外,还可以使用 docker compose 运行多个容器。 本文以项目:https://github.com/johncxf/go-api 为例。 定义 Dockerfile 我这里用于区分默认 Dockerfile 文件&a…...
Day36 435无重叠区间 763划分字母区间
435 无重叠区间 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于它的起点。 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。 本题与上一题类似: 如果按照左…...
【Servlet】如何编写第一个Servlet程序
个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Servlet】 本专栏旨在分享学习Servlet的一点学习心得,欢迎大家在评论区交流讨论💌 Servlet是Java编写的服务器端…...
读懂比特币—bitcoin代码分析(五)
今天的代码分析主要是 bitcoin/src/init.cpp 文件中的三个函数:AppInitSanityChecks、AppInitLockDataDirectory、AppInitInterfaces,下面我们来说明这三个函数是用来干什么的,并逐行解读函数代码,先贴出源代码如下: …...
uniapp使用uQRCode插件生成二维码的简单使用
最近在找移动端绘制二维码的问题 ,直接上代码 下载 weapp-qrcode.js(可以通过npm install weapp-qrcode --save 下载,之后把它父子到untils目录下) npm install weapp-qrcode --save在组件页面使用 <canvas id"couponQrcode" canvas-id&qu…...
【寒假每日一题·2024】AcWing 4965. 三国游戏(补)
文章目录 一、题目1、原题链接2、题目描述 二、解题报告1、思路分析2、时间复杂度3、代码详解 一、题目 1、原题链接 4965. 三国游戏 2、题目描述 二、解题报告 1、思路分析 思路参考y总:y总讲解视频 (1)题目中的获胜情况分为三种ÿ…...
docker 安装mongodb 数据库
1.拉取mongodb镜像 docker pull mongo2.创建文件夹 mkdir -p /home/mongo/conf/ mkdir -p /home/mongo/data/ mkdir -p /home/mongo/logs/3.新增mongod.conf文件 cd /home/mongo/conf && vi mongod.confmongod.conf文件内容: # 数据库文件存储位置 dbpa…...
【嵌入式Linux】Libmodbus RTU从源码到实战:基于i.MX6UL的工业通信移植指南
1. 为什么选择Libmodbus RTU在i.MX6UL上做工业通信? 在工业自动化领域,Modbus协议就像设备之间的"普通话",而RTU模式则是其中最省流量、最抗干扰的方言。我去年给一家工厂做设备改造时,发现他们的老式PLC和传感器清一色…...
大数据毕业设计 hadoop+spark+kafka+hive动漫推荐系统 动漫数据分析 可视化 漫画推荐
1、项目介绍 技术栈: Python语言、Django框架、SQLite数据库、Echarts可视化 、HTML、基于物品协同过滤推荐算法 (1)首页------不同类 型的动漫数据 (2)动漫类型饼图 (3)动漫收藏排名和不同国家…...
APK Editor Studio:从入门到精通的完整Android应用编辑指南
APK Editor Studio:从入门到精通的完整Android应用编辑指南 【免费下载链接】apk-editor-studio Powerful yet easy to use APK editor for PC and Mac. 项目地址: https://gitcode.com/gh_mirrors/ap/apk-editor-studio 在Android应用开发和逆向工程领域&am…...
3个高效能的核心功能:League-Toolkit开源工具效率提升指南
3个高效能的核心功能:League-Toolkit开源工具效率提升指南 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League-Too…...
GPStar Audio串口控制库:嵌入式多轨音频系统开发指南
1. GPStar Audio Serial Library 技术深度解析GPStar Audio Serial Library 是专为 GPStar Technologies 公司推出的 GPStar Audio 与 GPStar Audio XL 系列嵌入式音频播放器设计的串行通信控制库。该库并非通用音频驱动,而是针对特定硬件平台深度定制的、面向实时交…...
3D元器件库技术解析与工程应用指南
## 1. 3D元器件库技术解析与应用指南### 1.1 3D封装库的技术价值 在现代电子设计自动化(EDA)流程中,高质量的3D元器件库可显著提升设计效率。本套封装库包含1088个标准封装模型,涵盖电阻器、电容器、接线端子、IC芯片、晶振等常见电子元件,所…...
三相桥式整流电路有源逆变状态的研究:基于Matlab仿真的直流发电机电动系统电能流转关系分析
三相桥式整流电路有源逆变状态 Matlab仿真可写报告 直流发电机电动系统入手,研究电能流转关系,再转入变流器分析交流和直流电之间流转,掌握有源逆变条件。玩过直流电机调速的朋友可能遇到过这样的情况:明明在减速状态,…...
Android音频输出流实战:从AudioFlinger到HAL层的完整调用链解析
Android音频输出流深度解析:从框架设计到硬件交互 1. Android音频系统架构概览 Android音频子系统采用分层设计,每一层都有明确的职责划分。理解这个架构是分析音频输出流的基础。 核心层级结构: 应用层:通过AudioTrack、MediaPla…...
3步彻底解决Umi-OCR Rapid版本HTTP服务无响应问题:参数配置完全指南
3步彻底解决Umi-OCR Rapid版本HTTP服务无响应问题:参数配置完全指南 【免费下载链接】Umi-OCR Umi-OCR: 这是一个免费、开源、可批量处理的离线OCR软件,适用于Windows系统,支持截图OCR、批量OCR、二维码识别等功能。 项目地址: https://git…...
益达App:5分钟打造你的个性化跨平台媒体中心
益达App:5分钟打造你的个性化跨平台媒体中心 【免费下载链接】yidaRule 益达规则仓库 项目地址: https://gitcode.com/gh_mirrors/yi/yidaRule 在信息爆炸的时代,我们每天都要面对海量的媒体内容——视频、音频、小说、漫画分散在各个平台和网站中…...
