EasyExcel是Alibaba开源的一个Java处理Excel的工具。

官网解读:快速、简洁、解决大文件内存溢出的java处理Excel工具

快速

快速的读取excel中的数据。

简洁

映射excel和实体类,让代码变的更加简洁。

大文件

在读写大文件的时候使用磁盘做缓存,更加的节约内存。

官网地址:https://easyexcel.opensource.alibaba.com/

感兴趣可自己琢磨,该工具简单易上手,且性能相对比较高。

本文主要处理的问题是该工具读取Excel空数据行的问题。

首先解释为什么会产生空数据行:简单解释就是你在Excel中设置了单元的样式,却没有给单元格设值。因此,该工具在读取数据时便没有判断这一步,直接读取到整行数据均为null。

理解了核心问题后,要解决这个问题,实现思路也不难。

莫非就是把这种空数据行过滤即可。

本文是基于批处理监听器实现数据读取的,自定义集成该监听器(com.alibaba.excel.read.listener.PageReadListener),实现自己的逻辑即可解决问题。

下面是自定义监听器

package xin.cosmos.basic.easyexcel.framework;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.util.ListUtils;
import lombok.extern.slf4j.Slf4j;
import xin.cosmos.basic.util.ObjectsUtil;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;/*** 自定义分批Excel数据读取监听器,解决官方无法移除空的Excel行问题** @param <T>* @author geng*/
@Slf4j
public class BatchPageReadListener<T> extends PageReadListener<T> {/*** Temporary storage of data*/private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** consumer*/private final Consumer<List<T>> consumer;public BatchPageReadListener(Consumer<List<T>> consumer) {super(consumer);this.consumer = consumer;}@Overridepublic void invoke(T data, AnalysisContext context) {// 如果一行Excel数据均为空值,则不装载该行数据if (isLineNullValue(data)) {return;}cachedDataList.add(data);if (cachedDataList.size() >= BATCH_COUNT) {consumer.accept(cachedDataList);cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {if (ObjectsUtil.isNull(cachedDataList)) {return;}consumer.accept(cachedDataList);}/*** 判断整行单元格数据是否均为空*/private boolean isLineNullValue(T data) {if (data instanceof String) {return ObjectsUtil.isNull(data);}try {List<Field> fields = Arrays.stream(data.getClass().getDeclaredFields()).filter(f -> f.isAnnotationPresent(ExcelProperty.class)).collect(Collectors.toList());List<Boolean> lineNullList = new ArrayList<>(fields.size());for (Field field : fields) {field.setAccessible(true);Object value = field.get(data);if (ObjectsUtil.isNull(value)) {lineNullList.add(Boolean.TRUE);} else {lineNullList.add(Boolean.FALSE);}}return lineNullList.stream().allMatch(Boolean.TRUE::equals);} catch (Exception e) {log.error("读取数据行[{}]解析失败: {}", data, e.getMessage());}return true;}}

下面是我对EasyExcel封装的工具

package xin.cosmos.basic.easyexcel.helper;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import xin.cosmos.basic.define.ResultVO;
import xin.cosmos.basic.easyexcel.framework.BatchPageReadListener;
import xin.cosmos.basic.easyexcel.template.HeadVO;
import xin.cosmos.basic.exception.PlatformException;
import xin.cosmos.basic.util.BeanMapUtil;
import xin.cosmos.basic.util.ObjectsUtil;import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;/*** EasyExcel 帮助类*/
@Slf4j
public class EasyExcelHelper {/*** 读取Excel文件** @param stream      文件流* @param entityClass 读取转换的Java对象类型* @param <T>* @return*/public static <T> List<T> doReadExcelData(InputStream stream, Class<T> entityClass) {List<T> data = new LinkedList<>();EasyExcelFactory.read(stream, entityClass, new PageReadListener<T>(data::addAll)).sheet().doRead();return data;}/*** 读取Excel文件** @param stream      文件流* @param entityClass 读取转换的Java对象类型* @param comparator  排序比较器* @param <T>* @return*/public static <T> List<T> doReadExcelData(InputStream stream, Class<T> entityClass, Comparator<T> comparator) {List<T> data = new LinkedList<>();EasyExcelFactory.read(stream, entityClass, new BatchPageReadListener<T>(list -> {if (comparator != null) {list.sort(comparator);}data.addAll(list);})).sheet().doRead();return data;}/*** 读取Excel文件** @param file        MultipartFile文件* @param entityClass 读取转换的Java对象类型*/@SneakyThrowspublic static <T> List<T> doReadExcelData(MultipartFile file, Class<T> entityClass) {return doReadExcelData(file.getInputStream(), entityClass);}/*** 读取Excel文件** @param file        File文件* @param entityClass 读取转换的Java对象类型*/@SneakyThrowspublic static <T> List<T> doReadExcelData(File file, Class<T> entityClass) {List<T> data = new LinkedList<>();EasyExcelFactory.read(file, entityClass, new BatchPageReadListener<T>(data::addAll)).sheet().doRead();return data;}/*** Excel数据浏览器下载** @param pathName    下载文件的完整路径名称* @param data        需下载数据* @param entityClazz 下载数据类型模板*/@SneakyThrowspublic static <T> void downloadExcel(String pathName, List<T> data, Class<T> entityClazz) {try {// 构建Excel表头及数据体ExcelWriterSheetBuilder builder = EasyExcel.write(pathName).autoCloseStream(true).sheet("sheet1");doWriteWithDynamicColumns(builder, entityClazz, data);} catch (Exception e) {log.error("写文件错误:{}", e.getMessage());throw new PlatformException("Excel下载数据错误");}}/*** Excel数据浏览器下载* <p>* 前端下载js代码示例:* <pre>* function downloadFile(bytes, fileName) {*    const blob = new Blob([bytes], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});*    if (window.navigator.msSaveOrOpenBlob) { // 兼容IE10*          navigator.msSaveBlob(blob, fileName)*    } else {*         const url = window.URL.createObjectURL(blob);*         const a = document.createElement('a');*         a.href = url;*         a.download = fileName;*         a.click();*         window.URL.revokeObjectURL(url);*    }* }* </pre>** @param excelFileName 下载文件名称* @param response      响应容器* @param data          需下载数据* @param entityClazz   下载数据Bean实体类型,苏醒必须使用注解<code>@ExcelProperty</code>中value指定写出列的表头吗,名称*/public static <T> void downloadExcelToResponse(HttpServletResponse response, String excelFileName, List<T> data, Class<T> entityClazz) {if (ObjectsUtil.isNull(data)) {log.error("写文件错误:{}", "暂无可下载的数据");writeErrMsg(response, "暂无可下载的数据");return;}try {// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postmanresponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");if (excelFileName.endsWith(".xlsx") || excelFileName.endsWith(".xls") ||excelFileName.endsWith(".XLSX") || excelFileName.endsWith(".XLS")) {excelFileName = excelFileName.substring(0, excelFileName.lastIndexOf("."));}// 这里URLEncoder.encode可以防止中文乱码 当然和easy excel没有关系String urlFileName = URLEncoder.encode(excelFileName, "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + urlFileName + ".xlsx");response.setHeader("excel-file-name", urlFileName + ".xlsx");// 构建Excel表头及数据体ExcelWriterSheetBuilder builder = EasyExcel.write(response.getOutputStream()).excelType(ExcelTypeEnum.XLSX).autoCloseStream(true).sheet("sheet1");doWriteWithDynamicColumns(builder, entityClazz, data);} catch (Exception e) {log.error("写文件错误:{}", e.getMessage());writeErrMsg(response, e.getMessage());}}/*** EasyExcel支持动态列写数据** @param builder     指定输出方式和样式* @param entityClazz 实体的Class对象* @param data        Excel行数据*/public static <T> void doWriteWithDynamicColumns(ExcelWriterSheetBuilder builder, Class<T> entityClazz, List<T> data) {List<HeadVO> customizeHeads = new ArrayList<>();Field[] fieldArray = entityClazz.getDeclaredFields();// 获取类的注解for (Field field : fieldArray) {// 忽略导出属性if (field.isAnnotationPresent(ExcelIgnore.class)) {continue;}if (field.isAnnotationPresent(ExcelProperty.class)) {ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);List<String> head = Arrays.asList(excelProperty.value());int index = excelProperty.index();int order = excelProperty.order();HeadVO headVO = HeadVO.builder().headTitle(head).index(index).order(order).field(field.getName()).build();customizeHeads.add(headVO);}}// 表头排序Collections.sort(customizeHeads);// 处理表头List<List<String>> heads = new ArrayList<>();List<String> fields = new ArrayList<>();for (int i = 0; i <= customizeHeads.size() - 1; i++) {heads.add(customizeHeads.get(i).getHeadTitle());fields.add(customizeHeads.get(i).getField());}// 处理数据List<List<Object>> objs = new ArrayList<>();List<Map<String, ?>> maps = BeanMapUtil.beansToMaps(data);maps.forEach(map -> {List<Object> obj = new ArrayList<>();for (String field : fields) {obj.add(map.get(field));}objs.add(obj);});builder.head(heads).doWrite(objs);}@SneakyThrowsprivate static void writeErrMsg(HttpServletResponse response, String errMsg) {// 重置responseresponse.reset();response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().println(JSON.toJSONString(ResultVO.failed(errMsg)));}
}
package xin.cosmos.basic.easyexcel.template;import lombok.Builder;
import lombok.Data;import java.util.List;/*** EasyExcel 表头信息VO类*/
@Builder
@Data
public class HeadVO implements Comparable<HeadVO> {/*** Excel表头名称*/private List<String> headTitle;/*** Excel表头名称映射的Java对象属性名称*/private String field;/*** 主排序*/private int index;/*** 次排序*/private int order;/*** 升序排序* @param o* @return*/@Overridepublic int compareTo(HeadVO o) {if (this.index == o.getIndex()) {return this.order - o.getOrder();}return this.index - o.getIndex();}
}

最后是一个基于Spring cglib的Map<==>Java Bean之间的转换工具

package xin.cosmos.basic.util;import org.springframework.cglib.beans.BeanMap;
import xin.cosmos.basic.exception.PlatformException;import java.util.*;/*** bean和map互转 工具类* <p>* 使用到spring的cglib*/
public class BeanMapUtil {/*** 将Bean转为Map** @param bean* @param <T>* @return*/public static <T> Map<String, ?> beanToMap(T bean) {BeanMap beanMap = BeanMap.create(bean);Map<String, Object> map = new HashMap<>();beanMap.forEach((key, value) -> map.put(String.valueOf(key), value));return map;}/*** 将Map转为Bean** @param map* @param beanClazz* @param <T>* @return*/public static <T> T mapToBean(Map<String, ?> map, Class<T> beanClazz) {T bean;try {bean = beanClazz.newInstance();} catch (InstantiationException | IllegalAccessException e) {e.printStackTrace();throw new PlatformException("Map集合转换到Bean失败");}BeanMap beanMap = BeanMap.create(bean);beanMap.putAll(map);return bean;}/*** 将一组Beans转为List** @param dataList* @param <T>* @return*/public static <T> List<Map<String, ?>> beansToMaps(List<T> dataList) {List<Map<String, ?>> list = new ArrayList<>();if (ObjectsUtil.isNull(dataList)) {return Collections.emptyList();}Map<String, ?> map;T bean;for (T t : dataList) {bean = t;map = beanToMap(bean);list.add(map);}return list;}/*** 将一组Map转为一组Beans** @param dataMaps* @param beanClazz* @param <T>* @return*/public static <T> List<T> mapsToBeans(List<Map<String, ?>> dataMaps, Class<T> beanClazz) {List<T> list = new ArrayList<>();if (ObjectsUtil.isNull(dataMaps)) {return Collections.emptyList();}Map<String, ?> map;for (Map<String, ?> dataMap : dataMaps) {map = dataMap;T bean = mapToBean(map, beanClazz);list.add(bean);}return list;}
}

解决EasyExcel工具读取Excel空数据行的问题相关推荐

