Apache poi 对单元格进行合并

news2024/11/17 7:45:52

需求背景:

在导出excel时, 需要对内容相同的单元格进行纵向合并

期望达到的效果:

poi 实现合并单元格的方法  

sheet.addMergedRegion(new CellRangeAddress(开始行, 结束行, 开始列, 结束列));

个人的实现思路:

1): 举个列子, 就拿截图贴出的 [公司类别] 这一列来进行说明

这个 [公司类别] 一共有 (营运 和 营销) 这两个不同的内容,  我们需要实现的效果是, 如果上下两行的内容是一致的话, 就需要对单元格进行合并

2): 在同列不同行的背景下, 获取到内容相同的单元格坐标, 这里的坐标有 #1合并单元格所需的开始行(也就是你这个单元格需要从第几行开始合并)  #2 合并单元格所需的结束行(也就是你这个单元格需要从第几行结束合并)  #3: 需要对哪一列的数据进行合并  (因为我们这里是纵向合并, 所以firstCol 和 lastCol 都是同一个)     ps: 在poi中, 行和列的索引都是从0开始,  也就是Excel中的[A]列对应poi的0列,   [1]行对应的是0行

3): 在我截图发出的excel中,  B列的3到15行内容都是 [营运], B列的16到25行都是[营销],  那么我们就需要计算出他们在poi中对应的坐标,  也就是1列的2到14行是[营运], 1列的15到24行是[营销],  只要我们能够清楚的获取到这个坐标信息, 就可以对单元格进行合并了

那么我是怎么判断出excel单元格中, 上下两行的数据是否一致呢?

1):  我们写入excel数据的时候, 其实会对sql查询出来的结果数据进行遍历, 然后依次写入excel中, 那么我们在遍历的过程中, 可以把相同列的数据存在起来, 定义两个List<String>  分别存放上一行的单元格内容 (perColList),  和当前当的单元格内容 (currentColList)   记住这里的List是有序的, 会记录添加顺序

用一个Map<String,List<String>>装起来, Map的key是列的坐标(加入是B列, 对应存放的就是1),  Map的Value是B列每一行的单元格数据

2):

此时开始数据的遍历, 当我们在遍历到Excel中的第三行A列的时候, 此时我们就需要获取到第二行的数据, 因为第二行的数据并不是我们sql结果集中的数据, 所以我们可以在perColList中默认存放一个空的字符串, 然后在currentColList中存放 "10",    遍历到第三行B列的时候, perColList存放空字符串, currentColList中存放 "营运",   在遍历的过程中, 我们需要判断当前行的单元格内容是否跟上一行的单元格内容相同, 如果相同, 我们此时就应该把坐标记录起来了, 可以存在到一个对象中

 3): 当我们在遍历到第四行当时候, 此时我们这个对象就是  firstRow=2   lastRow=3  firstCol=1  lastCol=1   重点来了, 遍历到第五行的时候, 因为第四行的数据跟第五行的也一致, 那么我们此时就需要把对象里面的 lastRow 替换成 4,  直到遍历到第16行, 此时这个对象就应该是 firstRow=2   lastRow=15  firstCol=1  lastCol=1 

4): 现在程序遍历到第17行, 因为此时的B列内容变成了(营销),  那么当前行的内容跟上一行的内容不一致,  此时我们这里就需要构建新的对象了,  把之前我们构建好的那个 lastRow=15 的营运对象存放起来, 放到一个List中,  然后再重新构建这个单元格合并对象

5): 此时程序遍历到25行, 对象就是 firstRow=15   lastRow=24  firstCol=1  lastCol=1,  遍历到第26行当时候, 发现内容又不相同了, 就得重复之前的操作, 把 lastRow=24 的对象存在到List中, 开始构建新的单元格合并对象,  以此类推 , 最后我们的List中就会存在多个单元格合并对象,   然后我们头通过调用poi合并单元格的方法, 对这个List进行合并就达到这个效果了

代码实现:

/**
 * 构建需要合并单元格操作的对象信息
 * @param resultMergedColList 存在需要进行合并的单元格对象(最终结果)
 * @param mergedColMaps       Key:excel的第几列  Value:合并单元格对象
 * @param currentRow         当前行
 * @param currentRowValue     当前行的值
 * @param preRow           上一行
 * @param preRowValue         上一行的值
 * @param colNum           第几列
 */
