easyexcel读取excel合并单元格数据的操作代码

 更新时间:2023年05月04日 10:05:56   作者:luffy5459  
这篇文章主要介绍了easyexcel读取excel合并单元格数据的操作代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

    普通的excel列表,easyexcel读取是没有什么问题的。但是,如果有合并单元格,那么它读取的时候,能获取数据,但是数据是不完整的。如下所示的单元格数据:

    我们通过简单的异步读取,最后查看数据内容:

  ExcelData.java

package com.example.model;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExcelData {
    @ExcelProperty("学生姓名")
    private String name;
    @ExcelProperty("年龄")
    private int age;
    @ExcelProperty("性别")
    private String gender;
    @ExcelProperty({"课程", "课程名称"})
    private String courseName;
    @ExcelProperty({"课程", "分数"})
    private double score;
}

    ExcelRead.java

package com.example.service;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.model.ExcelData;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class ExcelRead {
    private static final String FILEPATH = "e:\\test\\student.xlsx";
    public List<ExcelData> list() {
        List<ExcelData> excelDataList = new ArrayList<>();
        EasyExcel.read(FILEPATH, ExcelData.class, new AnalysisEventListener<ExcelData>() {
            @Override
            public void invoke(ExcelData excelData, AnalysisContext analysisContext) {
                log.info("read data {}", excelData);
                excelDataList.add(excelData);
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            }
        }).sheet().doRead();
        return excelDataList;
    }
}

   ExcelTest.java

package com.example.service;
import com.example.model.ExcelData;
import java.util.List;
public class ExcelTest {
    public static void main(String[] args) {
        ExcelRead excelRead = new ExcelRead();
        List<ExcelData> list = excelRead.list();
        System.out.println(list.size());
    }
}

    运行程序,打印日志信息如下:

   获取了6个数据没错,但是每一个合并单元格记录里面都有一个数据获取是空的。

    解决办法就是需要在异步读取数据监听器里面读取合并单元格的额外数据,并把这部分数据给补充上。

    需要修改的地方:

    1、实体需要增加注解索引值:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExcelData {
    @ExcelProperty(value = "学生姓名", index = 0)
    private String name;
    @ExcelProperty(value = "年龄", index = 1)
    private int age;
    @ExcelProperty(value = "性别", index = 2)
    private String gender;
    @ExcelProperty(value = {"课程", "课程名称"}, index = 3)
    private String courseName;
    @ExcelProperty(value = {"课程", "分数"}, index = 4)
    private double score;
}

   2、自定义监听器,读取合并单元格数据:

package com.example.service;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.CellExtra;
import com.example.model.ExcelData;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class CustomAnalysisEventListener extends AnalysisEventListener<ExcelData> {
    private int headRowNum;
    public CustomAnalysisEventListener(int headRowNum) {
        this.headRowNum = headRowNum;
    }
    private List<ExcelData> list = new ArrayList<>();
    private List<CellExtra> cellExtraList = new ArrayList<>();
    @Override
    public void invoke(ExcelData excelData, AnalysisContext analysisContext) {
        log.info(" data -> {}", excelData);
        list.add(excelData);
    }
    @Override
    public void extra(CellExtra extra, AnalysisContext context) {
        CellExtraTypeEnum type = extra.getType();
        switch (type) {
            case MERGE: {
                if (extra.getRowIndex() >= headRowNum) {
                    cellExtraList.add(extra);
                }
                break;
            }
            default:{
            }
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    }
    public List<ExcelData> getList() {
        return list;
    }
    public List<CellExtra> getCellExtraList() {
        return cellExtraList;
    }
}

    3、通过监听器读取数据,通过监听器获取数据和合并单元格数据,然后设置单元格数据。

 
package com.example.service;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.metadata.CellExtra;
import com.example.model.ExcelData;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.List;
@Slf4j
public class ExcelRead {
    private static final int HEAD_ROW_NUM = 2;
    private static final String FILEPATH = "e:\\test\\student.xlsx";
    public List<ExcelData> list() {
        List<ExcelData> excelDataList;
        CustomAnalysisEventListener listener = new CustomAnalysisEventListener(HEAD_ROW_NUM);
        EasyExcel.read(FILEPATH, ExcelData.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();
        excelDataList = listener.getList();
        List<CellExtra> cellExtraList = listener.getCellExtraList();
        if (cellExtraList != null && cellExtraList.size() > 0) {
            mergeExcelData(excelDataList, cellExtraList, HEAD_ROW_NUM);
        }
        return excelDataList;
    }
    private void mergeExcelData(List<ExcelData> excelDataList, List<CellExtra> cellExtraList, int headRowNum) {
        cellExtraList.forEach(cellExtra -> {
            int firstRowIndex = cellExtra.getFirstRowIndex() - headRowNum;
            int lastRowIndex = cellExtra.getLastRowIndex() - headRowNum;
            int firstColumnIndex = cellExtra.getFirstColumnIndex();
            int lastColumnIndex = cellExtra.getLastColumnIndex();
            //获取初始值
            Object initValue = getInitValueFromList(firstRowIndex, firstColumnIndex, excelDataList);
            //设置值
            for (int i = firstRowIndex; i <= lastRowIndex; i++) {
                for (int j = firstColumnIndex; j <= lastColumnIndex; j++) {
                    setInitValueToList(initValue, i, j, excelDataList);
                }
            }
        });
    }
    private void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<ExcelData> data) {
        ExcelData object = data.get(rowIndex);
        for (Field field : object.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation != null) {
                if (annotation.index() == columnIndex) {
                    try {
                        field.set(object, filedValue);
                        break;
                    } catch (IllegalAccessException e) {
                        log.error("设置合并单元格的值异常:{}", e.getMessage());
                    }
                }
            }
        }
    }
    private Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<ExcelData> data) {
        Object filedValue = null;
        ExcelData object = data.get(firstRowIndex);
        for (Field field : object.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation != null) {
                if (annotation.index() == firstColumnIndex) {
                    try {
                        filedValue = field.get(object);
                        break;
                    } catch (IllegalAccessException e) {
                        log.error("设置合并单元格的初始值异常:{}", e.getMessage());
                    }
                }
            }
        }
        return filedValue;
    }
}

    有个小细节需要注意,我们在通过监听器读取的时候,还需要额外读取合并单元格部分。

