EasyExcel 动态表头 + 数据单元格合并

原文地址:https://blog.csdn.net/qq_40623878/article/details/122686482

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.3.2</version>
        </dependency>
package test2;

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.List;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2024-04-22 13:50
 */
public class AssignRowsAndColumnsToMergeStrategy extends AbstractMergeStrategy {
    // 合并坐标集合
    private List<CellRangeAddress> cellRangeAddresses;

    // 构造
    public AssignRowsAndColumnsToMergeStrategy() {
    }

    public AssignRowsAndColumnsToMergeStrategy(List<CellRangeAddress> cellRangeAddresses) {
        this.cellRangeAddresses = cellRangeAddresses;
    }

    /**
     * 合并操作:对每个单元格执行!!!
     *
     * @param sheet            sheet对象
     * @param cell             当前单元格
     * @param head             表头对象
     * @param relativeRowIndex 相关行索引
     */
    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        /*
         * 合并单元格
         *
         * 由于merge()方法会在写每个单元格(cell)时执行,因此需要保证合并策略只被添加一次。否则如果每个单元格都添加一次
         * 合并策略,则会造成重复合并。例如合并A2:A3,当cell为A2时,合并A2:A3,但是当cell为A3时,又要合并A2:A3,而此时
         * 的A2已经是之前的A2和A3合并后的结果了。
         * 由于此处的表头占了两行,因此数据单元格是从(2, 0)开始的,所以就对这个单元格(cell.getRowIndex() == 2 && cell.getColumnIndex() == 0)
         * 添加一次合并策略就可以了。如果表头只有一行,则判断条件改为「cell.getRowIndex() == 1 && cell.getColumnIndex() == 0」就可以了。
         */
        if (cell.getRowIndex() == 2 && cell.getColumnIndex() == 0) {
            for (CellRangeAddress item : cellRangeAddresses) {
                sheet.addMergedRegion(item);
            }
        }

        /*
         * 如果不作判断,可以使用addMergedRegionUnsafe()方法,
         * 这样生成的Excel文件可以打开,只是打开时会提示内容有问题,修复后可以打开
         */
        // for (CellRangeAddress item : cellRangeAddresses) {
        //     sheet.addMergedRegionUnsafe(item);
        // }
    }
}

package test2;

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import lombok.Data;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2024-04-22 13:48
 */
@Data
public class MergeSameRowsStrategy implements CellWriteHandler {
    private int[] mergeColumnIndex;
    private int mergeRowIndex;

    public MergeSameRowsStrategy() {
    }

    public MergeSameRowsStrategy(int mergeRowIndex, int[] mergeColumnIndex) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        // 当前行
        int curRowIndex = cell.getRowIndex();
        // 当前列
        int curColIndex = cell.getColumnIndex();

        if (curRowIndex > mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }
    }


    /**
     * 当前单元格向上合并
     *
     * @param writeSheetHolder sheet保持对象
     * @param cell             当前单元格
     * @param curRowIndex      当前行
     * @param curColIndex      当前列
     */
    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        // 获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并
        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();

        // 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
        if (curData.equals(preData)) {
            Sheet sheet = writeSheetHolder.getSheet();
            List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergedRegions.size() && !isMerged; i++) {
                CellRangeAddress cellRangeAddr = mergedRegions.get(i);
                // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
                    sheet.removeMergedRegion(i);
                    cellRangeAddr.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellRangeAddr);
                    isMerged = true;
                }
            }
            // 若上一个单元格未被合并,则新增合并单元
            if (!isMerged) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
                sheet.addMergedRegion(cellRangeAddress);
            }
        }
    }
}

package test2;

import com.alibaba.excel.EasyExcel;
import org.apache.poi.ss.util.CellRangeAddress;
import org.junit.Test;

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

/**
 * @author TANGSHUAI
 * @version 1.0
 * @date 2024-04-22 13:50
 */
public class MergeTest {



    private static String fileName = "D:\\" + System.currentTimeMillis() + ".xlsx";

    @Test
    public void test01() {
        EasyExcel.write(fileName)
                .head(header())
                // 合并策略:合并相同数据的行。第一个参数表示从哪一行开始进行合并,由于表头占了两行,因此从第2行开始(索引从0开始)
                // 第二个参数是指定哪些列要进行合并
                .registerWriteHandler(new MergeSameRowsStrategy(2, new int[]{0, 1, 2, 3, 8, 9}))
                // 注意:需要先调用registerWriteHandler()再调用sheet()方法才能使合并策略生效!!!
                .sheet("模板")
                .doWrite(data());
    }