private static void buildPoiMergedSameColInfo(List<PoiMergedSameCol> resultMergedColList, Map<Integer, List<PoiMergedSameCol>> mergedColMaps, Integer currentRow,
                                   String currentRowValue, Integer preRow, String preRowValue, int colNum) {
   if (StringUtils.isNotBlank(currentRowValue) && StringUtils.isNotBlank(preRowValue) && currentRowValue.equals(preRowValue)) {
      List<PoiMergedSameCol> poiMergedSameCols = mergedColMaps.get(colNum);
      if (CollectionUtils.isEmpty(poiMergedSameCols)) {
         PoiMergedSameCol poiMergedSameCol = new PoiMergedSameCol();
         poiMergedSameCol.setFirstRow(preRow);
         poiMergedSameCol.setLastRow(currentRow);
         poiMergedSameCol.setFirstCol(colNum);
         mergedColMaps.put(colNum, Lists.newArrayList(poiMergedSameCol));
      } else {
         Boolean existFlag = false;
         for (PoiMergedSameCol col : poiMergedSameCols) {
            if (preRow.equals(col.getLastRow())) {
               col.setLastRow(currentRow);
               existFlag = true;
            }
         }

         if (!existFlag) {
            //将之前生成的需要合并的单元格数据保存
            resultMergedColList.addAll(mergedColMaps.get(colNum));
            //构建新的需要保存的单元格数据
            PoiMergedSameCol poiMergedSameCol = new PoiMergedSameCol();
            poiMergedSameCol.setFirstRow(preRow);
            poiMergedSameCol.setLastRow(currentRow);
            poiMergedSameCol.setFirstCol(colNum);
            mergedColMaps.put(colNum, Lists.newArrayList(poiMergedSameCol));
         }
      }
   }
}

这只是个人的解决思路, 如果有更好的方法也大家也可以一起分享下

觉得文章不错的话, 麻烦点赞收藏啦

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

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

相关文章

【QT学习】01:helloqt

helloqt OVERVIEW helloqt一、helloqt1.使用向导创建2.手动创建3.pro文件4.Qt应用程序框架 二、按钮创建main.cppmywidget.cpp 三、对象模型1.对象树引入2.存在的问题 一、helloqt 创建一个qt项目&#xff0c;可以使用creator的向导创建&#xff0c;也可自己手动创建&#xff…

企业如何搭建矩阵内容,才能真正实现目的?

当下&#xff0c;新媒体矩阵营销已成为众多企业的营销选择之一&#xff0c;各企业可以通过新媒体矩阵实现扩大品牌声量、维持用户关系、提高销售业绩等不同的目的。 而不同目的的矩阵&#xff0c;它的内容运营模式会稍有差别&#xff0c;评价体系也会大不相同。 企业在运营某类…

性能优化-react路由懒加载和组件懒加载

背景 随着项目越来越大&#xff0c;打包后的包体积也越来越大&#xff0c;严重影响了首屏加载速度&#xff0c;需要对路由和组件做懒加载处理 主要用到了react中的lazy和Suspense。 废话不多说&#xff0c;直接上干货 路由懒加载 核心代码 import React, { lazy, Suspens…

精准感知+高效预判——城市“听诊器”防水患于未然

近期&#xff0c;全国多地遭遇暴雨猛袭&#xff0c;引发城市积涝&#xff0c;更有台风“杜苏芮”登陆后引发沿海内陆极端降水&#xff0c;各地排水防涝工作面临严峻考验。 快速定位城市排水管网系统的管道淤堵点&#xff0c;对河道水位、雨量情况、污水厂进水流量以及泵站运行情…

【云原生K8s】二进制部署单master K8s+etcd集群

