当前位置: 首页 > news >正文

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>() {@Overridepublic void invoke(ExcelData excelData, AnalysisContext analysisContext) {log.info("read data {}", excelData);excelDataList.add(excelData);}@Overridepublic 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<>();@Overridepublic void invoke(ExcelData excelData, AnalysisContext analysisContext) {log.info(" data -> {}", excelData);list.add(excelData);}@Overridepublic void extra(CellExtra extra, AnalysisContext context) {CellExtraTypeEnum type = extra.getType();switch (type) {case MERGE: {if (extra.getRowIndex() >= headRowNum) {cellExtraList.add(extra);}break;}default:{}}}@Overridepublic 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合并单元格数据

普通的excel列表&#xff0c;easyexcel读取是没有什么问题的。但是&#xff0c;如果有合并单元格&#xff0c;那么它读取的时候&#xff0c;能获取数据&#xff0c;但是数据是不完整的。如下所示的单元格数据&#xff1a; 我们通过简单的异步读取&#xff0c;最后查看数据内容&…...

2023哪款蓝牙耳机性价比高?200左右高性价比蓝牙耳机推荐

现如今的蓝牙耳机越来越多&#xff0c;人们在选择时不免纠结&#xff0c;不知道选什么蓝牙耳机比较好&#xff1f;针对这个问题&#xff0c;我来给大家推荐几款性价比高的蓝牙耳机&#xff0c;一起来看看吧。 一、南卡小音舱Lite2蓝牙耳机 参考价&#xff1a;299 蓝牙版本&am…...

Java代码弱点与修复之——Masked Field(掩码字段)

弱点描述 MF: Masked Field (FB.MF_CLASS_MASKS_FIELD) 是 FindBugs 代码分析工具的一个警告信息, 属于中风险的代码弱点。 Masked Field,翻译过来是掩码字段, 字段可以理解为属性, 那么掩码是什么意思呢? 掩码是什么? 掩码是一串二进制代码对目标字段进行位与运算,屏…...

C语言编程入门之刷题篇(C语言130题)(8)

&#xff08;题目标题可以直接跳转此题链接&#xff09; BC72 平均身高 描述 从键盘输入5个人的身高&#xff08;米&#xff09;&#xff0c;求他们的平均身高&#xff08;米&#xff09;。 输入描述&#xff1a; 一行&#xff0c;连续输入5个身高&#xff08;范围0.00~2.00…...

QML动画类型总结

目录 一 常用动画 二 特殊场景动画 一 常用动画 有几种类型的动画&#xff0c;每一种都在特定情况下都有最佳的效果&#xff0c;下面列出了一些常用的动画&#xff1a; 1、PropertyAnimation&#xff08;属性动画&#xff09;- 使用属性值改变播放的动画&#xff1b; 2、Num…...

编译一个魔兽世界开源服务端Windows需要安装什么环境

编译一个魔兽世界开源服务端Windows需要安装什么环境 大家好我是艾西&#xff0c;去年十月份左右wy和bx发布了在停服的公告。当时不少小伙伴都在担心如果停服了怎么办&#xff0c;魔兽这游戏伴随着我们渡过了太多的时光。但已经发生的事情我们只能顺其自然的等待GF的消息就好了…...

HTML5字体集合的实践经验

随着互联网的发展&#xff0c;网站已成为人们获取信息和交流的重要平台。而一个好的网站&#xff0c;不仅需要有美观的界面&#xff0c;还需要有良好的用户体验。其中&#xff0c;字体是影响用户体验的一个重要因素。下面就让我们来看看HTML字体集合的相关内容。 HTML字体集合是…...

Mybatis 框架 ( 一 ) 基本步骤

1.概念 1.1.什么是Mybatis框架 &#xff08;1&#xff09;Mybatis是一个半ORM&#xff08;Object Relation Mapping 对象关系映射&#xff09;框架&#xff0c;它内部封装了JDBC&#xff0c;开发时只需要关注SQL语句本身&#xff0c;不需要花费精力去处理加载驱动、创建连接、…...

【华为OD机试真题】We Are A Team(C++javapython)100%通过率 超详细代码注释 代码优化

We Are A Team 题目描述: 总共有n个人在机房,每个人有一个标号(1<=标号<=n) ,他们分成了多个团队,需要你根据收到的m条消息判定指定的两个人是否在 一个团队中,具体的: 1、消息构成为abc,整数a、b分别代表两个人的标号,整数C代表指令 2、c = = 0 代表a和b在一…...

Oracle_Workflow_Builder工作流工具(一)

简介 目标WORKFLOW是oracle 公司的一个标准产品&#xff0c;它通过图形化的方式来表达业务处理过程。用户使用工作流可以灵活地定义或更改流程的结构。WORKFLOW是建立在数据库基础上的一个应用&#xff0c;它由后台的数据对象和前台的客户端程序组成。本文档主要介绍工作流的基…...

JavaWeb学习--RequestResponse

目录 JavaWeb学习--Request&Response 1&#xff0c;Request和Response的概述 request:获取请求数据 response:设置响应数据 **小结** 2&#xff0c;Request对象 **小结** 2.2 Request获取请求数据 **小结** 2.4 请求参数中文乱码问题 URL编码 2.5 Request请求转…...

Linux cat 命令

cat&#xff08;英文全拼&#xff1a;concatenate&#xff09;命令用于连接文件并打印到标准输出设备上。 使用权限 所有使用者 语法格式 cat [-AbeEnstTuv] [--help] [--version] fileName 参数说明&#xff1a; -n 或 --number&#xff1a;由 1 开始对所有输出的行数编…...

力扣sql中等篇练习(十四)

力扣sql中等篇练习(十四) 1 最后一个能进入电梯的人 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 在表某一个范围内的可以考虑自连接的方式,注意连接的表只需要精准的字段 # 需要排序是因为它需要找到最后一个上车的用户 SELECT q1.person_name…...

什么是Spring FactoryBean?有什么作用?

1、什么是Spring Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架&#xff0c;以 IOC和AOP为内核。含有七大核心模块 2、Spring的七大模块 (1)Spring Core&#xff1a;核心容器提供了Spring的基本功能。核心容器的核心功能是用IOC 容器来管理类的依赖关系&#xff…...

Python List pop()方法

在Python中&#xff0c;列表&#xff08;list&#xff09;是一种有序的可变集合&#xff0c;可以包含任何数据类型的元素。列表对象提供了许多方法来处理列表中的元素&#xff0c;其中之一是pop()方法。 pop()方法用于从列表中移除并返回指定位置的元素。如果不指定位置&#…...

HJ51 输出单向链表中倒数第k个结点

写在前面&#xff1a; 做题环境如下&#xff1a; 题目渠道&#xff1a;牛客网 HJ51 输出单向链表中倒数第k个结点 华为机试题 编程语言&#xff1a;C 一、题目描述 描述 输入一个单向链表&#xff0c;输出该链表中倒数第k个结点&#xff0c;链表的倒数第1个结点为链表的尾指针…...

c#笔记-内置类型

内置类型 内置类型是一些有关键字表示的类型。关键字具有非常高的优先级&#xff0c;可以让你在没有别的配置的情况下&#xff0c; 只要用的是c#就可以使用。这也意味着这些类型是非常重要&#xff0c;或是基本的东西。 整数&#xff1a;byte, sbyte, short, ushort, int, ui…...

功能齐全的 DIY ESP32 智能手表设计之原理图讲解一

相关设计资料下载ESP32 智能手表带心率、指南针设计资料(包含Arduino源码+原理图+Gerber+3D文件).zip 目录 USB部分原理图讲解 供电部分原理图讲解 USB转串口原理图讲解...

8年测试经验分享,15K的测试工程师需要掌握那些知识?

软件测试行业是随着软件产业的发展而兴起的一个重要领域&#xff0c;目前处于快速发展阶段。以下是软件测试行业的现状&#xff1a; 人才需求增长&#xff1a;随着互联网、移动互联网、物联网等新技术的不断发展&#xff0c;软件测试人才需求呈现出快速增长的趋势。越来越多的…...

利用通信基础设施提高电网的稳态稳定性(Matlab代码实现)

目录 1 概述 2 稳态稳定性分析 2.1 系统模型 2.2 稳态稳定性 2.3 问题说明 3 仿真结果 4 Matlab代码 1 概述 随着电力系统的复杂性和规模的增加&#xff0c;电力系统的有效控制变得越来越困难。我们提出了一种自动控制策略&#xff0c;该策略基于通过通信基础设施获得的…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...