需求背景:
在导出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)); } } } }
这只是个人的解决思路, 如果有更好的方法也大家也可以一起分享下
觉得文章不错的话, 麻烦点赞收藏啦