    @Test
    public void test02() {
        // 合并策略:指定要合并的行列范围
        int[][] toMergeRows = {{2, 3}, {4, 6}};
        int[] toMergeColumns = {0, 1, 2, 3, 8, 9};
        List<CellRangeAddress> list = new ArrayList<>();
        for (int[] toMergeRow : toMergeRows) {
            for (int toMergeColumn : toMergeColumns) {
                list.add(new CellRangeAddress(toMergeRow[0], toMergeRow[1], toMergeColumn, toMergeColumn));
            }
        }

        EasyExcel.write(fileName)
                .head(header())
                .registerWriteHandler(new AssignRowsAndColumnsToMergeStrategy(list))
                .sheet("模板")
                .doWrite(data());
    }


    /**
     * 创建表头
     */
    private List<List<String>> header() {
        List<List<String>> headers = new ArrayList<>();
        headers.add(Arrays.asList("提交人用户名", "提交人用户名"));
        headers.add(Arrays.asList("提交人姓名", "提交人姓名"));
        headers.add(Arrays.asList("创建时间", "创建时间"));
        headers.add(Arrays.asList("更新时间", "更新时间"));
        headers.add(Arrays.asList("学习经历", "时间"));
        headers.add(Arrays.asList("学习经历", "学校"));
        headers.add(Arrays.asList("学习经历", "专业"));
        headers.add(Arrays.asList("学习经历", "学位"));
        headers.add(Arrays.asList("工作单位", "工作单位"));
        headers.add(Arrays.asList("国籍", "国籍"));
        headers.add(Arrays.asList("获奖经历", "时间"));
        headers.add(Arrays.asList("获奖经历", "何种奖励"));
        return headers;
    }

    /**
     * 创建数据
     */
    private List<List<Object>> data() {
        List<List<Object>> data = new ArrayList<>();
        data.add(Arrays.asList("fengqingyang", "风清扬", "2022-01-25 11:08", "2022-01-25 11:08",
                "2013.9 ~ 2017.7", "华山派", "剑宗", "剑宗高手", "隐居思过崖", "中国", "2015.12", "华山剑法高手"));
        data.add(Arrays.asList("fengqingyang", "风清扬", "2022-01-25 11:08", "2022-01-25 11:08",
                "2017.9 ~ 2020.7", "独孤求败", "独孤剑法", "剑术通神", "隐居思过崖", "中国", "2019.12", "剑法高手"));
        data.add(Arrays.asList("linghuchong", "令狐冲", "2022-01-25 12:08", "2022-01-25 12:08",
                "2020.9 ~ 2024.7", "华山派", "气宗", "气宗庸手", "漂泊江湖", "中国", "2022.12", "华山剑法庸手"));
        data.add(Arrays.asList("linghuchong", "令狐冲", "2022-01-25 12:08", "2022-01-25 12:08",
                "2024.9 ~ 2027.7", "风清扬", "独孤剑法", "剑法高手", "漂泊江湖", "中国", "2025.12", "剑法高手"));
        data.add(Arrays.asList("linghuchong", "令狐冲", "2022-01-25 12:08", "2022-01-25 12:08",
                "2027.9 ~ 2030.7", "少林寺", "易筋经", "内功高手", "漂泊江湖", "中国", "2029.12", "内功高手"));
        return data;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于使用 EasyExcel 动态合并表头,您可以按照以下步骤操作: 1. 导入 EasyExcel 的相关依赖包,确保您的项目中已经正确引入了 EasyExcel。 2. 创建一个表头合并的实体类,例如 `MergeHeader`,用于描述每个合并表头单元格的位置和内容。该实体类可以包含以下属性: - `firstRow`:合并表头起始行索引(从0开始计数) - `lastRow`:合并表头结束行索引(从0开始计数) - `firstCol`:合并表头起始列索引(从0开始计数) - `lastCol`:合并表头结束列索引(从0开始计数) - `content`:表头内容 3. 创建一个 List,用于存储所有的 MergeHeader 对象,表示所有需要合并表头。 4. 使用 EasyExcel 提供的 API 进行表格的写入,并设置合并表头的样式。示例代码如下: ```java // 创建 ExcelWriter 对象 ExcelWriter excelWriter = EasyExcel.write("output.xlsx").build(); // 设置表头样式 CellStyle headerStyle = excelWriter.getWorkbook().createCellStyle(); headerStyle.setAlignment(HorizontalAlignment.CENTER); // 设置居中对齐 // 设置表头字体 Font headerFont = excelWriter.getWorkbook().createFont(); headerFont.setBold(true); // 设置加粗 headerStyle.setFont(headerFont); // 写入数据 Sheet sheet = excelWriter.write(...).sheet(); // 写入表头数据 List<List<String>> headers = new ArrayList<>(); // 添加表头数据 // ... // 合并表头单元格 for (MergeHeader mergeHeader : mergeHeaders) { CellRangeAddress cellRangeAddress = new CellRangeAddress(mergeHeader.getFirstRow(), mergeHeader.getLastRow(), mergeHeader.getFirstCol(), mergeHeader.getLastCol()); sheet.addMergedRegion(cellRangeAd

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值