本文主要讲解关于EasyExcel如何实现单元格合并相关内容,让我们来一起学习下吧!
作为一名光荣的crud(搬砖)工程师,导出Excel可是必备的技能树(❛‿˂̵✧),使用原生的poi导出代码既复杂又容易出bug,日常工作中更多的时使用阿里开源的EasyExcel;文档中有关合并单元格的例子不太满足日常工作的需要,本篇文章自定义了一个合并的策略,实现行内容相同的合并。
合并策略
/**
* 行内容相同合并策略
*/
public static class RowContentSameMergeStrategy implements RowWriteHandler {
/**
* 数据量,即导出数据的行数,不包含表头
*/
private final int dataSize;
/**
* 表头数量,即导出列的数量
*/
private final int headSize;
/**
* 数据的开始行
*/
private Integer startRow;
/**
* 合并的高度
*/
private int[][] mergeHeight;
public RowContentSameMergeStrategy(int dataSize, int headSize) {
this.dataSize = dataSize - 1;
this.headSize = headSize;
}
@Override
public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
if (isHead) {
return;
}
// 定义数据的开始行
if (startRow == null) {
startRow = row.getRowNum();
}
// 没到最后一行,直接返回
if (relativeRowIndex != dataSize) {
return;
}
// 定义数据的结束行
int endRow = row.getRowNum();
// 定义二维数组记录合并的高度
mergeHeight = new int[endRow + 1][headSize + 1];
// 全部sheet已经加载完毕
// 需要进行单元格的合并
// 这里处理的是行合并,不处理列合并
// 读取每列
for (int cellIndex = 0; cellIndex < headSize; cellIndex++) {
// startRowPoint=开始行指针 endRowPoint=结束行指针 preCellIndex=前一列单元格
int startRowPoint = startRow, endRowPoint = startRow, preCellIndex = cellIndex - 1;
// startRowCell=开始行当前单元格的内容
String startRowCell = null;
for (; endRowPoint <= endRow; endRowPoint++) {
if (startRowPoint == endRowPoint) {
startRowCell = writeSheetHolder.getSheet().getRow(startRowPoint).getCell(cellIndex).getStringCellValue();
continue;
}
if (preCellIndex >= 0 ) {
// 前一个格子的高度
int preHeight = mergeHeight[startRowPoint][preCellIndex];
// 若当前格子合并的高度已经超过了前一列,直接进行重置处理
if (endRowPoint - startRowPoint + 1 > preHeight) {
// 需要进行合并
if (startRowPoint != endRowPoint - 1) {
merge(writeSheetHolder, startRowPoint, endRowPoint - 1, cellIndex);
}
// 重置两个指针,由于endPoint会固定往后走一位,所以将start调整到当前位置
startRowPoint = endRowPoint;
endRowPoint = endRowPoint - 1;
continue;
}
}
// 计算当前行数据是否相同
String endCell = writeSheetHolder.getSheet().getRow(endRowPoint).getCell(cellIndex).getStringCellValue();
// 最后一行的特殊处理
// 如果相同直接合并单元格
if (endRowPoint == endRow && StringUtils.equals(startRowCell, endCell)) {
merge(writeSheetHolder, startRowPoint, endRowPoint, cellIndex);
continue;
}
// 不相同 -> 需要进行单元格的合并
if (!StringUtils.equals(startRowCell, endCell)) {
// 需要进行合并
if (startRowPoint != endRowPoint - 1) {
merge(writeSheetHolder, startRowPoint, endRowPoint - 1, cellIndex);
}
// 重置两个指针,由于endPoint会固定往后走一位,所以将start调整到当前位置
startRowPoint = endRowPoint;
endRowPoint = endRowPoint - 1;
}
// 相同 -> 继续读取下一行
}
}
}
private void merge(WriteSheetHolder writeSheetHolder, int startRowPoint, int endRowPoint, int cellIndex) {
// 计算高度
int height = endRowPoint - startRowPoint + 1;
CellRangeAddress cellRangeAddress = new CellRangeAddress(
startRowPoint, endRowPoint,
cellIndex, cellIndex
);
// 维护高度
for (int i = startRowPoint; i <= endRowPoint; i++) {
mergeHeight[i][cellIndex] = height;
}
writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
}
}
策略使用
public static void main(String[] args) {
List<DemoData> list = new ArrayList<>();
list.add(new DemoData("us", "x", "y1", "z1"));
list.add(new DemoData("us", "x", "y1", "z2"));
list.add(new DemoData("us", "x", "y1", "z3"));
list.add(new DemoData("jp", "x", "y2", "z1"));
list.add(new DemoData("jp", "x", "y2", "z2"));
list.add(new DemoData("jp", "x", "y2", "z3"));
String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
// 自定义合并单元格策略
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class)
.registerWriteHandler(new RowContentSameMergeStrategy(list.size(), 4))
.sheet("模板")
.doWrite(list);
}
以上就是关于EasyExcel如何实现单元格合并相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!