使用EasyExcel动态合并单元格(模板方法)

发布于:2025-07-11 ⋅ 阅读:(10) ⋅ 点赞:(0)

1、导入EasyExcel依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>4.0.3</version>
</dependency>

2、编写实体类

@Data
publci class Student{ 
    @ExcelProperty("姓名")
    private String name;
}

3、具体方法如下

调用方法(除了基础的模板地址和数据外,增加了合并列索引和分组函数)

/**
     * 填充模板并合并单元格
     *
     * @param tempName 模板名称
     * @param list 填充数据集合
     * @param resultMap 特殊数据替换map
     * @param targetFilePath 导出地址
     * @param excelTypeEnum  ecxcel文件类型
     * @param mergeColumnIndex sheet中需要合并的列的索引
     * @param groupFunction    分组函数
     * @param <T>
     */
    public static <T> void buildMergeExcel(String tempName, List<T> list, Map<String, String> resultMap, String targetFilePath, ExcelTypeEnum excelTypeEnum
            , int[] mergeColumnIndex, Function<T, String> groupFunction) {
        try {
            // 获取模板文件
            ClassPathResource classPathResource = new ClassPathResource("template/" + tempName);
           
            // 行计数,初始值取列头行数
            int lineCount = 1;
            // 分别填充list数据和特殊数据
            ExcelWriter excelWriter = EasyExcel.write(new File(LocalStoragePropertiesConstants.LOCAL_PROFILE + targetFilePath))
                    .excelType(excelTypeEnum)
                    .withTemplate(classPathResource.getInputStream()).build();
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            List<CellRangeAddress> rangeCellList = createCellRange(list, mergeColumnIndex, lineCount, groupFunction);
            WriteSheet writeSheet = EasyExcel.writerSheet()
                    .registerWriteHandler(new MergeCellRangeWriteHandler(rangeCellList)).build();
            excelWriter.fill(list, fillConfig, writeSheet);
            excelWriter.fill(resultMap, writeSheet);
            list.clear();
            excelWriter.finish();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

提前计算合并的单元格,在sheet创建后一次性合并

 /**
     * 生成合并区域
     *
     * @param detailList       数据列表
     * @param mergeColumnIndex 要合并的列索引
     * @param startRowIndex    起始行(含表头时,表头行数)
     * @param groupFunction    分组函数,如 e -> e.get某字段()
     * @return 合并区域集合
     */
    public static <T> List<CellRangeAddress> createCellRange(List<T> detailList, int[] mergeColumnIndex, int startRowIndex, Function<T, String> groupFunction) {
        if (detailList == null || detailList.isEmpty()) {
            return Collections.emptyList();
        }
        // 计算每个key下的数量
        Map<String, Long> groupMap = new LinkedHashMap<>();
        for (T item : detailList) {
            String key = groupFunction.apply(item);
            groupMap.put(key, groupMap.getOrDefault(key, 0L) + 1);
        }

        List<CellRangeAddress> rangeCellList = new ArrayList<>();
        // 当前行数
        int lineCount = startRowIndex;

        for (Map.Entry<String, Long> entry : groupMap.entrySet()) {
            int count = entry.getValue().intValue();
            if (count > 1) {
                int endRowIndex = lineCount + count - 1;
                for (int columnIndex : mergeColumnIndex) {
                    rangeCellList.add(new CellRangeAddress(lineCount, endRowIndex, columnIndex, columnIndex));
                }
            }
            lineCount += count;
        }

        return rangeCellList;
    }

单元格合并策略

/**
 * easyExcel 合并单元格
 */
public class MergeCellRangeWriteHandler implements SheetWriteHandler {

    private final List<CellRangeAddress> rangeCellList;

    public MergeCellRangeWriteHandler(List<CellRangeAddress> rangeCellList) {
        this.rangeCellList = (rangeCellList == null) ? Collections.emptyList() : rangeCellList;
    }

    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        Sheet sheet = writeSheetHolder.getSheet();
        for (CellRangeAddress cellRangeAddress : this.rangeCellList) {
            sheet.addMergedRegionUnsafe(cellRangeAddress);
        }
    }
}

调用如下:

        String sheetTitle = "模板名称";
        FileResultVO fileResultVO = ExpandFileUtil.generateFilePath(EXTENSION_XLSX, sheetTitle + UUID.randomUUID(), EXTENSION_XLSX);
        ExpandEasyExcelUtil.buildMergeExcel(
                "MB.xlsx",
                dataList, null, fileResultVO.getFilePath(),
                ExcelTypeEnum.XLSX,
                new int[]{0, 1, 2, 3, 4},
                Student::getName
        );

工作中实测使用,有什么问题欢迎留言交流


网站公告

今日签到

点亮在社区的每一天
去签到