Apache poi 对单元格进行合并

需求背景:

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

期望达到的效果:

Apache poi 对单元格进行合并_第1张图片

poi 实现合并单元格的方法  

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

Apache poi 对单元格进行合并_第2张图片

Apache poi 对单元格进行合并_第3张图片

个人的实现思路:

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  分别存放上一行的单元格内容 (perColList),  和当前当的单元格内容 (currentColList)   记住这里的List是有序的, 会记录添加顺序

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

2):

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

Apache poi 对单元格进行合并_第4张图片

 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进行合并就达到这个效果了

代码实现:

Apache poi 对单元格进行合并_第5张图片

/**
 * 构建需要合并单元格操作的对象信息
 * @param resultMergedColList 存在需要进行合并的单元格对象(最终结果)
 * @param mergedColMaps       Key:excel的第几列  Value:合并单元格对象
 * @param currentRow         当前行
 * @param currentRowValue     当前行的值
 * @param preRow           上一行
 * @param preRowValue         上一行的值
 * @param colNum           第几列
 */
private static void buildPoiMergedSameColInfo(List resultMergedColList, Map> mergedColMaps, Integer currentRow,
                                   String currentRowValue, Integer preRow, String preRowValue, int colNum) {
   if (StringUtils.isNotBlank(currentRowValue) && StringUtils.isNotBlank(preRowValue) && currentRowValue.equals(preRowValue)) {
      List 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));
         }
      }
   }
}

Apache poi 对单元格进行合并_第6张图片

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

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

你可能感兴趣的:(excel,java)