  1. linux qt写入excel文件内容,Qt 读取Excel表格数据 生成Excel表格并写入数据

    Qt 读取Excel表格数据 生成Excel表格并写入数据 Qt 读取Excel表格数据 生成Excel表格并写入数据 修改.pro文件,增加 axcontainer QT += axcontaine ...

  2. python读取excel表格数据

    python操作excel主要用到xlrd和xlwt两个库,xlrd读取表格数据,支持xlsx和xls格式的excel表格:xlwt写入excel表格数据 一.python读取excel表格数据 1. ...

  3. Qt之如何读取Excel表格数据

    Qt之如何读取Excel表格数据 概述: 代码示例: .pro: 需要包含的头文件: readExcelData.h: readExcelData.cpp: over: 概述: 大家好我是背锅侠&qu ...

  4. matlab读取excel表作图,读取Excel表格数据进行绘图-如何将excel表格中大量数据导入matlab中并作图...

    matlab 读取excel时间数据并绘图 没看懂你的格式是什么意思, 不过我一般读取excel都用xlsread函数,你也可以试一试 [a,b,c]=xlsresd('data.xls');%r如果 ...

  5. VC6.0读取Excel文件数据

    VC6.0读取Excel文件数据 文件存储在Excel文件中,因此第一步是能够在程序中方便地读取表格数据,这里用的是VC6.0 MFC.文章内容仅供参考,程序不完整. 完整的VC6.0相关程序,需要的 ...

