easyExcle单元格合并

自定义单元格合并策略:

/*** 自定义单元格合并策略** @create: 2023-11-15 13:41**/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class EasyExcelCustomMergeStrategy implements RowWriteHandler {/*** 总数*/private Integer totalNum;//合并行计数private int count;//要合并的列 从0开始private int[] mergeColumnIndex;//已合并单元数private int mergedTotalCount = 0;public EasyExcelCustomMergeStrategy(int[] mergeColumnIndex) {this.mergeColumnIndex = mergeColumnIndex;}// 每写入一行会执行一次afterRowDispose,存在合并行时进行合并方法mergeSameRow,否则什么也不做@Overridepublic void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {//当前行索引int curRowNum = row.getRowNum();if (mergeColumnIndex != null && mergeColumnIndex.length > 0 && !isHead) {//当前行第一列单元格Cell curA1Cell = row.getCell(0);Object curA1Data = curA1Cell.getCellTypeEnum() == CellType.STRING ? curA1Cell.getStringCellValue() : curA1Cell.getNumericCellValue();//上一行第一列单元格Cell preA1Cell = row.getSheet().getRow(curRowNum - 1).getCell(0);Object preA1Data = preA1Cell.getCellTypeEnum() == CellType.STRING ? preA1Cell.getStringCellValue() : preA1Cell.getNumericCellValue();if (curA1Data.equals(preA1Data)) {count++;} else {if (count > 0) {for (int columnIndex : mergeColumnIndex) {mergeSameRow(writeSheetHolder, curRowNum, count, columnIndex);}//for (int i = 0; i < mergeColumnIndex.length; i++) {////}count = 0;}}// 最后一行存在合并时,需要单独调用合并,否则不会执行mergeSameRowif (curRowNum == totalNum && count > 0) {for (int columnIndex : mergeColumnIndex) {mergeSameRow(writeSheetHolder, curRowNum + 1, count, columnIndex);}}}}/*** 按列合并单元格** @param writeSheetHolder 写出处理* @param curRowIndex      当前行索引,有n行固定行就加n* @param needMergeNum     需要合并的行* @param curColIndex      需要合并的列*/private void mergeSameRow(WriteSheetHolder writeSheetHolder, int curRowIndex, int needMergeNum, int curColIndex) {Sheet sheet = writeSheetHolder.getSheet();try {Field sh = sheet.getClass().getDeclaredField("_sh");sh.setAccessible(true);XSSFSheet shSheet = (XSSFSheet) sh.get(sheet);CTWorksheet worksheet = shSheet.getCTWorksheet();CTMergeCells ctMergeCells = mergedTotalCount > 0 ? worksheet.getMergeCells() : worksheet.addNewMergeCells();CTMergeCell ctMergeCell = ctMergeCells.addNewMergeCell();CellRangeAddress cellAddresses = new CellRangeAddress(curRowIndex - needMergeNum - 1, curRowIndex - 1, curColIndex, curColIndex);ctMergeCell.setRef(cellAddresses.formatAsString());mergedTotalCount++;} catch (Exception e) {log.error("导出出错!", e);throw new BusinessException("导出出错!\n");}}
}

easyExcel提供了两种合并单元格方法:addMergedRegion和addMergedRegionUnsafe,在使用中发现会遇到不同的问题:

如果将需要合并的数据一次性传入afterRowDispose方法进行合并,在合并过程中使用addMergedRegionUnsafe方法合并单元格可能会导致工作簿损坏,而使用addMergedRegion会进行单元格是否重复合并的校验,会直接抛出异常。

使用addMergedRegionUnsafe方法合并单元格导致的问题:

使用addMergedRegion进行的校验:

