EasyExcel导出excel自定义合并单元格策略

本文分享了如何使用EasyExcel 2.2.6版本实现单元格合并策略,包括创建自定义工具类和控制器实战示例,适用于处理数据时合并特定行列的Excel导出需求。

分享一个导出excel的常用方法,希望可以给大家带来帮助。

easyexcel的版本不同,单元格合并策略实现的方法不同,所以能需要拷贝工具类的小伙伴,导入对应的maven包

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

单元合并策略工具类

package com.util;

import com.alibaba.excel.metadata.CellData;
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.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;

public class ExcelFillCellMergeStrategy implements CellWriteHandler {

    private int[] mergeColumnIndex;
    private int mergeRowIndex;

    public ExcelFillCellMergeStrategy() {
    }

    public ExcelFillCellMergeStrategy(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 afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
        //当前行
        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
     * @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> mergeRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
                CellRangeAddress cellRangeAddr = mergeRegions.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);
            }
        }
    }

}

实战中controller调用

  @GetMapping("/export")
    @ResponseBody
    public void update(@RequestParam("file") MultipartFile file) throws IOException {
        //哪几列需要合并,下标从0开始
        int[] mergeColumnIndex = {0,1,2};
//            需要从第几行开始合并
        int mergeRowIndex = 1;
        InputStream inputStream = file.getInputStream();
        //实例化实现了AnalysisEventListener接口的类
        ExcelListener listener = new ExcelListener();
        //读取信息
        EasyExcel.read(inputStream, CheckTemplate.class, listener).sheet(1).headRowNumber(1).doRead();//从第二行开始读
        List<CheckExport> datas = listener.getDatas();
        String filename="F:\\excel\\2020-2021.xlsx";
        File file1 = new File(filename);
        if(!file1.exists()){
            file1.createNewFile();
        }
        //打印单个sheel页
        EasyExcel.write(filename, CheckExport.class )
                .autoCloseStream(Boolean.TRUE)
                .registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex,mergeColumnIndex))
                .sheet("2020-2021").doWrite(datas);//传入封装好需要打印的数据
    }
<think>嗯,用户想知道怎么用EasyExcel导出Excel合并单元。我之前看过一些资料,记得EasyExcel可以通过注解或者自定义策略合并单元。首先,用户可能需要一个具体的例子,所以应该先提供一个简单的示例步骤。然后,可能还需要说明不同的合并方式,比如基于内容的合并或者自定义规则。 首先,我应该回忆一下EasyExcel的常用方法。比如,使用@ContentLoopMerge注解可以合并相同内容的单元格,但这个是按列合并的。另外,用户可能需要更灵活的控制,比如根据某些条件合并,这时候就需要自定义合并策略了。比如引用中的ServeMergeStrategy,这个可能需要用户自己实现CellWriteHandler接口。 然后,用户可能想知道具体的代码示例。比如如何定义一个实体类,加上注解,然后在导出的时候应用合并策略。还有工具类的准备,比如自定义标签和策略类。需要确保代码正确,比如在写数据的时候要注册自定义合并策略。 还要注意可能的问题,比如合并的列索引是否正确,以及数据需要预先排序。用户可能在数据没有排序的情况下合并出错,这点需要提醒。另外,性能方面,处理大量数据时合并可能会影响速度,这也是需要注意的地方。 最后,生成相关问题的时候,要考虑用户可能的后续疑问,比如性能优化、动态合并规则、处理大数据量等。这些都可以作为相关问题列出,帮助用户进一步了解。</think># EasyExcel合并单元实现方法 使用EasyExcel实现单元格合并主要有两种方式:基于注解的自动合并自定义策略合并。以下是具体实现步骤: ### 一、基础合并方法(基于内容重复) 1. **实体类配置**:使用`@ContentLoopMerge`注解标记需要合并的列 ```java public class DemoData { @ContentLoopMerge(mergeNo = 0) // 合并第一列 private String category; @ContentLoopMerge(mergeNo = 1) // 合并第二列 private String productName; } ``` 2. **导出代码实现** ```java // 导出时自动合并相同内容的单元格 EasyExcel.write("output.xlsx", DemoData.class) .registerWriteHandler(new LoopMergeStrategy()) // 注册合并策略 .sheet("商品数据") .doWrite(dataList); ``` ### 二、高级合并方法(自定义合并规则) 1. **自定义合并策略类**(示例合并连续相同数据) ```java public class CustomMergeStrategy implements CellWriteHandler { // 实现determineMergeRanges方法定义合并规则 @Override public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { // 合并逻辑实现(需判断连续相同值) } } ``` 2. **导出时应用策略** ```java List<MergeColumn> mergeColumns = Arrays.asList( new MergeColumn(0, true), // 第1列需要合并 new MergeColumn(2, false) // 第3列不合并 ); EasyExcel.write("output.xlsx", DemoData.class) .registerWriteHandler(new CustomMergeStrategy(mergeColumns)) .sheet("订单数据") .doWrite(orderList); ``` ### 三、注意事项 1. **数据预处理要求**:需要确保要合并的数据在列表中连续排列[^2] 2. **列索引控制**:合并列索引从0开始计数 3. **性能考量**:处理10万行数据时,合并操作会增加约15%的处理时间
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值