easyexcel读取excel合并单元格数据的操作代码
作者:luffy5459 发布时间:2022-08-26 16:26:21
普通的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不能保证不被人为编辑,那么就很有可能,我们在进行合并单元格的时候,把有值和无值合并到一起,最后就出现前面提到的读取合并单元格出现数据缺失的问题。 而我们期望,合并单元格部分他们的数据应该是一样的。所以今天的解决方案是一种保险的做法,不管你的表格是否有合并单元格,是否人为修改,最终都能把合并单元格缺失的数据进行恢复。
来源:https://blog.csdn.net/feinifi/article/details/130437926


猜你喜欢
- 本文实例为大家分享了java实现文件归档和还原的具体代码,供大家参考,具体内容如下基本思路: 文件归档,换句话就是把多个文件的字节
- 众所周知,PDF文档除了具有较强稳定性和兼容性外, 还具有较强的安全性,在工作中可以有效避免别人无意中对文档内容进行修改。但与此同
- GitHub 地址:quickjs-android-wrapper特性支持 Java 和 JavaScript 类型互转支持 Promise
- 前言总结java常见的锁区分各个锁机制以及如何使用使用方法锁名考察线程是否要锁住同步资源乐观锁和悲观锁锁住同步资源后,要不要阻塞不阻塞可以使
- 1.ReadWriteLock介绍为什么我们有了Lock,还要用ReadWriteLock呢。我们对共享资源加锁之后,所有的线程都将会等待。
- xamarin 可以很方便的编写一个电话拨号程序,下面的代码是调用android系统的拨号功能,拨号前会给出一个提示信息。callButto
- 定义:简单绑定是将一个用户界面元素(控件)的属性绑定到一个类型(对象)实例上的某个属性的方法。基本类型、包装类型、数组(以参数a
- Java代码 InputMethodManager imm = (InputMethodManager)getSystemService(S
- 一、Spring Boot 、 Spring MVC 、Spring对比首先你需要明白一件事情:Spring Boot项目目的并不是替换Sp
- Room在SQLite基础上做了ORM封装,使用起来类似JPA,不需要写太多的sql。导入依赖//roomdef room_version=
- 1.用法\t 表示制表符,相当于制表符前面的输出内容位数为8的倍数,\t将输出8个空格前面的输出内容位数不是8的倍数,\t将补足8位2.测试
- 本文为大家分享了Android使用线程获取网络图片的具体代码,供大家参考,具体内容如下AndroidManifest.xml &n
- 前言相信很多人对枚举并不陌生,枚举可以很方便和直观的管理一组特定值。如果我们在页面上直接输出我们希望匹配的汉语意思或则其他满足我们需求的语句
- 主从表关联查询,返回对象带有集合属性昨天有同事让我帮着看一个问题,mybatis主从表联合查询,返回的对象封装集合属性。我先将出现的问题记录
- 本文实例讲述了C#自定义缓存封装类。分享给大家供大家参考。具体如下:这个自定义的C#类封装了部分常用的缓存操作,包括写入缓存,读取缓存,设置
- Java 8 , Lambda + foreach 语法糖, 写起来非常的 cleanpublic static void main(Str
- 本文实例讲述了C#使用listView增删操作的方法。分享给大家供大家参考。具体分析如下:应用场景: C#中使用listView控件,实现动
- 概述 Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBr
- 前言 红包文化源远流长。从古时的红色纸包,到手
- 本文实例为大家分享了Android Glide图片加载的具体代码,供大家参考,具体内容如下1.普通用法Glide.with(context)