1.先按照mergekey排序,然后相同的key分组,只保留第一个对象,其他对象属性都设置为null.
2.
ClassPathResource resource = new ClassPathResource("template/template.xlsx");
ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(resource.getInputStream()).build();
WriteSheet writeSheet = EasyExcel.writerSheet().registerWriteHandler(new PartBoxMergeStrategyNew(16, 27, 11, details.size())).build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(header, writeSheet);
excelWriter.fill(details, fillConfig, writeSheet);
excelWriter.finish();
3.
public class PartBoxMergeStrategyNew implements CellWriteHandler {
// 需要合并的起始列索引(从0开始)
private final int startMergeColumns;
// 需要合并的结束列索引(从0开始)
private final int endMergeColumns;
// rowIndex 从0 开始
private final int startMergeRowIndex;
// rowIndex 从0 开始s
private final int lastRowIndex;
public PartBoxMergeStrategyNew(int startMergeColumns, int endMergeColumns, int startMergeRowIndex, int rowSize) {
this.startMergeColumns = startMergeColumns;
this.endMergeColumns = endMergeColumns;
this.startMergeRowIndex = startMergeRowIndex;
this.lastRowIndex = rowSize-1+startMergeRowIndex;
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
// 跳过表头和空值单元格
if (isHead) return;
Sheet sheet = writeSheetHolder.getSheet();
int col = cell.getColumnIndex();
int rowIndex = cell.getRowIndex();
boolean lastFlag = rowIndex == lastRowIndex;
if(rowIndex <= startMergeRowIndex) return;
if (col >= startMergeColumns && col <= endMergeColumns) {
mergeAdjacentCells(sheet, cell, rowIndex, col, lastFlag);
}
}
//row是从0开始的
private void mergeAdjacentCells(Sheet sheet, Cell cell, int currentRowIndex, int currentColIndex, boolean lastFlag) {
int firstRow = currentRowIndex;
int lastRow = currentRowIndex;
// 向上查找合并起始行(跳过空值)
// 这里是要等到最后一个空值才进行合并
Cell curr = cell.getSheet().getRow(currentRowIndex).getCell(startMergeColumns);
while (firstRow -1 >= startMergeRowIndex) {
Cell prev = cell.getSheet().getRow(firstRow -1).getCell(startMergeColumns);
if(lastFlag) {
if(getCellValue(curr)==null&&getCellValue(prev)==null) {
//最后一行,当前为空,前一个为空,则继续找,说明还没有找到最前面的一行不为空的,需要继续
firstRow--;
}else if(getCellValue(curr)==null&&getCellValue(prev)!=null){
//最后一行,当前为空,前一个不为空,说明已经找到了需要合并的最前面的一行,同时当前也是空的,所以lastRow不用-1
firstRow--;
break;
}else if(getCellValue(curr)!=null&&getCellValue(prev)!=null){
//最后一行,当前不为空,前一个也不为空,相邻的两行都不是空的,无需合并
lastRow--;
break;
}else{
//最后一行,当前不为空,前一个为空,当前不为空,则说明当前行不是一伙的,所以要-1,前一行为空,说明这一行的领头羊在前面
firstRow--;
}
}else{
if(getCellValue(curr)==null) {//不是最后一行,当前为空,则需要等到不为空的行再往上面找,不需要触发合并,
break;
}else{
if(getCellValue(prev)==null){//不是最后一行,当前不为空,前一个为空,则继续找
firstRow--;
}else{//不是最后一行,当前不为空,前一个不为空,则不用找,当前不为空,说明跟前面不是一伙的,
// 前一个不为空,则说明已经找到了最前面的领头的
firstRow--;
lastRow--;
break;
}
}
}
}
// cur=17 16
// 执行合并(如果跨越多行)
if (lastRow > firstRow) {
sheet.addMergedRegionUnsafe(new CellRangeAddress(
firstRow , lastRow , currentColIndex, currentColIndex
));
}
}
private Object getCellValue(Cell cell) {
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
return cell.getNumericCellValue();
case BOOLEAN:
return cell.getBooleanCellValue();
default:
return null;
}
}
}