当前位置: 首页 > 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或…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...