一、实验设计 mater节点master01192.168.190.10kube-apiserver kube-controller-manager kube-scheduler etcd node节点node01192.168.190.20kubelet kube-proxy docker (容…

HTTP(超文本传输协议)学习

关于HTTP补学 一、HTTP能干什么 通过下图能够直观的看出&#xff1a;“交换数据 ” 二、HTTP请求例子 一个 HTTP 方法&#xff0c;通常是由一个动词&#xff0c;像 GET、POST 等&#xff0c;或者一个名词&#xff0c;像 OPTIONS、HEAD 等&#xff0c;来定义客户端执行的动作。…

Centos7.x修改密码

Centos7.x修改密码 root修改自己的密码 云服务器 云服务器则直接在控制台修改(例如阿里云服务器直接在阿里云服务器控制台修改&#xff0c;不赘述)命令行方式: 命令行输入: passwd 再两次输入新密码 root修改普通用户的密码 命令行方式: passwd 用户名再输入新的密码 普…

深入理解TCP三次握手:连接可靠性与安全风险

目录 导言TCP简介和工作原理的回顾TCP三次握手的目的和步骤TCP三次握手过程中可能出现的问题和安全风险为什么TCP三次握手是必要的&#xff1f;是否可以增加或减少三次握手的次数&#xff1f;TCP四次挥手与三次握手的异同点 导言 在网络通信中&#xff0c;TCP&#xff08;Tra…

7个更好用的数据可视化工具,建议收藏

在数据可视化工具的帮助下&#xff0c;设计师可以将数据转化为图像进行表达&#xff0c;让数据更加直观&#xff0c;更容易理解。今天本文会与打击分享7个好用的数据可视化工具&#xff0c;一起来get更好用的数据表达方式吧&#xff01; 1、即时设计 即时设计是一个非常受欢迎…

【js】FormData方法介绍和使用:

文章目录 一、接口使用FormData提交数据&#xff1a;二、FormData概述&#xff1a;三、FormData案例&#xff1a; 一、接口使用FormData提交数据&#xff1a; 二、FormData概述&#xff1a; 三、FormData案例&#xff1a; let formData new FormData() for (const key in tha…

一篇聊聊JVM优化:堆

一、Java 堆概念 1、简介 对于Java应用程序来说&#xff0c;Java堆&#xff08;Java Heap&#xff09;是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享 的一块内存区域&#xff0c;在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例&#xff0c;Java 世界…

成为“黑客“前,必须经过的“学习路线“!!!

成为"黑客"前&#xff0c;必须经过的"学习路线"&#xff01;&#xff01;&#xff01; 最近很多小伙伴在看了我的文章后&#xff0c;有一个共同的问题&#xff0c;"我们是小白&#xff0c;我们没有基础&#xff0c;我们如何通过自学&#xff0c;就可…

vue3数组V-for中动态生成$refs

vue3数组V-for中动态生成$refs 在项目实际需求中&#xff0c;可能会遇到使用数组动态生成$refs,根据官方参考&#xff0c;采用了以下方式实现 <template><div class"content"><ul v-for"(item, index) in editableTabs" :key"item.n…

2023全网最全的爆款抓包工具,各有千秋

在处理IP网络的故障时&#xff0c;经常使用以太网抓包工具来查看和抓取IP网络上某些端口或某些网段的数据包&#xff0c;并对这些数据包进行分析&#xff0c;定位问题。 在 IMON项目里&#xff0c;使用抓包工具抓包进行分析的场景在EPG采集、引流模块和软终端监看模块&#xff…

【练】创建两个线程:其中一个线程拷贝图片的前半部分,另一个线程拷贝后半部分

方法一&#xff1a; 先在主函数创建并清空拷贝的目标文件&#xff0c;再创建两个线程&#xff0c;在两个线程内部同时打开要读取的文件以及要拷贝的目标文件&#xff08;两个线程不共用同一份资源&#xff09;。 使用到的函数&#xff1a; 标准IO函数&#xff08;fprintf&…

(数据库系统概论|王珊)第一章绪论-第一节:数据库系统概论

目录 一&#xff1a;四大基本概念 &#xff08;1&#xff09;数据(Data) &#xff08;2&#xff09;数据库(DataBase,DB) &#xff08;3&#xff09;数据库管理系统(DataBase Management System,DBMS) &#xff08;4&#xff09;数据库系统(Database System&#xff0c;DBS…

HBN:2023年原生白护肤白皮书(附下载)

关于报告的所有内容&#xff0c;公众【营销人星球】获取下载查看 核心观点 调研数据表明&#xff0c;近九成的消费者对自己肤色不满&#xff0c;其中偏黄、偏黑是大家的核心困扰&#xff08;图1-1&#xff09;。在此情况下&#xff0c;“美白” 在各社媒平台的搜素量近年来一…

开利网络受邀出席数利丰应用研讨会 分享企业数字化转型落地经验

数利丰应用研讨会在广州举办。本次研讨会的主题为「聚焦数据价值&#xff0c;引领数字转型」。 广州市开利网络科技有限公司总经理、和合生态联合发起人付立军先生受邀出席研讨会并同在座40余国内外企业创始人与高管共同探讨企业经营所面临的共性问题&#xff0c;分享在企业数…

【力扣】19. 删除链表的倒数第 N 个结点 <链表指针、快慢指针>

【力扣】19. 删除链表的倒数第 N 个结点 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n…

【java安全】原生反序列化利用链JDK7u21

文章目录 【java安全】原生反序列化利用链JDK7u21前言原理equalsImpl()如何调用equalsImpl()&#xff1f;HashSet通过反序列化间接执行equals()方法如何使hash相等&#xff1f; 思路整理POCGadget为什么在HashSet#add()前要将HashMap的value设为其他值&#xff1f; 【java安全】…