当前位置: 首页 > 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 处理任务变得简单易行。希望本文对你有所帮助!

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

http://www.lryc.cn/news/462474.html

相关文章:

  • 985研一学习日记 - 2024.10.16
  • 安装mysql 5.5.62
  • AnaTraf | 网络性能监控系统的价值
  • 决策树和集成学习的概念以及部分推导
  • servlet基础与环境搭建(idea版)
  • 【10月最新】植物大战僵尸杂交版新僵尸预告(附最新版本下载链接)
  • 网络编程-UDP以及数据库mysql
  • ubuntu 20.04 安装ros1
  • ShardingSphere-Proxy 数据库中间件MySql分库分表环境搭建
  • Pytest+selenium UI自动化测试实战实例
  • 服务器技术研究分析:存储从HBM到CXL
  • 下载并安装 WordPress 中文版
  • 从零开始的LeetCode刷题日记:515.在每个树行中找最大值
  • C语言 | Leetcode C语言题解之第492题构造矩形
  • 在FastAPI网站学python:虚拟环境创建和使用
  • 安全风险评估(Security Risk Assessment, SRA)
  • SQL Injection | SQL 注入 —— 布尔盲注
  • stm32 bootloader写法
  • Unity3D 物体表面水滴效果详解
  • 若依框架中spring security的完整认证流程,及其如何使用自定义用户表进行登录认证,学会轻松实现二开,嘎嘎赚块乾
  • selenium:操作滚动条的方法(8)
  • Discuz | 起尔开发 传奇开服表游戏公益服发布论坛网站插件
  • 问:JAVA对象的数据结构长啥样?
  • STGCN解读(论文+代码)
  • perl读取目录,写入文件
  • JDK-23与JavaFX配置在IDEA中
  • VSCode运行QT界面
  • npm-run-all 使用实践
  • 【CCPC】The 2021 CCPC Guilin Onsite (XXII Open Cup, Grand Prix of EDG) K
  • selenium的实际使用