package com.mes.utils.excel; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.write.handler.RowWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; /** * @Author : zhoush * @Date: 2025/5/12 16:55 * @Description: */ public class ExcelMergeStrategy implements RowWriteHandler { /** * 主键下标 */ private Integer primaryKeyIndex; /** * 需要合并的列的下标集合 */ private final List mergeColumnIndexList = new ArrayList<>(); /** * 数据类型 */ private final Class elementType; public ExcelMergeStrategy(Class elementType) { this.elementType = elementType; } @Override public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) { // 判断是否为标题 if (isHead) { return; } // 获取当前工作表 Sheet sheet = writeSheetHolder.getSheet(); // 初始化主键下标和需要合并字段的下标 if (primaryKeyIndex == null) { this.initPrimaryIndexAndMergeIndex(writeSheetHolder); } // 判断是否需要和上一行进行合并 // 不能和标题合并,只能数据行之间合并 if (row.getRowNum() <= 1) { return; } // 获取上一行数据 Row lastRow = sheet.getRow(row.getRowNum() - 1); // 将本行和上一行是同一类型的数据(通过主键字段进行判断),则需要合并 if (lastRow.getCell(primaryKeyIndex).getStringCellValue().equalsIgnoreCase(row.getCell(primaryKeyIndex).getStringCellValue())) { for (Integer mergeIndex : mergeColumnIndexList) { CellRangeAddress cellRangeAddress = new CellRangeAddress(row.getRowNum() - 1, row.getRowNum(), mergeIndex, mergeIndex); sheet.addMergedRegionUnsafe(cellRangeAddress); } } } /** * 初始化主键下标和需要合并字段的下标 * * @param writeSheetHolder WriteSheetHolder */ private void initPrimaryIndexAndMergeIndex(WriteSheetHolder writeSheetHolder) { // 获取当前工作表 Sheet sheet = writeSheetHolder.getSheet(); // 获取标题行 Row titleRow = sheet.getRow(0); // 获取所有属性字段 Field[] fields = this.elementType.getDeclaredFields(); // 遍历所有字段 for (Field field : fields) { // 获取@ExcelProperty注解,用于获取该字段对应列的下标 ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); // 判断是否为空 if (null == excelProperty) { continue; } // 获取自定义注解,用于合并单元格 ExcelMerge excelMerge = field.getAnnotation(ExcelMerge.class); // 判断是否需要合并 if (null == excelMerge) { continue; } for (int i = 0; i < fields.length; i++) { Cell cell = titleRow.getCell(i); if (null == cell) { continue; } // 将字段和表头匹配上 if (excelProperty.value()[0].equalsIgnoreCase(cell.getStringCellValue())) { if (excelMerge.isPrimaryKey()) { primaryKeyIndex = i; } if (excelMerge.merge()) { mergeColumnIndexList.add(i); } } } } // 没有指定主键,则异常 if (null == this.primaryKeyIndex) { throw new IllegalStateException("使用@ExcelMerge注解必须指定主键"); } } }