使用 easyExcel 合并相同数据的单元格与解析合并单元格里面的数据

实现效果

遇到一个项目,里面要求把一些数据合并,研究了一天整的我头大,现在把这个方法公布出来,我也是抄的别人的实现

先看一下要操作的表格
在这里插入图片描述
这里分为读写两个操作,读是要将合并单元格的数据读出来,写是将相同的数据合并。
来看一下合并之后的样子
在这里插入图片描述
你觉得不好看可以自己调整一下表间距

ok 了家人们,上代码

依赖

        <!-- easy excel-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.4</version>
        </dependency>

        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!-- lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>

        <!-- slf4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.6</version>
        </dependency>


        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.6</version>
        </dependency>

        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.22</version>
        </dependency>

        <!-- gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>

代码实现

package com.example.demo.excel.input;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.metadata.CellExtra;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 导入工具类
 *
 * @param <T>
 */
@Slf4j
public class ImportExcelHelper<T> {
   

    /**
     * 返回解析后的List
     *
     * @return java.util.List<T> 解析后的List
     * @param: fileName 文件名
     * @param: clazz Excel对应属性名
     * @param: sheetNo 要解析的sheet
     * @param: headRowNumber 正文起始行
     */

    public List<T> getList(InputStream file, Class<T> clazz, Integer sheetNo, Integer headRowNumber) {
   
        //开启监听器
        ImportExcelListener<T> listener = new ImportExcelListener<>(headRowNumber);
        //多线程倒计时计数器
        CountDownLatch latch = new CountDownLatch(1);
        new Thread(() -> {
   
            try {
   
                                                        //读取额外的可合并的数据            第 0 个 sheet                 第 1 行开始
                EasyExcel.read(file, clazz, listener).extraRead(CellExtraTypeEnum.MERGE).sheet(sheetNo).headRowNumber(headRowNumber).doRead();
            } catch (Exception e) {
   
                log.error(e.getMessage());
            }
            //开始倒计时减1
            latch.countDown();
        }).start();
        try {
   
            //阻塞程序等待完成
            latch.await();
        } catch (InterruptedException ignored) {
   
        }
        List<CellExtra> extraMergeInfoList = listener.getExtraMergeInfoList();
        //没有合并单元格情况,直接返回即可
        if (isEmpty(extraMergeInfoList)) {
   
            return listener.getData();
        }
        CountDownLatch computerLatch = new CountDownLatch(1);
        AtomicReference<List<T>> data = new AtomicReference<>();
        new Thread(() -> {
   
            //存在有合并单元格时,自动获取值,并校对
            data.set(explainMergeData(listener.getData(), extraMergeInfoList, headRowNumber));
            computerLatch.countDown();
        }).start();
        try {
   
            computerLatch.await();
        } catch (InterruptedException ignored) {
   
        }
        return data.get();
    }


    /**
     * 处理合并单元格
     *
     * @param data               解析数据
     * @param extraMergeInfoList 合并单元格信息
     * @param headRowNumber      起始行
     * @return 填充好的解析数据
     */

    private List<T> explainMergeData(List<T> data, List<CellExtra> extraMergeInfoList, Integer headRowNumber) {
   
        //循环所有合并单元格信息
        extraMergeInfoList.forEach(cellExtra -> {
   
            //获取第一行
            int firstRowIndex = cellExtra.getFirstRowIndex() - headRowNumber;
            //获取最后一行
            int lastRowIndex = cellExtra.getLastRowIndex() - headRowNumber;
            //获取第一列
            int firstColumnIndex = cellExtra.getFirstColumnIndex();
            //获取最后一列
            int lastColumnIndex = cellExtra.getLastColumnIndex();
            //获取初始值
            Object initValue = getInitValueFromList(firstRowIndex, firstColumnIndex, data);
            //设置值
            for (int i = firstRowIndex; i <= lastRowIndex; i++
### EasyExcel 解析合并单元数据方法 当处理带有合并单元Excel 文件时,EasyExcel 提供了强大的功能来解析这些复杂结构的数据。为了确保能够正确读取合并单元中的数据,可以采用以下策略。 #### 配置监听器类 创建自定义监听器继承 `AnalysisEventListener` 接口,并重写相应的方法以实现对每一行记录的操作逻辑。在此过程中需要注意的是,在遇到跨越多行或多列的情况时要特别小心处理[^1]。 ```java public class MergeCellListener extends AnalysisEventListener<DemoData> { @Override public void invoke(DemoData data, AnalysisContext context) { System.out.println(data); } @Override public void doAfterAllAnalysed(AnalysisContext context) { // 所有数据解析完成后的操作 } } ``` #### 设置表头转换规则 通过配置 `HeadRowNumber` 参数指定跳过的头部行数以及设置字段映射关系,从而让框架自动识别并适配不同类型的单元格内容。对于存在空白项的位置,则会依据上下文环境合理推测其实际值[^2]。 ```java // 创建解析参数对象 ReadSheet readSheet = EasyExcel.read(fileName).sheet().headRowNumber(0).build(); readSheet.setHeadConverter(new DefaultConverter()); ``` #### 处理缺失值填补 针对某些情况下可能出现的部分区域为空白的情形,默认机制将会尝试利用相邻的有效数值来进行补充替换;当然也可以根据具体业务需求自行定制化此部分行为模式。 ```java @Override protected Map<Integer, String> convertOneRow(List<CellData> cellDataList, Integer relativeRowIndex, Boolean isHead) { Map<Integer, String> result = new HashMap<>(); for (int i = 0; i < cellDataList.size(); i++) { CellData cellData = cellDataList.get(i); if (cellData.getType() == CellDataTypeEnum.STRING && StringUtils.isEmpty(cellData.getStringValue())) { // 自定义填充逻辑... } else { result.put(i, cellData.getStringValue()); } } return result; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值