• EasyExcel低版本中数据行中包含空数据会跳过导致数据对应不上的问题解析


    文章摘自:https://blog.csdn.net/caijwjava/article/details/100855361

    实战

    1、导入一个相关依赖即可

    1. <dependency>
    2. <groupId>com.alibaba</groupId>
    3. <artifactId>easyexcel</artifactId>
    4. <version>2.2.6</version>
    5. </dependency>

    2、读取(上传)Excel文件,使用上非常的简单,只要几行代码。

    1. public class EasyExcelDemo {
    2. public static void main(String[] args) {
    3. String path = "E:\\tmp\\demo.xlsx";
    4. // 自定义读取每一行数据的事件监听
    5. ReadListen readListen = new ReadListen();
    6. // 开始读取Excel数据
    7. ExcelReader reader = EasyExcel.read(path, readListen).build();
    8. // 读取第一个sheet,readSheet默认是读取第一个,可以自定义
    9. ReadSheet readSheet = EasyExcel.readSheet().build();
    10. // 开始读取数据
    11. reader.read(readSheet);
    12. // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
    13. reader.finish();
    14. }
    15. }

    3、自定义ReadListen,主要是为了装数据,方便获取和使用,具体怎么调到这个方法的,以及出现的问题点在哪,往下走。。。

    1. public class ReadListen extends AnalysisEventListener {
    2. private List<T> sheetData = new ArrayList<>(10);
    3. @Override
    4. public void invoke(T t, AnalysisContext analysisContext) {
    5. sheetData.add(t);
    6. System.out.println(t);
    7. }
    8. @Override
    9. public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    10. // Excel数据解析完成后,想要实现的业务逻辑
    11. System.out.println("excel data resolve finish!!!");
    12. }
    13. }

    4、开始源码分析,easyexcel怎么读取数据,以及问题点分析解决!4.1 当调用reader.read(readSheet);时,进入

    1. public ExcelReader read(ReadSheet readSheet) {
    2. checkFinished();
    3. // 开始进入解析sheet
    4. excelAnalyser.analysis(readSheet);
    5. return this;
    6. }

    我们只要分析excelAnalyser.analysis(readSheet);,进入继续

    1. analysisContext.currentSheet(excelExecutor, readSheet);
    2. try {
    3. // 真正解析sheet表格的地方
    4. excelExecutor.execute();
    5. } catch (ExcelAnalysisStopException e) {
    6. if (LOGGER.isDebugEnabled()) {
    7. LOGGER.debug("Custom stop!");
    8. }
    9. }
    10. // 这个是在sheet表格解析完成后回调的方法,参考前面自定义的ReadListen
    11. analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);

    点击进入

    1. @Override
    2. public void execute() {
    3. parseXmlSource(sheetMap.get(analysisContext.readSheetHolder().getSheetNo()),
    4. // 这个就是我们真正关心的地方,每行解析完成后会执行的操作
    5. new XlsxRowHandler(analysisContext, stylesTable));
    6. }

    点击进入,继续

    1. public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable) {
    2. // 这个是每个单元格执行的一些操作,包括回调之类的
    3. this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, stylesTable);
    4. // ...
    5. }

    点击进去,这时我们会注意到notifyEndOneRow,这个正是需要关注的点,继续

    1. @Override
    2. public void endHandle(String name) {
    3. analysisContext.readSheetHolder()
    4. // 这个就是每一行表格数据解析完成后会触发的回调
    5. .notifyEndOneRow(new EachRowAnalysisFinishEvent(rowResultHandler.getCurRowContent()), analysisContext);
    6. rowResultHandler.clearResult();
    7. }

    点击继续,看看里面做了什么操作。。。

    1. @Override
    2. public void notifyEndOneRow(AnalysisFinishEvent event, AnalysisContext analysisContext) {
    3. // ...to do something
    4. if (rowIndex >= headRowNumber) {
    5. // Now is data
    6. for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {
    7. try {
    8. // 真正触发回调的地方,这里会有多个监听,包括我们前面自定义的ReadListen
    9. readListener.invoke(readRowHolder.getCurrentRowAnalysisResult(), analysisContext);
    10. // ...

    现在慢慢的明朗了整个读取流程,在debug之后,看看每个Listenner之后,找到一个ModelBuildEventListener,这个就是Excel数据转换的Listenner,也就是前面说到的会导致Excel表格列数据为空的时候,导致位置发生变化的地方,具体看看这里做了什么?

    1. private Object buildStringList(Map<Integer, CellData> cellDataMap, ReadHolder currentReadHolder,
    2. AnalysisContext context) {
    3. // 这里是为了兼容一些旧的代码,做了一个映射,是返回list还是map
    4. if (context.readWorkbookHolder().getDefaultReturnMap()) {
    5. // ...省略不需要关心的代码
    6. return map;
    7. } else {
    8. List<String> list = new ArrayList<String>();
    9. for (Map.Entry<Integer, CellData> entry : cellDataMap.entrySet()) {
    10. // ...省略不需要关心的代码
    11. return list;
    12. }
    13. }

    在进入context.readWorkbookHolder().getDefaultReturnMap())的时候,在新的版本中默认是true,这样返回map的时候就不会出现前面说的列数据对不上的问题。下面看看返回Map和List有什么区别。

    使用List返回的数据示例:

    使用Map返回的数据示例:

    通过对比,我们就很快可以发现使用List缺少了序号而导致无法把数据对应上,而使用Map的时候,key就是序号,value是我们需要的单元格数据。那么,这个开关在哪里呢?细心的应该看到了,如果你也存在这个问题,又不想升级版本等,可以使用一个开关设置成Map再转换成自己需要的List集合即可。或者说不想用Map,那么都可以自己设置。

    1. public static void main(String[] args) {
    2. // ...省略
    3. ReadSheet readSheet = EasyExcel.readSheet().build();
    4. // 具体的设置开关,新的的版本中默认true
    5. reader.analysisContext().readWorkbookHolder().setDefaultReturnMap(true);
    6. // 开始读取数据
    7. reader.read(readSheet);
    8. // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
    9. reader.finish();
    10. }

    在前面的代码中,添加一句reader.analysisContext().readWorkbookHolder().setDefaultReturnMap(true);,注意这里默认就是true,可以设置为false,返回的数据就是list了。

  • 相关阅读:
    EasyCVR平台通过接口编辑通道出现报错“ID不能为空”,是什么原因?
    电脑msvcp100.dll丢失了怎么办?详细的5个修复方法
    OpenCV学习——绘图函数案例
    安装Photon虚拟机
    开发上门按摩系统对技师如何管理,薪资结构怎么设计
    什么是自动采矿卡车autonomous mining trucks
    0001__非对称加密与 RSA 算法
    Hibernate 一对多关系映射
    【全开源】简单商城系统源码(PC/UniAPP)
    【基于Springboot、Mybatis后端框架开发——招生管理网站(系统)】附源码
  • 原文地址:https://blog.csdn.net/lingyejun/article/details/127828272