java操作doc——java利用Aspose.Words操作Word文档并动态设置单元格合并
在实际工作中,如果业务线是管理类项目或者存在大量报表需要导出的业务时,可以借助第三方插件实现其对应功能。
尤其是需要对word文档的动态操作或者模板数据的定向合并,使用Aspose会相对来说容易一些,而且相关文档比较完整,具体如何使用,请参看如下案例:
下图展示的是数据模板图1:
一、什么是Aspose?
官网地址:Aspose.Words 产品系列 | Aspose API 参考
文档处理是个人和专业人士必备的技能。然而,手动文档处理可能非常耗时且容易。Aspose.Words Java 文档处理教程提供了使用代码自动生成和管理文档的全面指南。
这些教程涵盖了广泛的主题,从基本的表格处理到高级文档合并和水印。Aspose.Words 教程注重实际实施,使开发人员能够高效地简化文档处理任务并提供定制的解决方案。
无论您是初学者还是经验丰富的开发人员,Aspose.Words Java 文档处理教程都可以帮助您将文档处理技能提升到更高的水平。
二、springboot项目如何引入?
1.获得许可
2.引入pom
<dependency><groupId>aspose</groupId><artifactId>words</artifactId><version>21.4.0</version><classifier>jdk17</classifier></dependency>
三、具体使用案例
1.集成授权
public static void setAuthLicense() {try {//根目录下的授权文件ClassPathResource resource = new ClassPathResource("授权文件路径");URL licenseFileNameURL = resource.getUrl();String savePath = java.net.URLDecoder.decode(licenseFileNameURL.toString(), "utf-8");String licenseFileName = savePath.toString().substring(6);if (new File(licenseFileName).exists()) {License license = new License();license.setLicense(licenseFileName);}} catch (Exception e) {e.printStackTrace();log.error("aspose 授权异常");}}
2.设置模板绑定字段
/*** 设置模板绑定字段** @param document 默认的文档对象* @param fieldname 模板key* @param fieldvalue 模板value* @throws Exception*/public static void mergeField(Document document, String fieldname,Object fieldvalue) throws Exception {document.getMailMerge().execute(new String[]{fieldname},new Object[]{fieldvalue});}
3.配置动态表格,主要用于集合遍历(数据列表展示)
public class ResultSetDataSource {public ResultSetDataSource(){}/*** 处理自定义的数据源* @param document 文档* @param tableStartFieldName tableStart的域名* @param fieldNames 列的域名数组* @param fieldValueArray 域值的数组* @throws Exception*/public void executeWithRegions(Document document, String tableStartFieldName, String[] fieldNames, String[][] fieldValueArray) throws Exception {java.sql.ResultSet resultSet = createCachedRowSet(fieldNames);int length = fieldValueArray.length;for(int i = 0; i < length;i ++){addRow(resultSet,fieldValueArray[i]);}com.aspose.words.net.System.Data.DataTable table = new com.aspose.words.net.System.Data.DataTable(resultSet, tableStartFieldName);document.getMailMerge().executeWithRegions(table);}public java.sql.ResultSet createCachedRowSet(String[] columnNames) throws Exception{RowSetMetaDataImpl metaData = new RowSetMetaDataImpl();metaData.setColumnCount(columnNames.length);for (int i = 0; i < columnNames.length; i++){metaData.setColumnName(i + 1, columnNames[i]);metaData.setColumnType(i + 1, java.sql.Types.VARCHAR);}CachedRowSet rowSet = RowSetProvider.newFactory().createCachedRowSet();rowSet.setMetaData(metaData);return rowSet;}public void addRow(java.sql.ResultSet resultSet, String[] values) throws Exception{resultSet.moveToInsertRow();for (int i = 0; i < values.length; i++) {resultSet.updateString(i + 1, values[i]);}resultSet.insertRow();resultSet.moveToCurrentRow();resultSet.last();}
4.业务实现
public void testExportDoc(@RequestParam("id") String testId, HttpServletResponse response){//aspose 授权AsposeWordLib.setAuthLicense();SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");//插入动态表格ResultSetDataSource dataSource = new ResultSetDataSource();OutputStream responseOutputStream = null;try{//基础数据赋值String uuid = testId;RequestLogUtils.setAttribute("code",uuid);ClassPathResource pathResource = new ClassPathResource("test01/test01.docx");InputStream in = pathResource.getInputStream();Document doc = new Document(in);WordLib.mergeField(doc, "code",uuid);WordLib.mergeField(doc, "productmodel", "2024-M11-");WordLib.mergeField(doc, "productname", "产品名称");WordLib.mergeField(doc, "username", "用户名");Date date = new Date();WordLib.mergeField(doc, "applytimestr",formatter.format(date));WordLib.mergeField(doc, "num",556251);//集合数据动态赋值String [] arrDefault = {"seq","name","sign"};String [][] arrayTab = new String[2][3];for (int i = 0; i < 2; i++) {arrayTab[i][0] = i + "";arrayTab[i][1] = "物资" + i;arrayTab[i][2] = "sign" + i;}dataSource.executeWithRegions(doc,"t1",arrDefault, arrayTab);String [] arrMerge = {"content","status","userStr"};String [][] arrayTabMerge = new String[3][3];for (int i = 0; i < 3; i++) {arrayTabMerge[i][0] = i + "、内容" + i;if(i%2 == 0){arrayTabMerge[i][1] = "☑ 正常 ☐ 停用";}else {arrayTabMerge[i][1] = "☐ 正常 ☑ 停用";}arrayTabMerge[i][2] = "用户";}dataSource.executeWithRegions(doc,"t2",arrMerge, arrayTabMerge);//默认的行数 = 固定表格数(从1开始计算)+动态计算的arrayTab长度int defaultRow = 7 + arrayTab.length;//需要合并的行数int dynamicMergeRowsCM = arrayTabMerge.length;//内容列表-详细内容单元格合并DocumentBuilder documentBuilder = new DocumentBuilder(doc);//移动到第一个表格的第defaultStaIndex行的第columnIndex列(第一个格子)的第一个字符(doc表格外的标题不做计算)documentBuilder.moveToCell(0, defaultRow, 0, 0);documentBuilder.getCellFormat().setVerticalMerge(CellMerge.FIRST);for(int i = 0; i < dynamicMergeRowsCM; i++ ) {documentBuilder.moveToCell(0, defaultRow + i, 0, 0);documentBuilder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);}//内容列表-操作人单元格合并//移动到第一个表格的第defaultStaIndex行的第columnIndex列(第一个格子)的第一个字符(doc表格外的标题不做计算)documentBuilder.moveToCell(0, defaultRow, 3, 0);documentBuilder.getCellFormat().setVerticalMerge(CellMerge.FIRST);for(int i = 0; i < dynamicMergeRowsCM; i++ ) {documentBuilder.moveToCell(0, defaultRow + i, 3, 0);documentBuilder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);}//返回前台ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try {doc.save(outputStream, SaveFormat.DOCX);} catch (Exception e) {e.printStackTrace();}// 建立一个文件的输出的输出流ByteArrayOutputStream byteArrayOutputStream = (ByteArrayOutputStream) outputStream;byte[] aByte = byteArrayOutputStream.toByteArray();response.setCharacterEncoding("UTF-8");response.setHeader("Content-Disposition", "attachment; filename=" + uuid +".docx");String returnType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";response.setContentType(returnType);responseOutputStream = response.getOutputStream();responseOutputStream.write(aByte);responseOutputStream.flush();}catch (Exception e){e.printStackTrace();}}
5.单元格合并问题(仅展示垂直合并)
- 解决不连续合并的问题(包括垂直和水平合并两种)
//默认的行数 = 固定表格数(从1开始计算)+动态计算的arrayTab长度
int defaultRow = 7 + arrayTab.length;
//需要合并的行数
int dynamicMergeRowsCM = arrayTabMerge.length;
//内容列表-详细内容单元格合并
DocumentBuilder documentBuilder = new DocumentBuilder(doc);
//移动到第一个表格的第defaultStaIndex行的第columnIndex列(第一个格子)的第一个字符(doc表格外的标题不做计算)
documentBuilder.moveToCell(0, defaultRow, 0, 0);
documentBuilder.getCellFormat().setVerticalMerge(CellMerge.FIRST);
for(int i = 0; i < dynamicMergeRowsCM; i++ ) {documentBuilder.moveToCell(0, defaultRow + i, 0, 0);documentBuilder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);
}
- 对于连续合并的模板(此方案必须基于保存的文件)
public static void mergeCells(Cell startCell, Cell endCell) {Table parentTable = startCell.getParentRow().getParentTable();Point startCellPos = new Point(startCell.getParentRow().indexOf(startCell), parentTable.indexOf(startCell.getParentRow()));Point endCellPos = new Point(endCell.getParentRow().indexOf(endCell), parentTable.indexOf(endCell.getParentRow()));Rectangle mergeRange = new Rectangle(Math.min(startCellPos.x, endCellPos.x), Math.min(startCellPos.y, endCellPos.y), Math.abs(endCellPos.x - startCellPos.x) + 1,Math.abs(endCellPos.y - startCellPos.y) + 1);for (Row row : parentTable.getRows()) {for (Cell cell : row.getCells()) {Point currentPos = new Point(row.indexOf(cell), parentTable.indexOf(row));if (mergeRange.contains(currentPos)) {if (currentPos.x == mergeRange.x)cell.getCellFormat().setHorizontalMerge(CellMerge.FIRST);elsecell.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);if (currentPos.y == mergeRange.y)cell.getCellFormat().setVerticalMerge(CellMerge.FIRST);elsecell.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);}}}}//具体实现方案
public static void main(String[] args) {ClassPathResource re = new ClassPathResource("exportDocTemplate/new241119/test02.docx");InputStream in = re.getInputStream();Document targetDoc = new Document(in);Table table = targetDoc.getFirstSection().getBody().getTables().get(0);Cell cellStartRange = table.getRows().get(12).getCells().get(0); //开始的行和列Cell cellEndRange = table.getRows().get(13).getCells().get(0); //结束的行列ReportExportCommonUtils.mergeCells(cellStartRange, cellEndRange);Cell s1 = table.getRows().get(12).getCells().get(3); //开始的行和列Cell e1 = table.getRows().get(13).getCells().get(3); //结束的行列ReportExportCommonUtils.mergeCells(s1, e1);Cell s2 = table.getRows().get(10).getCells().get(0); //开始的行和列Cell e2 = table.getRows().get(11).getCells().get(0); //结束的行列ReportExportCommonUtils.mergeCells(s2, e2);Cell s3 = table.getRows().get(10).getCells().get(3); //开始的行和列Cell e3 = table.getRows().get(11).getCells().get(3); //结束的行列mergeCells(s3, e3);}
6.最终效果展示
7.需要主要的问题点
- 水平合并关键代码
documentBuilder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
- 在编辑数据模板时需要切换域代码,也就是文中指定的数据模板图1
相关文章:

java操作doc——java利用Aspose.Words操作Word文档并动态设置单元格合并
在实际工作中,如果业务线是管理类项目或者存在大量报表需要导出的业务时,可以借助第三方插件实现其对应功能。 尤其是需要对word文档的动态操作或者模板数据的定向合并,使用Aspose会相对来说容易一些,而且相关文档比较完整&#…...

探索 .NET 9 控制台应用中的 LiteDB 异步 CRUD 操作
本文主要是使用异步方式,体验 litedb 基本的 crud 操作。 LiteDB 是一款轻量级、快速且免费的 .NET NoSQL 嵌入式数据库,专为小型本地应用程序设计。它以单一数据文件的形式提供服务,支持文档存储和查询功能,适用于桌面应用、移动…...

《进程隔离机制:C++多进程编程安全的坚固堡垒》
在当今数字化时代,软件系统的安全性愈发成为人们关注的焦点。尤其是在 C多进程编程领域,如何确保进程间的安全交互与数据保护,是每一位开发者都必须面对的重要课题。而进程隔离机制,犹如一座坚固的堡垒,为 C多进程编程…...

构建无障碍的数字世界:深入探讨Web可访问性指南
文章目录 前言一、什么是Web可访问性?二、Web内容无障碍指南(WCAG)三、ARIA属性的应用四、实践中的Web可访问性结语 前言 在当今高度互联的世界里,互联网已成为人们日常生活不可或缺的一部分。然而,对于数百万残障人士…...

跨境出海安全:如何防止PayPal账户被风控?
今天咱们聊聊那些让人头疼的事儿——PayPal账户被风控。不少跨境电商商家反馈,我们只是想要安安静静地在网上做个小生意,结果不知道为什么,莫名其妙账户就被冻结了。 但其实每个封禁都是有原因的,今天就来给大家分享分享可能的原…...

学习日记_20241123_聚类方法(MeanShift)
前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…...

AI编程和AI绘画哪个更适合创业?
AI编程和AI绘画各有优势,适合创业的方向取决于你的资源、兴趣、市场需求和技术能力。以下是两者的对比分析,帮助你选择更适合的方向: AI编程 优势 1、广泛应用领域: 涉及自动化、数据分析、自然语言处理、计算机视觉等多个领域&a…...

macOS 无法安装第三方app,启用任何来源的方法
升级新版本 MacOS 后,安装下载的软件时,不能在 ”安全性与隐私” 中找不到 ”任何来源” 选项。 1. 允许展示任何来源 点击 启动器 (Launchpad) – 其他 (Other) – 终端 (Terminal): 打开终端后,输入以下代码回车: …...

关于SpringBoot集成Kafka
关于Kafka Apache Kafka 是一个分布式流处理平台,广泛用于构建实时数据管道和流应用。它能够处理大量的数据流,具有高吞吐量、可持久化存储、容错性和扩展性等特性。 Kafka一般用作实时数据流处理、消息队列、事件架构驱动等 Kafka的整体架构 ZooKeeper:…...

4.STM32之通信接口《精讲》之IIC通信---软件实现IIC《深入浅出》面试必备!
接下正式,进入软件编写IIC时序了,并实现对MPU6050的控制,既然是软件实现,那么硬件方面,我仅需两根控制线即可,即:数据控制线SDA,时钟控制线SCL。(人为软件层面定义的&…...

6G通信技术对比5G有哪些不同?
6G,即第六代移动通信技术,是5G之后的延伸,代表了一种全新的通信技术发展方向。与5G相比,6G在多个方面都有显著的不同和提升,以下是对6G通信技术及其与5G差异的详细分析: 一、6G的基本特点 更高的传输速率…...

「Mac玩转仓颉内测版28」基础篇8 - 元组类型详解
本篇将介绍 Cangjie 中的元组类型,包括元组的定义、创建、访问、数据解构以及应用场景,帮助开发者掌握元组类型的使用。 关键词 元组类型定义元组创建元组访问数据解构应用场景 一、元组类型概述 在 Cangjie 中,元组是一种用于存储多种数据…...

WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理
WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理 1. 标题识别elementUI组件爆红 这个原因是: 在官网说明里,才版本2024.1开始,默认启用的 Vue Language Server,但是在 Vue 2 项目…...

机械设计学习资料
免费送大家学习资源,已整理好,仅供学习 下载网址: https://www.zzhlszk.com/?qZ02-%E6%9C%BA%E6%A2%B0%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83SOP.zip...

Python 快速入门(上篇)❖ Python 字符串
Python 字符串 字符串格式化输出字符串拼接获取字符串长度字符串切片字符串处理方法 字符串格式化输出 name “xhx” age 30 # 方法1 print("我的名字是%s,今年%s岁了。 " % (name, age)) # 方法2 print(f"我的名字是{name},今年{age}岁了。")字符串拼接…...

Ubuntu中使用多版本的GCC
我的系统中已经安装了GCC11.4,在安装cuda时出现以下错误提示: 意思是当前的GCC版本过高,要在保留GCC11.4的同时安装GCC9并可以切换,可以通过以下步骤实现: 步骤 1: 安装 GCC 9 sudo apt-get update sudo apt-get ins…...

1+X应急响应(网络)文件包含漏洞:
常见网络攻击-文件包含漏洞&命令执行漏洞: 文件包含漏洞简介: 分析漏洞产生的原因: 四个函数: 产生漏洞的原因: 漏洞利用条件: 文件包含: 漏洞分类: 本地文件包含: …...

机器学习实战记录(1)
决策树——划分数据集 def splitDataSet(dataSet, axis, value): retDataSet [] #创建返回的数据集列表for featVec in dataSet: #遍历数据集if featVec[axis] value:reducedFeatVec featVec[:axis] #去掉axis特征reducedFeatVec.extend(featVec[axis1…...

PHP8解析php技术10个新特性
PHP8系列是 PHP编程语言的最新主线版本,带来了许多激动人心的新特性和改进。作为一名PHP开发者,了解这些更新能够帮助你编写更高效、安全和现代的代码。 8的核心技术知识点,包括语言特性、性能优化、安全增强以及开发者工具的改进。 Just-In…...

C++模版特化和偏特化
什么是模版特化 特化的含义:所谓特化,就是将泛型搞得具体化一些,从字面上来解释,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰(例如const或…...

Simulink中Model模块的模型保护功能
在开发工作过程中,用户为想要知道供应商的开发能力,想要供应商的模型进行测试。面对如此要求,为了能够尽快拿到定点项目,供应商会选择一小块算法或是模型以黑盒的形式供客户测试。Simulink的Model模块除了具有模块引用的功能之外&…...

Linux常用工具的使用(2):文本编辑器的使用
实验题目:Linux常用工具的使用(2):文本编辑器的使用 实验目的: (1)理解文本编辑器vi的工作模式; (2)掌握文本编辑器的使用方法 实验内容: &a…...

【StarRocks】starrocks 3.2.12 【share-nothing】 多Be集群容器化部署
文章目录 一. 集群规划二.docker compose以及启动脚本卷映射对于网络环境变量 三. 集群测试用户新建、赋权、库表初始化断电重启扩容 BE 集群 一. 集群规划 部署文档 https://docs.starrocks.io/zh/docs/2.5/deployment/plan_cluster/ 分类描述FE节点1. 主要负责元数据管理、…...

联想ThinkServer服务器主要硬件驱动下载
联想ThinkServer服务器主要硬件驱动下载: 联想ThinkServer服务器主要硬件Windows Server驱动下载https://newsupport.lenovo.com.cn/commonProblemsDetail.html?noteid156404#D50...

Ansys Zemax Optical Studio 中的近视眼及矫正
近视,通常称为近视眼,是一种眼睛屈光不正,导致远处物体模糊,而近处物体清晰。这是一种常见的视力问题,通常发生在眼球过长或角膜(眼睛前部清晰的部分)过于弯曲时。因此,进入眼睛的光…...

三次握手后的数据传输
一旦三次握手成功完成,TCP连接便正式建立,双方可以开始传输数据。在这个阶段,TCP协议利用其独特的可靠性和流控机制,确保数据的有序、无差错传输。 序列号与确认号:在数据传输过程中,TCP会为每个报文段分配…...

企业OA管理系统:Spring Boot技术实现与案例研究
摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了企业OA管理系统的开发全过程。通过分析企业OA管理系统管理的不足,创建了一个计算机管理企业OA管理系统的方案。文章介绍了企业OA管理系统的系统分析部…...

(免费送源码)计算机毕业设计原创定制:Java+JSP+HTML+JQUERY+AJAX+MySQL springboot计算机类专业考研学习网站管理系统
摘 要 大数据时代下,数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求,利用互联网服务于其他行业,促进生产,已经是成为一种势不可挡的趋势。在大学生在线计算机类专业考研学习网站管理的要求下,开发一…...

Go语言工程测试的基本规则和流程
Go语言工程测试的基本规则和流程 在Go语言的工程实践中,测试是确保软件质量和稳定性的关键环节。本文将深入探讨Go语言中的工程测试,包括单元测试、性能测试和集成测试等,以及它们的编写规则、组织方式和执行流程。 单元测试(Unit Testing) 单元测试是针对软件中最小可…...

阿里云cdn配置记录和nodejs手动安装
cdn 登录阿里云 域名解析权限 开启cdn,接引导流程, 源可以设置 域名或者ip等 配置好域名解析 上传https证书 图片不显示,后端开发需要配置 回源配置的回源协议 ,配置跟随客服端【如果浏览器多次重定向错误,客服或者改…...