EasyExcel.read(FILEPATH, ExcelData.class, listener).extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();   

    还有个小细节,就是我们的表格一般都是有头的,头的内容可能是2行,可能是1行,在进行合并单元格处理的时候,需要考虑这个行数。我们定义了一个常量HEAD_ROW_NUM来记录这个行数,最后进行单元格值计算的时候传入。 

    我在处理excel数据中发现,如果这个单元格合并,是由我们的程序自己做的,那么它读取的时候,是没有问题的。在上面为null的地方,它其实都有值:

    但是在实际中,我们的excel不能保证不被人为编辑,那么就很有可能,我们在进行合并单元格的时候,把有值和无值合并到一起,最后就出现前面提到的读取合并单元格出现数据缺失的问题。 而我们期望,合并单元格部分他们的数据应该是一样的。所以今天的解决方案是一种保险的做法,不管你的表格是否有合并单元格,是否人为修改,最终都能把合并单元格缺失的数据进行恢复。

到此这篇关于easyexcel读取excel合并单元格数据的操作代码的文章就介绍到这了,更多相关easyexcel合并单元格数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用java模拟简单的tomcat的方法详解

    使用java模拟简单的tomcat的方法详解

    这篇文章主要为大家详细介绍了java模拟简单的tomcat的方法,使用数据库,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • IDEA编译乱码Build Output提示信息乱码

    IDEA编译乱码Build Output提示信息乱码

    IDEA编译的时候乱码,Build Output提示信息乱码,本文就详细的介绍一下解决方法,有需要的同学可以了解一下
    2021-06-06
  • 详解Java线性结构中的链表

    详解Java线性结构中的链表

    除了一些算法之外,我们还有掌握一些常见的数据结构,比如数组、链表、栈、队列、树等结构,所以接下来就给大家详细讲解一下线性结构中的链表,需要的朋友可以参考下
    2023-07-07
  • SpringBoot配置数据库密码加密的方法

    SpringBoot配置数据库密码加密的方法

    由于系统安全的考虑,配置文件中不能出现明文密码的问题,本文就给大家详细介绍下springboot配置数据库密码加密的方法,下面话不多说了,来一起看看详细的介绍吧,需要的朋友可以参考下
    2023-08-08
  • Centos中yum方式安装java的实现示例

    Centos中yum方式安装java的实现示例

    这篇文章主要介绍了Centos中yum方式安装java的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • IDEA 插件 mapper和xml互相跳转操作

    IDEA 插件 mapper和xml互相跳转操作

    这篇文章主要介绍了IDEA 插件 mapper和xml互相跳转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • SpringBoot 多线程事务回滚的实现

    SpringBoot 多线程事务回滚的实现

    本文是基于springboot的@Async注解开启多线程,并通过自定义注解和AOP实现的多线程事务,避免繁琐的手动提交/回滚事务,感兴趣的可以了解一下
    2024-02-02
  • java jdk动态代理详解

    java jdk动态代理详解

    动态代理类的Class实例是怎么生成的呢,是通过ProxyGenerator类来生成动态代理类的class字节流,把它载入方法区
    2013-09-09
  • Java垃圾回收之分代收集算法详解

    Java垃圾回收之分代收集算法详解

    今天小编就为大家分享一篇关于Java垃圾回收之分代收集算法详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • Spring的BeanFactoryPostProcessor接口示例代码详解

    Spring的BeanFactoryPostProcessor接口示例代码详解

    这篇文章主要介绍了Spring的BeanFactoryPostProcessor接口,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02

最新评论