使用EasyExcel 导出复杂的合并单元格

引入pom.xml

java 复制代码
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
java 复制代码
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.HashMap;
import java.util.Map;

public class CustomMergeStrategy extends AbstractMergeStrategy {
    private final int[] mergeColumns;  // 需要合并的列索引
    private final int startRow;        // 开始合并的行号
    private Map<Integer, MergeRange> lastValueMap = new HashMap<>();

    public CustomMergeStrategy(int[] mergeColumns, int startRow) {
        this.mergeColumns = mergeColumns;
        this.startRow = startRow;
    }

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        int currentRow = cell.getRowIndex();
        if (currentRow <= startRow) return;

        for (int col : mergeColumns) {
            if (cell.getColumnIndex() == col) {
                String currentValue = cell.getStringCellValue();
                MergeRange lastRange = lastValueMap.get(col);

                if (lastRange != null && lastRange.value.equals(currentValue)) {
                    // 合并到上一个范围
                    sheet.addMergedRegion(new CellRangeAddress(
                            lastRange.startRow, currentRow, col, col
                    ));
                    lastValueMap.put(col, new MergeRange(
                            lastRange.startRow, currentValue
                    ));
                } else {
                    // 新值范围开始
                    lastValueMap.put(col, new MergeRange(
                            currentRow, currentValue
                    ));
                }
                break;
            }
        }
    }

    private static class MergeRange {
        int startRow;
        String value;

        MergeRange(int startRow, String value) {
            this.startRow = startRow;
            this.value = value;
        }
    }
}

完成列头合并

复制代码
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
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.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

public class ComplexHeadStrategy implements CellWriteHandler {

    public void afterCellDispose(WriteSheetHolder writeSheetHolder,
                                 WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

        if (head.getColumnIndex() == 0 || head.getColumnIndex() == 4) { // 第一列和第五列
            Sheet sheet = writeSheetHolder.getSheet();
            if (cell.getRowIndex() == 0) { // 首行
                // 合并"引导车误差分析"标题
                sheet.addMergedRegion(new CellRangeAddress(
                        0, 0, 0, 1 // 合并前两列
                ));
                sheet.addMergedRegion(new CellRangeAddress(
                        0, 0, 4, 5 // 合并最后两列
                ));
            }
        }
    }
}

Demo实现

复制代码
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import lombok.Data;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;

import java.util.ArrayList;
import java.util.List;

public class MergeCellExportDemo {
    public static void main(String[] args) {
        List<FlightData> dataList = new ArrayList<>();
        dataList.add(new FlightData("0.12", "0.5", "B-1234", "A01", "0.08", "0.3"));
        dataList.add(new FlightData("0.15", "0.6", "B-5678", "B02", "0.09", "0.4"));

        // 自定义合并策略(合并机号列)
        CustomMergeStrategy mergeStrategy = new CustomMergeStrategy(
                new int[]{2, 3}, 1 // 合并第3、4列(机号/机位)
        );


        // 设置表头样式
        WriteCellStyle headStyle = new WriteCellStyle();
        headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        WriteCellStyle contentStyle = new WriteCellStyle();
        contentStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        HorizontalCellStyleStrategy styleStrategy =
                new HorizontalCellStyleStrategy(headStyle, contentStyle);

        EasyExcel.write("flight_report.xlsx")
                .head(FlightData.class)
                .registerWriteHandler(new ComplexHeadStrategy()) // 复杂表头处理
                .registerWriteHandler(mergeStrategy)
                .registerWriteHandler(styleStrategy)
                .sheet("航班数据")
                .doWrite(dataList);
    }

    // 数据模型类(对应图片中的列)
    @Data
    static class FlightData {
        @ExcelProperty({"引导车开始", "开始_分析误差"})
        private String startAnalysisError;

        @ExcelProperty({"引导车开始", "开始_终端误差(s)"})
        private String startTerminalError;

        @ExcelProperty("机号")
        private String flightNumber;

        @ExcelProperty("机位")
        private String gate;

        @ExcelProperty({"引导车结束", "结束_分析误差"})
        private String endAnalysisError;

        @ExcelProperty({"引导车结束", "结束_终端误差(s)"})
        private String endTerminalError;


        public FlightData(String startAnalysisError, String startTerminalError, String flightNumber,
                          String gate, String endAnalysisError, String endTerminalError) {
            this.startAnalysisError=startAnalysisError;
            this.startTerminalError=startTerminalError;
            this.flightNumber=flightNumber;
            this.gate=gate;
            this.endAnalysisError=endAnalysisError;
            this.endTerminalError=endTerminalError;
        }


    }
}
相关推荐
笨蛋不要掉眼泪14 分钟前
Spring Boot集成腾讯云人脸识别实现智能小区门禁系统
java·数据库·spring boot
桃源学社(接毕设)17 分钟前
云计算下数据隐私保护系统的设计与实现(LW+源码+讲解+部署)
java·云计算·毕业设计·swing·隐私保护
用户03321266636732 分钟前
Java 将 Excel 转换为 HTML:解锁数据在线展示的无限可能
java·excel
字节跳跃者1 小时前
SpringBoot + MinIO + kkFile 实现文件预览,这样操作更安全!
java·后端·程序员
天天摸鱼的java工程师1 小时前
OpenFeign 首次调用卡 3 秒?八年老开发扒透 5 个坑,实战优化到 100ms
java·后端·面试
whitepure1 小时前
万字详解Java集合
java·后端
华仔啊1 小时前
乐观锁、悲观锁和分布式锁,你用对了吗?
java·分布式
自由的疯1 小时前
Java下载图片并导出压缩包
java·后端·trae
tanxiaomi1 小时前
Spring面试宝典:Spring IOC的执行流程解析
java·spring·面试
NightDW2 小时前
连续周更任务模块的设计与实现
java·后端·mysql