/*** adds a merged region of cells (hence those cells form one)** @param region (rowfrom/colfrom-rowto/colto) to merge* @param validate whether to validate merged region* @return index of this region* @throws IllegalArgumentException if region contains fewer than 2 cells* @throws IllegalStateException if region intersects with an existing merged region* or multi-cell array formula on this sheet*/
private int addMergedRegion(CellRangeAddress region, boolean validate) {if (region.getNumberOfCells() < 2) {// 区域包含少于 2 个单元格throw new IllegalArgumentException("Merged region " + region.formatAsString() + " must contain 2 or more cells");}region.validate(SpreadsheetVersion.EXCEL97);if (validate) {// throw IllegalStateException if the argument CellRangeAddress intersects with// a multi-cell array formula defined in this sheet// 此工作表上的多单元格数组公式validateArrayFormulas(region);// Throw IllegalStateException if the argument CellRangeAddress intersects with// a merged region already in this sheet// 区域与现有合并区域相交validateMergedRegions(region);}return _sheet.addMergedRegion(region.getFirstRow(),region.getFirstColumn(),region.getLastRow(),region.getLastColumn());
}

导致错误产生的代码:

public class EasyExcelCustomMergeStrategy implements RowWriteHandler {//合并坐标集合private List<CellRangeAddress> cellRangeAddress;//从哪行开始private int beginRow;//合并行数private int mergeRows;public PiFillMergeStrategy(List<CellRangeAddress> cellRangeAddress, int beginRow, int mergeRows) {this.cellRangeAddress = cellRangeAddress;this.beginRow = beginRow;this.mergeRows = mergeRows;}@Overridepublic void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {if (CollectionUtil.isNotEmpty(cellRangeAddress)) {if (row.getRowNum() >= beginRow && row.getRowNum() <= beginRow + mergeRows) {for (CellRangeAddress item : cellRangeAddress) {writeSheetHolder.getSheet().addMergedRegionUnsafe(item);}}}}}

因此合并时循环每一条数据判断是否与上一条数据是否相同,相同时再逐条进行合并,写法使用XSSFSheet写法或使用easyExcel自带的两种合并方法:

private void mergeSameRow(WriteSheetHolder writeSheetHolder, int curRowIndex, int needMergeNum, int curColIndex) {Sheet sheet = writeSheetHolder.getSheet();CellRangeAddress cellAddresses = new CellRangeAddress(curRowIndex - needMergeNum - 1, curRowIndex - 1, curColIndex, curColIndex);sheet.addMergedRegionUnsafe(cellAddresses);// 或使用// sheet.addMergedRegion(cellAddresses);
}

合并策略的使用:

public void download(HttpServletResponse response) {/***  此处为业务数据****/String subject = "XXX";String fileName = subject.concat(".xlsx");//定义多级表头List<List<String>> headList = new ArrayList<>();//定义数据体List<List<Object>> dataList = new ArrayList<>();this.getHeadAndData(headList, dataList);// 定义合并单元格 (根据业务需求自定义)List<Integer> mergeColumnIndex = new ArrayList<>();int mergeCol = headList.size() - offerVOList.size() - 3;for (int i = 0; i < mergeCol; i++) {mergeColumnIndex.add(i);}for (int j = mergeCol + 3; j < headList.size(); j++) {mergeColumnIndex.add(j);}// 生成自定义策略EasyExcelCustomMergeStrategy customMergeStrategy = new EasyExcelCustomMergeStrategy(mergeColumnIndex.stream().filter(Objects::nonNull).mapToInt(i->i).toArray());customMergeStrategy.setTotalNum(dataList.size());try {response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));EasyExcel.write(response.getOutputStream()).excelType(ExcelTypeEnum.XLSX).head(headList).sheet(subject).registerWriteHandler(customMergeStrategy)//调用策略.doWrite(dataList);} catch (Exception e) {throw new Exception(String.format("生成文件(%s)失败", fileName), e);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/144312.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Power Automate-创建自定义连接器

点击左侧导航栏&#xff0c;更多&#xff0c;点击全部发现 点击下方的自定义连接器 点击从空白创建 注意命名要用英文 常规信息中可以上传连接器icon、写一些说明 方案是观察接口地址前面的文本&#xff0c;主机是下方接口地址中蓝色框中的内容 点击下一步&#xff0c;根据API自…

gdb详解【Linux知识贩卖机】

你背朝太阳&#xff0c;就只能看到自己的影子。 --纪伯伦语录 文章目录 简介准备常用命令查看代码&#xff08;list&#xff09;运行&#xff08;run&#xff09;打断点&#xff08;break&#xff09;逐语句&#xff08;step&#xff09;逐过程&#xff08;next&#xff09;完成…

C# 使用Microsoft.Office.Interop.Excel库操作Excel

1.在NuGet管理包中搜索&#xff1a;Microsoft.Office.Interop.Excel&#xff0c;如下图红色标记处所示&#xff0c;进行安装 2. 安装完成后&#xff0c;在程序中引入命名空间如下所示&#xff1a; using Microsoft.Office.Interop.Excel; //第一步 添加excel第三方库 usi…

人格障碍在线测试,人格障碍筛查和判断 PDQ-4+

每个人都是独一无二的&#xff0c;每个人都存在人格上的偏差&#xff0c;日常生活中我们携带着自己的人格在忙碌&#xff0c;在不够成对学习、生活和工作的影响下&#xff0c;我们认为都是健康的人格&#xff0c;反之则属于人格障碍。 人格障碍给我们的日常生活带来极大的影响…

打开PDF文件之后不能编辑,有哪些原因?

打开PDF文件之后发现没有办法编辑PDF文件&#xff0c;都有哪些原因呢&#xff1f; 首先我们可以考虑一下&#xff0c;PDF文件中的内容是否是图片&#xff0c;如果确认是图片文件&#xff0c;那么我们想要编辑&#xff0c;就可以先使用PDF编辑器中的OCR扫描功能&#xff0c;将图…

如何通过 wireshark 捕获 C# 上传的图片

一&#xff1a;背景 1. 讲故事 这些天计划好好研究下tcp/ip&#xff0c;以及socket套接字&#xff0c;毕竟工控中设计到各种交互协议&#xff0c;如果只是模模糊糊的了解&#xff0c;对分析此类dump还是非常不利的&#xff0c;而研究协议最好的入手点就是用抓包工具 wireshar…

一加手机全球摄影展深圳开展 历年获奖作品齐登场

11 月 18 日至 12 月 3 日&#xff0c;一加手机将携手国际摄影奖&#xff08;International Photography Awards&#xff0c;以下简称IPA&#xff09;&#xff0c;在深圳市南山区海岸城购物中心举办一加手机全球摄影展&#xff08;OnePlus Global Photography Exhibition&#…

容联云发布生成式应用,让每个企业都拥有大模型沟通能力

基于容联云自主研发的赤兔大模型能力&#xff0c;容联云容犀机器人真正将大模型强大的理解能力、知识学习能力、总结能力、挖掘能力、推理能力融入于实际落地应用中。 开创性的打造生成式场景化智能问答、生成式智能辅助、AI运营话术库&#xff0c;帮助企业洞悉更精准的客户真…

Ubuntu 22.04 LTS ffmpeg mp4 gif 添加图片水印

ffmpeg编译安装6.0.1&#xff0c;参考 Ubuntu 20.04 LTS ffmpeg gif mp4 互转 许编译安装ffmpeg &#xff1b;解决gif转mp4转换后无法播放问题-CSDN博客 准备一个logo MP4添加水印 ffmpeg -i 2.mp4 -vf "movielogo.png[watermark];[in][watermark]overlayx10:y10[out]&…

分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测

分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测 目录 分类预测 | MATLAB实现基于Isomap降维算法与改进蜜獾算法IHBA的Adaboost-SVM集成多输入分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 Isomap-Adaboost-IHBA-…

基于Vue+SpringBoot的城市桥梁道路管理系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询城市桥梁4.2 新增城市桥梁4.3 编辑城市桥梁4.4 删除城市桥梁4.5 查询单个城市桥梁 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的城市桥梁道路管理系统&#xff0c;支持…

本地化小程序运营 同城小程序开发

时空的限制让本地化的线上平台成为一种追求&#xff0c;58及某团正式深挖人们城镇化、本地化的信息和商业需求而崛起的平台&#xff0c;将二者结合成本地化小程序&#xff0c;显然有着巨大的市场机会。本地化小程序运营可以结合本地化生活需求的一些信息&#xff0c;以及激发商…

最长上升子序列模型 笔记

首先附上模板&#xff1a; #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \nusing namespace std;typedef pair<int, int> PII; typedef long long ll;const int N 100010;int n; int a[N], q[N];int main()…

开源大模型部署及推理所需显卡成本必读之二

在前面的文章中&#xff0c;我们介绍了大模型占用显卡空间的一些分析情况&#xff0c;这次我们继续来看看具体量化角度上的结论。 因此&#xff0c;本文来来介绍一个偏具体数值量化的工作。 随着各厂商相继发布大型模型&#xff0c;排行榜变化频繁&#xff0c;新旧交替&#xf…

代码静态测试工具之cppcheck

cppcheck简介 Cppcheck is an analysis tool for C/C code. It provides unique code analysis to detect bugs and focuses on detecting undefined behaviour and dangerous coding constructs. The goal is to detect only real errors in the code, and generate as few f…

AIGC实战——变分自编码器(Variational Autoencoder, VAE)

AIGC实战——变分自编码器 0. 前言1. 变分自编码器1.1 基本原理1.2 编码器 2. 构建VAE编码器2.1 Sampling 层2.2 编码器2.3 损失函数2.4 训练变分自编码器 3. 变分自编码器分析小结系列链接 0. 前言 我们已经学习了如何实现自编码器&#xff0c;并了解了自编码器无法在潜空间中…

React-Router源码分析-History库

history源码 history 在 v5 之前使用单独的包&#xff0c; v6 之后再 router 包中单独实现。 history源码 Action 路由切换的动作类型&#xff0c;包含三种类型&#xff1a; POPREPLACEPUSH Action 枚举&#xff1a; export enum Action {Pop "POP",Push &quo…

OCR转换技巧:如何避免图片转Word时出现多余的换行?

在将图片中的文字识别转换为Word文档时&#xff0c;我们很多时候时会遇到识别内容的一个自然段还没结束就换行的问题&#xff0c;这些就是我们常说的多余换行的问题。为什么会产生这个问题呢&#xff1f;主要是由于OCR返回的识别结果是按图片上的文字换行而换行&#xff0c;而不…

高并发架构设计(三大利器:缓存、限流和降级)

引言 高并发背景 互联网行业迅速发展&#xff0c;用户量剧增&#xff0c;系统面临巨大的并发请求压力。 软件系统有三个追求&#xff1a;高性能、高并发、高可用&#xff0c;俗称三高。三者既有区别也有联系&#xff0c;门门道道很多&#xff0c;全面讨论需要三天三夜&#…