  6. excel导入matlab NaN,Matlab GUI 读取excel文件数据时,出现NaN的问题

    Matlab GUI 读取excel文件数据时,经常会用到如下一段代码,本人有两处不甚明白,请前辈解惑. 源代码 [num,text,raw]=xlsread('123.xls'); for i=1: ...

  7. 关于easyExcel中读取Excel表头的说明

    关于easyExcel中读取Excel表头的说明 1 环境准备 2 单表头Excel 3 多表头Excel 4 总结 在使用easyExcel读取文件时,对于Excel的表头,在解析读取时分成不同的状 ...

  8. python怎么从excel获取数据_python如何读取excel表数据

    python读取excel表数据的方法:首先安装Excel读取数据的库xlrd:然后获取Excel文件的位置并且读取进来:接着读取指定的行和列的内容,并将内容存储在列表中:最后运行程序即可. pyth ...

  9. 读取EXCEL文件数据,再调用第三方接口,将第三方数据重新写入到EXCEL文件

    读取EXCEL文件数据,再调用第三方接口,将第三方数据重新写入到EXCEL文件 工作中涉及很多提供文档数据,少则几条,多则上万,少的可以自己编辑一个,静态final来自己定义,一旦数太多得话,就得使用 ...

最新文章

  1. C/C++中memset()函数
  2. 洛谷 P4475 巧克力王国 解题报告
  3. Go 语言编程 — 高级数据类型 — 数组
  4. 北斗导航 | 估计地面车辆(无人车)的位姿(IMU+GPS:附Matlab源代码)
  5. CentOS 6.5安装与配置PostgreSQL9.2
  6. 【渝粤教育】 国家开放大学2020年春季 1167环境水利学 参考试题
  7. NOIP模拟测试19「count·dinner·chess」
  8. 实时语义分割算法大盘点
  9. 【超参数寻优】交叉验证(Cross Validation)超参数寻优的python实现:多参数寻优
  10. 获取Element UI中button组件的ID值
  11. win10下ipv6安装与设置
  12. 【微信小程序】上传Word、txt、Excel、PPT等文件
  13. 朱光潜给青年的十二封信 之 谈读书
  14. Linux 文件系统类型 文件系统结构 与Windows文件系统的比较
  15. 新手怎么写电影解说文案?
  16. mac 备份文件 太大 时间机器_如何在Mac OS X中设置时间机器备份 | MOS86
  17. 诺基亚发布NetAct云网络管理系统,为5G网络演进铺路
  18. 金融风控机器学习第三十一天---拜师课堂 机器学习算法--决策树 随机森林
  19. 解决:删除文件夹提示指定的文件名无效或太长,无法删除
  20. html鼠标悬停事件 dw,dw制作鼠标放上去图片就显示鼠标离开图片就消失

热门文章

  1. 移动端touchmove卡顿
  2. picoCTF2020_Web
  3. 宝塔面板安装YukiDrive —— 支持OneDrive SharePoint的文件浏览程序
  4. 计算机通信技术的发展趋势,计算机技术在通信的应用与发展趋势
  5. 2022年最新江苏交安安全员考试题库及答案
  6. aspose,word转pdf,及破解思路
  7. 整理下维护别人项目遇到的Bug或者错误写法
  8. 我的世界服务器中的m p c显示指令,我的世界指令中的commat;p | 手游网游页游攻略大全...
  9. 木木夕推荐:第一款产品《美柚》
  10. 解决华为荣耀鸿蒙2.0系统设备未获得Play保护机制认证HarmonyOS安装谷歌服务框架GMS谷歌应用商店Google Play华为P40 Mate40 Mate30 P30