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合并单元格数据内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 阿里的Easyexcel读取Excel文件的方法(最新版本)

    目录 优化 简单使用读取Excel,返回List集合 完整的Excel简单读取类和测试   本篇文章主要介绍一下使用阿里开源的Easyexcel工具处理读取excel文件,因为之前自己想在网上找一下这个简单的立即上手的博客,发现很多文章的教程都针对比较旧的版本的Easyexcel,没有使用新版本的方法,导致很多方法都标志过期了或者运行时报错,所以本篇博客主要是使用最新版的Easyexcel去读取excel文件,顺便说一下目前新版本的特性. 优化 目前读取excel文件不再需要指定ExcelTyp

  • 关于easyExcel中读取Excel表头的实例说明

    目录 前言 1 环境准备 1 添加pom 2 添加dto对象 3 准备一个控制器 4 准备一个监听类 2 单表头Excel 3 多表头Excel 4 总结 前言 在使用easyExcel读取文件时,对于Excel的表头,在解析读取时分成不同的状态,需要加以区分. 1 环境准备 准备一个可以正常访问的SpringBoot项目. 1 添加pom <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --> <depende

  • Java利用EasyExcel读取写入Excel详情

    目录 EasyExcel介绍 为什么使用EasyExcel? 封装使用 例子 EasyExcel介绍 EasyExcel是一个基于Java的.快速.简洁.解决大文件内存溢出的Excel处理工具.他能让你在不用考虑性能.内存的等因素的情况下,快速完成Excel的读.写等功能. 为什么使用EasyExcel? Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但PO

  • EasyExcel工具读取Excel空数据行问题的解决办法

    EasyExcel是Alibaba开源的一个Java处理Excel的工具. 官网解读:快速.简洁.解决大文件内存溢出的java处理Excel工具 快速 快速的读取excel中的数据. 简洁 映射excel和实体类,让代码变的更加简洁. 大文件 在读写大文件的时候使用磁盘做缓存,更加的节约内存. 官网地址:https://easyexcel.opensource.alibaba.com/ 感兴趣可自己琢磨,该工具简单易上手,且性能相对比较高. 本文主要处理的问题是该工具读取Excel空数据行的问题

  • python之DataFrame实现excel合并单元格

    在工作中经常遇到需要将数据输出到excel,且需要对其中一些单元格进行合并,比如如下表表格,需要根据A列的值,合并B.C列的对应单元格 pandas中的to_excel方法只能对索引进行合并,而xlsxwriter中,虽然提供有merge_range方法,但是这只是一个和基础的方法,每次都需要编写繁琐的测试才能最终调好,而且不能很好的重用.所以想自己写一个方法,结合dataframe和merge_range.大概思路是: 1.定义一个MY_DataFrame类,继承DataFrame类,这样能很

  • java实现对excel文件的处理合并单元格的操作

    一.依赖引入 <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifactId>jxl</artifactId> <version>2.6.12</version> </dependency> 二.表格操作 1.读取xls文件 测试文件为: 代码: public void test() throws IOException, BiffEx

  • Python批量合并有合并单元格的Excel文件详解

    合并单元格 合并单元格相信大家都会,比如下面这段简单的代码就可以实现: app='Word' word=win32.gencache.EnsureDispatch('%s.Application' % app) doc=word.Documents.Add() word.Visible=False #Title begin sel =word.Selection sel.Font.Name = u"微软雅黑" sel.Font.Size = 8 sel.Font.Bold = Fals

  • Python实现Excel自动分组合并单元格

    大家好,我们经常会有这样的需求.比如下图 我们需要把同一个省份的合并起来,如下图的效果 如何实现呢,这是原有的df 直观的操作是这样的: df.to_excel('test.xlsx',index=False) from openpyxl import load_workbook wb=load_workbook('test.xlsx') ws=wb.active() ws.merge_cells(start_row=2,end_row=8,start_column=1,end_column=1

  • Java导出Excel统计报表合并单元格的方法详解

    目录 前言 示例 注意事项 总结 前言 Apache POI是一种流行的API,允许程序员使用Java程序创建,修改和显示MS Office文件. 它是由Apache Software Foundation开发和分发的开源库,用于使用Java程序设计或修改Microsoft Office文件. 它包含将用户输入数据或文件解码为MS Office文档的类和方法. HSSF - 用于读取和写入MS-Excel文件的xls格式 示例 类似上面的需要合并表头的报表在日常的开发中也是经常遇到,这里总结下关

  • Java利用EasyExcel实现合并单元格

    目录 pom版本 1.自定义合并单元格 1.1 不合并单元格 1.2 合并单元格 1.3 写多个sheet 1.4 WriteTable pom版本 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.7</version> </dependency> 1.自定义合并单元格 在某些

  • java实现合并单元格的同时并导出excel示例

    介绍 POI提供API给Java程序对Microsoft Office格式档案读和写的功能.POI可以操作的文档格式有excel,word,powerpoint等,POI进行跨行需要用到对象HSSFSheet对象,现在就当我们程序已经定义了一个HSSFSheet对象sheet. 跨第1行第1个到第2个单元格的操作为 sheet.addMergedRegion(new Region(0,(short)0,0,(short)1)); 跨第1行第1个到第2行第1个单元格的操作为 sheet.addMe

  • 用NPOI创建Excel、合并单元格、设置单元格样式、边框的方法

    今天在做项目中,遇到使用代码生成具有一定样式的Excel,找了很多资料,最后终于解决了,Excel中格式的设置,以及单元格的合并等等.下面就介绍下,使用NPOI类库操作Excel的方法. 1.首先我们先在内存中生成一个Excel文件,代码如下:   HSSFWorkbook book = new HSSFWorkbook();        ISheet sheet = book.CreateSheet("Sheet1"); 2.然后在新创建的sheet里面,创建我们的行和列,代码如下

  • Python使用xlrd实现读取合并单元格

    合并单元格 操作方法: 1.使用xlrd自带属性:merged_cells # 获取表格中所有合并单元格位置,以列表形式返回 (起始行,结束行,起始列,结束列) merged = sheet.merged_cells #结果:[(1,5,0,1),(5,9,0,1)] 2.使用循环判断是合并单元格还是普通单元格,并将合并单元格中的首行值赋值给合并单元格 def get_cell_type(row_index, col_index): """既能得到合并单元格也能得到普通单元格

  • Java用POI解析excel并获取所有单元格数据的实例

    1.导入POI相关jar包 org.apache.poi jar 2.代码示例 public List getAllExcel(File file, String tableName, String fname, String enterpriseId, String reportId, String projectId) throws FileNotFoundException, IOException, ClassNotFoundException, InstantiationExcepti

随机推荐