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

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文档并动态设置单元格合并

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

探索 .NET 9 控制台应用中的 LiteDB 异步 CRUD 操作

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

《进程隔离机制:C++多进程编程安全的坚固堡垒》

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

构建无障碍的数字世界:深入探讨Web可访问性指南

文章目录 前言一、什么是Web可访问性&#xff1f;二、Web内容无障碍指南&#xff08;WCAG&#xff09;三、ARIA属性的应用四、实践中的Web可访问性结语 前言 在当今高度互联的世界里&#xff0c;互联网已成为人们日常生活不可或缺的一部分。然而&#xff0c;对于数百万残障人士…...

跨境出海安全:如何防止PayPal账户被风控?

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

学习日记_20241123_聚类方法(MeanShift)

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…...

AI编程和AI绘画哪个更适合创业?

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

macOS 无法安装第三方app,启用任何来源的方法

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

关于SpringBoot集成Kafka

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

4.STM32之通信接口《精讲》之IIC通信---软件实现IIC《深入浅出》面试必备!

接下正式&#xff0c;进入软件编写IIC时序了&#xff0c;并实现对MPU6050的控制&#xff0c;既然是软件实现&#xff0c;那么硬件方面&#xff0c;我仅需两根控制线即可&#xff0c;即&#xff1a;数据控制线SDA&#xff0c;时钟控制线SCL。&#xff08;人为软件层面定义的&…...

6G通信技术对比5G有哪些不同?

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

「Mac玩转仓颉内测版28」基础篇8 - 元组类型详解

本篇将介绍 Cangjie 中的元组类型&#xff0c;包括元组的定义、创建、访问、数据解构以及应用场景&#xff0c;帮助开发者掌握元组类型的使用。 关键词 元组类型定义元组创建元组访问数据解构应用场景 一、元组类型概述 在 Cangjie 中&#xff0c;元组是一种用于存储多种数据…...

WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理

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

机械设计学习资料

免费送大家学习资源&#xff0c;已整理好&#xff0c;仅供学习 下载网址&#xff1a; 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&#xff0c;在安装cuda时出现以下错误提示&#xff1a; 意思是当前的GCC版本过高&#xff0c;要在保留GCC11.4的同时安装GCC9并可以切换&#xff0c;可以通过以下步骤实现&#xff1a; 步骤 1: 安装 GCC 9 sudo apt-get update sudo apt-get ins…...

1+X应急响应(网络)文件包含漏洞:

常见网络攻击-文件包含漏洞&命令执行漏洞&#xff1a; 文件包含漏洞简介&#xff1a; 分析漏洞产生的原因&#xff1a; 四个函数&#xff1a; 产生漏洞的原因&#xff1a; 漏洞利用条件&#xff1a; 文件包含&#xff1a; 漏洞分类&#xff1a; 本地文件包含&#xff1a; …...

机器学习实战记录(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编程语言的最新主线版本&#xff0c;带来了许多激动人心的新特性和改进。作为一名PHP开发者&#xff0c;了解这些更新能够帮助你编写更高效、安全和现代的代码。 8的核心技术知识点&#xff0c;包括语言特性、性能优化、安全增强以及开发者工具的改进。 Just-In…...

C++模版特化和偏特化

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

情感漏洞经纪:倒卖AI崩溃瞬间年入百万

新兴暴利职业的崛起在人工智能技术高速发展的今天&#xff0c;一种名为“情感漏洞经纪”的灰色产业悄然兴起&#xff0c;从业者通过倒卖AI系统崩溃瞬间的数据年入百万。这些经纪人专门捕捉AI模型在情感交互中的故障时刻——如系统宕机前的“遗言”、未完成的情感回应或异常输出…...

异构数据库迁移利器:dbswitch实现多源数据高效同步

1. 异构数据库迁移的痛点与常见方案 第一次接触异构数据库迁移时&#xff0c;我被各种工具搞得晕头转向。当时公司需要把Oracle的业务数据同步到Greenplum做分析&#xff0c;试了好几种方案都不太理想。比如用kettle配置gpload&#xff0c;光是理解那些参数就花了两天时间&…...

Docker 安装 Portainer(Docker 容器管理工具)

安装步骤 1. 创建 Portainer 数据卷&#xff08;可选&#xff0c;用于持久化数据&#xff09; docker volume create portainer_data2. 运行 Portainer 容器 方式一&#xff1a;Docker 命令运行 docker run -d \-p 8000:8000 \-p 9443:9443 \--name portainer \--restartalways…...

SwiftHub:终极GitHub iOS客户端开发指南 - RxSwift与MVVM-C架构实践

SwiftHub&#xff1a;终极GitHub iOS客户端开发指南 - RxSwift与MVVM-C架构实践 【免费下载链接】SwiftHub GitHub iOS client in RxSwift and MVVM-C clean architecture 项目地址: https://gitcode.com/gh_mirrors/sw/SwiftHub SwiftHub是一款功能强大的GitHub iOS客户…...

变压器差动保护MATLAB/simulink仿真 变压器差动保护仿真➕报告

变压器差动保护MATLAB/simulink仿真 变压器差动保护仿真➕报告第一部分&#xff1a;Simulink 仿真模型搭建指南 以下是变压器差动保护的Simulink模型搭建步骤及核心代码&#xff0c;包含模型参数设置、差动逻辑实现和仿真分析&#xff1a; 一、Simulink模型搭建 打开MATLAB&…...

【数字信号调制】GMSK调制解调系统【含Matlab源码 15239期】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;Matlab武动乾坤博客之家&#x1f49e;…...

ASPP模块的演进与优化:从DeepLab v2到v3+的多尺度语义分割实践

1. 多尺度语义分割的挑战与ASPP的诞生 想象一下你要给一张街景照片中的每个像素分类——哪些是道路、哪些是车辆、哪些是行人。最大的困难是什么&#xff1f;是远处的小车和近处的大卡车可能属于同一类别&#xff0c;但尺寸差异巨大。这就是语义分割中的多尺度问题&#xff0c;…...

网络异常排查:快速定位域连接问题

问题描述与初步排查网络位置异常通常表现为计算机无法正确识别当前所在的AD域环境&#xff0c;导致访问域资源受限或登录问题。常见症状包括系统托盘显示“无法访问域”、组策略无法应用、DNS解析失败等。检查计算机是否能够ping通域控制器的主机名和IP地址。使用nslookup命令验…...

探索Ryujinx:Nintendo Switch模拟器全解析

探索Ryujinx&#xff1a;Nintendo Switch模拟器全解析 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx 在游戏技术不断发展的今天&#xff0c;模拟器技术为玩家提供了跨平台体验游戏的可…...

太原理工大学Web开发历年真题解析:期末复习必备指南(附最新试卷)

太原理工大学Web开发核心考点深度剖析与高效复习方法论 Web开发课程期末备考的战略视角 又到了期末季&#xff0c;作为太原理工大学计算机相关专业的学生&#xff0c;面对Web开发这门实践性极强的课程&#xff0c;你是否还在为如何高效复习而焦虑&#xff1f;不同于传统理论课…...