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

使用 EasyExcel 相邻数据相同时行和列的合并,包括动态表头、数据

前言

在处理 Excel 文件时,经常会遇到需要对表格中的某些单元格进行合并的情况,例如合并相同的行或列。Apache POI 是一个强大的工具,但它使用起来相对复杂。相比之下,EasyExcel 是一个基于 Apache POI 的轻量级 Excel 处理库,它提供了更简单易用的 API,使得处理 Excel 文件变得更加方便。

本文将介绍如何使用 EasyExcel 进行列和列的合并,并提供一个完整的示例代码。

准备工作

首先,确保你的项目中已经引入了 EasyExcel 的依赖。如果你使用的是 Maven,可以在 pom.xml 中添加以下依赖:

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.10</version>
</dependency>
创建合并策略

EasyExcel 提供了一个 AbstractMergeStrategy 抽象类,我们可以继承它来实现自定义的合并策略。下面是一个示例,展示了如何创建一个可以同时进行行和列合并的策略:

package org.songtang.exceldemo.test;import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;import java.util.*;public class OptimizedMergeCellStrategyHandler extends AbstractMergeStrategy {private final boolean alikeColumn;private final boolean alikeRow;private final int rowIndex;private final int rowIndexStart;private final Set<Integer> columns;private int currentRowIndex = 0;public OptimizedMergeCellStrategyHandler(boolean alikeColumn, boolean alikeRow, int rowIndex, Set<Integer> columns) {this(alikeColumn, alikeRow, rowIndex, columns, 0);}public OptimizedMergeCellStrategyHandler(boolean alikeColumn, boolean alikeRow, int rowIndex, Set<Integer> columns, int rowIndexStart) {this.alikeColumn = alikeColumn;this.alikeRow = alikeRow;this.rowIndex = rowIndex;this.columns = columns;this.rowIndexStart = rowIndexStart;}@Overrideprotected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {int rowId = cell.getRowIndex();currentRowIndex = rowId;if (rowIndex > rowId) {return;}int columnId = cell.getColumnIndex();if (alikeColumn && columnId > 0) {mergeCells(sheet, cell, columnId - 1, columnId, 0);}if (alikeRow && rowId > rowIndexStart && columns.contains(columnId)) {mergeCells(sheet, cell, rowId - 1, rowId, 1);}}private void mergeCells(Sheet sheet, Cell cell, int start, int end, int direction) {String cellValue = getCellVal(cell);Cell referenceCell = direction == 0 ? cell.getRow().getCell(start) : sheet.getRow(start).getCell(cell.getColumnIndex());String refCellValue = getCellVal(referenceCell);if (Objects.equals(cellValue, refCellValue)) {CellRangeAddress rangeAddress = createRangeAddress(sheet, cell, start, end, direction);if (rangeAddress != null) {sheet.addMergedRegion(rangeAddress);}}}private CellRangeAddress createRangeAddress(Sheet sheet, Cell cell, int start, int end, int direction) {CellRangeAddress rangeAddress = direction == 0 ?new CellRangeAddress(cell.getRowIndex(), cell.getRowIndex(), start, end) :new CellRangeAddress(start, end, cell.getColumnIndex(), cell.getColumnIndex());return findExistAddress(sheet, rangeAddress, getCellVal(cell));}private CellRangeAddress findExistAddress(Sheet sheet, CellRangeAddress rangeAddress, String currentVal) {List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();for (int i = mergedRegions.size() - 1; i >= 0; i--) {CellRangeAddress exist = mergedRegions.get(i);if (exist.intersects(rangeAddress)) {if (exist.getLastRow() < rangeAddress.getLastRow()) {exist.setLastRow(rangeAddress.getLastRow());}if (exist.getLastColumn() < rangeAddress.getLastColumn()) {exist.setLastColumn(rangeAddress.getLastColumn());}sheet.removeMergedRegion(i);return exist;}}return rangeAddress;}private String getCellVal(Cell cell) {try {return cell.getStringCellValue();} catch (Exception e) {// 使用日志框架代替 System.out.printf// Logger logger = LoggerFactory.getLogger(OptimizedMergeCellStrategyHandler.class);// logger.error("读取单元格内容失败:行{} 列{}", cell.getRowIndex() + 1, cell.getColumnIndex() + 1, e);System.out.printf("读取单元格内容失败:行%d 列%d %n", (cell.getRowIndex() + 1), (cell.getColumnIndex() + 1));return null;}}
}
编写测试代码

接下来,我们编写一个测试类来生成一个包含合并行和列的 Excel 文件:

package org.songtang.exceldemo;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import org.junit.jupiter.api.Test;
import org.songtang.exceldemo.test.OptimizedMergeCellStrategyHandler;import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;//@SpringBootTest
public class ExcelTest {@Testpublic void generateRowMergedFile() {String fileName = "/Users/test/Downloads/" + System.currentTimeMillis() + ".xlsx";ExcelWriterBuilder write = EasyExcel.write(fileName);Set<Integer> set = new HashSet<>();set.add(0); // 合并第0列set.add(1); // 合并第1列set.add(2); // 合并第2列write.registerWriteHandler(new OptimizedMergeCellStrategyHandler(true, true, 2, set)); // 启用列和行合并write.head(head()).automaticMergeHead(true).sheet("模板").doWrite(data1());}private List<List<String>> data1() {List<List<String>> data = new ArrayList<>();List<String> data1 = new ArrayList<>();data1.add("人员");data1.add("人员");data1.add("语文");data1.add("数值一");data1.add("数值二");List<String> data2 = new ArrayList<>();data2.add("人员");data2.add("人员");data2.add("语文");data2.add("数值三");data2.add("数值四");data.add(data1);data.add(data2);return data;}private List<List<String>> head() {List<List<String>> list = new ArrayList<>();List<String> head0 = new ArrayList<>();head0.add("模块");head0.add("模块");List<String> head00 = new ArrayList<>();head00.add("模块");head00.add("模块");List<String> head1 = new ArrayList<>();head1.add("课程");head1.add("课程");List<String> head2 = new ArrayList<>();head2.add("完美世界");head2.add("石昊");List<String> head3 = new ArrayList<>();head3.add("完美世界");head3.add("火灵儿");list.add(head0);list.add(head00);list.add(head1);list.add(head2);list.add(head3);return list;}
}
运行测试

运行 generateRowMergedFile 测试方法,将会在指定路径生成一个包含合并行和列的 Excel 文件。你可以打开生成的文件,查看合并的效果。

总结

通过上述步骤,我们成功地使用 EasyExcel 实现了 Excel 文件中行和列的合并。EasyExcel 的强大之处在于其简洁的 API 和灵活的扩展能力,使得复杂的 Excel 处理任务变得简单易行。希望本文对你有所帮助!

如果你有任何问题或建议,欢迎留言交流!

相关文章:

使用 EasyExcel 相邻数据相同时行和列的合并,包括动态表头、数据

前言 在处理 Excel 文件时&#xff0c;经常会遇到需要对表格中的某些单元格进行合并的情况&#xff0c;例如合并相同的行或列。Apache POI 是一个强大的工具&#xff0c;但它使用起来相对复杂。相比之下&#xff0c;EasyExcel 是一个基于 Apache POI 的轻量级 Excel 处理库&am…...

985研一学习日记 - 2024.10.16

一个人内耗&#xff0c;说明他活在过去&#xff1b;一个人焦虑&#xff0c;说明他活在未来。只有当一个人平静时&#xff0c;他才活在现在。 日常 1、起床6:00√ 2、健身1个多小时 今天练了二头和背部&#xff0c;明天练胸和三头 3、LeetCode刷了3题 旋转图像&#xff1a…...

安装mysql 5.5.62

1>先检查是否存在其他版本mysql rpm -qa|grep -i mariadb 存在则卸载 yum -y remove maria* 2>下载mysql 5.5.62 wget https://cdn.mysql.com/archives/mysql-5.5/mysql-5.5.62-linux-glibc2.12-x86_64.tar.gz 3>确认系统是否安装libaio库 yum -y install libai…...

AnaTraf | 网络性能监控系统的价值

目录 1. IT运维工程师 2. 网络管理员 3. 安全团队&#xff08;网络安全工程师&#xff09; 4. 业务部门&#xff08;应用开发人员、产品经理&#xff09; 5. 管理层与决策者&#xff08;CTO/CIO、IT经理&#xff09; 6. 最终用户&#xff08;普通员工&#xff09; 总结&…...

决策树和集成学习的概念以及部分推导

一、决策树 1、概述 决策树是一种树形结构&#xff0c;树中每个内部节点表示一个特征上的判断&#xff0c;每个分支代表一个判断结果的输出&#xff0c;每个叶子节点代表一种分类结果 决策树的建立过程&#xff1a; 特征选择&#xff1a;选择有较强分类能力的特征决策树生成…...

servlet基础与环境搭建(idea版)

文章目录 环境变量配置安包装环境变量配置JDK 配置 静态网页动态网页&#xff08;idea&#xff09;给模块添加 web框架新版本 2023 之后的 idea&#xff0c;使用方法二idea 目录介绍建立前端代码启动配置 环境变量配置 tomcat 环境变量 安包装 环境变量配置 JDK 配置 静态网页…...

【10月最新】植物大战僵尸杂交版新僵尸预告(附最新版本下载链接)

【BOSS僵尸】埃德加二世 【新BOSS僵尸】埃德加二世 “埃德加博士的克隆体。驾驶着最新一代小型化机甲&#xff0c;致力于为戴夫博士扫清障碍。” -体型&#xff08;模型大小&#xff09;小于原版僵王的头 -血量120000&#xff08;原版僵王复仇的2倍&#xff09;&#xff0c;免疫…...

网络编程-UDP以及数据库mysql

UDP通信流程 服务端客户端有一个邮箱socket()有一个邮箱socket()绑定地址bind()发送数据sendto接收数据recvfrom关闭close()关闭colse() //服务端 #include "head.h" // ./server 10001 int main(int argc,char *argv[]) {// 1、创建socket套接字// 参数1&#xff…...

ubuntu 20.04 安装ros1

步骤 1&#xff1a;设置系统 首先&#xff0c;确保系统环境是最新的&#xff1a; sudo apt update sudo apt upgrade 步骤 2&#xff1a;设置源和密钥 添加 ROS 软件源&#xff1a; 首先&#xff0c;确保 curl 和 gnupg 已安装&#xff1a; sudo apt install curl gnupg2…...

ShardingSphere-Proxy 数据库中间件MySql分库分表环境搭建

一. ShardingSphere-Proxy简介 1、简介 Apache ShardingSphere 是一款开源分布式数据库生态项目&#xff0c;旨在碎片化的异构数据库上层构建生态&#xff0c;在最大限度的复用数据库原生存算能力的前提下&#xff0c;进一步提供面向全局的扩展和叠加计算能力。其核心采用可插…...

Pytest+selenium UI自动化测试实战实例

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 今天来说说pytest吧&#xff0c;经过几周的时间学习&#xff0c;有收获也有疑惑&#xff0c;总之最后还是搞个小项目出来证明自己的努力不没有白费 环境准备 1 …...

服务器技术研究分析:存储从HBM到CXL

服务器变革&#xff1a;存储从HBM到CXL 在《从云到端&#xff0c;AI产业的新范式&#xff08;2024&#xff09;》中揭示&#xff0c;传统服务器价格低至1万美金&#xff0c;而配备8张H100算力卡的DGX H100AI服务器价值高达40万美金&#xff08;约300万人民币&#xff09;。 从供…...

下载并安装 WordPress 中文版

下载并安装 WordPress 中文版 1. 安装 LAMP 环境(Linux, Apache, MySQL, PHP)1. 安装 Apache2. 安装 MySQL3. 安装 PHP1. 下载并安装 WordPress 中文版1. 下载 WordPress2. 配置文件权限3 . 创建 MySQL 数据库4 . 配置 WordPress1. 安装 LAMP 环境(Linux, Apache, MySQL, PH…...

从零开始的LeetCode刷题日记:515.在每个树行中找最大值

一.相关链接 题目链接&#xff1a;515.在每个树行中找最大值 二.心得体会 这道题也是层序遍历&#xff0c;只需要记录每一层的最大值即可&#xff0c;反复比较记录最大值。 三.代码 class Solution { public:vector<int> largestValues(TreeNode* root) {vector<…...

C语言 | Leetcode C语言题解之第492题构造矩形

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> constructRectangle(int area) {int w sqrt(1.0 * area);while (area % w) {--w;}return {area / w, w};} };...

在FastAPI网站学python:虚拟环境创建和使用

Python虚拟环境&#xff08;virtual environment&#xff09;是一个非常重要的工具&#xff0c;它允许开发者为每个项目创建独立的Python环境&#xff0c;隔离您为每个项目安装的软件包&#xff0c;从而避免不同项目之间的依赖冲突。 学习参考FastAPI官网文档&#xff1a;Virt…...

安全风险评估(Security Risk Assessment, SRA)

安全风险评估&#xff08;Security Risk Assessment, SRA&#xff09;是识别、分析和评价信息安全风险的过程。它帮助组织了解其信息资产面临的潜在威胁&#xff0c;以及这些威胁可能带来的影响。通过风险评估&#xff0c;组织可以制定有效的风险管理策略&#xff0c;以减少或控…...

SQL Injection | SQL 注入 —— 布尔盲注

关注这个漏洞的其他相关笔记&#xff1a;SQL 注入漏洞 - 学习手册-CSDN博客 0x01&#xff1a;布尔盲注 —— 理论篇 布尔盲注&#xff08;Boolean-Based Blind Injection&#xff09;是一种常见的 SQL 注入技术&#xff0c;它适用于那些 SQL 注入时&#xff0c;查询结果不会直…...

stm32 bootloader写法

bootloader写法&#xff1a; 假设app的起始地址&#xff1a;0x08020000&#xff0c;则bootloader的范围是0x0800,0000~0x0801,FFFF。 #define APP_ADDR 0x08020000 // 应用程序首地址定义 typedef void (*APP_FUNC)(void); // 函数指针类型定义 /*main函数中调用rum_app&#x…...

Unity3D 物体表面水滴效果详解

在游戏开发中&#xff0c;逼真的水滴效果能够显著提升游戏场景的真实感和沉浸感。Unity3D作为一款强大的游戏开发引擎&#xff0c;提供了丰富的工具和技术来实现这种效果。本文将详细介绍如何在Unity3D中实现物体表面的水滴效果&#xff0c;包括技术详解和代码实现。 对惹&…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践

01技术背景与业务挑战 某短视频点播企业深耕国内用户市场&#xff0c;但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大&#xff0c;传统架构已较难满足当前企业发展的需求&#xff0c;企业面临着三重挑战&#xff1a; ① 业务&#xff1a;国内用户访问海外服…...

深度解析:etcd 在 Milvus 向量数据库中的关键作用

目录 &#x1f680; 深度解析&#xff1a;etcd 在 Milvus 向量数据库中的关键作用 &#x1f4a1; 什么是 etcd&#xff1f; &#x1f9e0; Milvus 架构简介 &#x1f4e6; etcd 在 Milvus 中的核心作用 &#x1f527; 实际工作流程示意 ⚠️ 如果 etcd 出现问题会怎样&am…...