easyexcel 读取指定行数据_使用设计模式简化EasyExcel读取(从30行到1行)

本文介绍了如何通过Java8的Consumer和模板方法设计模式简化EasyExcel的读取操作,避免为每个Excel文件创建单独的监听器类。作者提供了一个共用的EasyExcel读取监听器,将数据处理前置,实现分页读取,并给出简化后的使用示例。此外,还探讨了如何进一步封装读取方法和返回Page对象以增强进度反馈。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工作中总会遇到对Excel读写功能,EasyExcel开源挺久了,但使用上感觉有点让人望而生怯,刚开始看官方文档上读取Excel挺简单的,只需要一行代码[1],继续细看的话还需要创建一个回调监听器[2],有点复杂呀(每个Excel都需要创建一个单独的回调监听器类)。

10b07593057f2a5eb79710fe69c27b5c.png
EasyExcel官方读取示例

3ffc720942278cd9c0017f62a1e96067.png
EasyExcel读取监听器

平常用poi读取excel数据量少,加上EasyExcel读取Excel有点复杂,所以一直也没在项目中使用EasyExcel,直到有一回要读取的数据量太大,使用poi读取Excel在创建Workbook -> WorkbookFactory.create(inputStream) 时就异常了,分配很多内存也不好使,所以放弃使用poi转使用EasyExcel。

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 --EasyExcel

使用EasyExcel读取Excel时一直在想如何简化读取方式,不用读取每个Excel都创建一个XXDataListene监听器类,刚开始想,把DataListener加上泛型,共用一个DataListener<T>,但是还涉及到如何传递Dao和每个Dao如何保存数据,而且保存数据前可能还需要对数据进行不同的处理。

5fbae9c800db72649b6a556750253821.png
EasyExcel读取监听器共用监听器涉及的难点

最后想到了可以用Java8的Consumer + 模板方法设计模式/环绕执行模式/回调(Java8以下可以用匿名内部类),创建一个共用的EasyExcel读取监听器,不在监听器中对数据进行处理,把处理前置。

a1221b612c980142a3d96ed8255e1437.png
EasyExcel读取监听共用

新建一个读取方法,将调用读取方法时需要创建Listener的步骤隐藏到新方法内,并把Consumer传递到Listener中。*此类继承EasyExcel类。

a0b4befbd6b5b6847df418c7a0070118.png
EasyExcel读取简化(二次封装)

EasyExcel读取封装后的使用示例:(此处将EasyExcel读取的数据进行了分页,并将原先需在监听器中处理的数据前置到和读取方法同层进行)

Integer pageSize = 7;
ExcelUtil.read(excelFile, DemoData.class, pageSize, pageList -> {
  log.info("读取到数据:[size={}]{}", pageList.size(), pageList); // or demoDataService.save(pageList);
}).sheet().doRead();
// 读取到数据:[size=7][DemoData(string=字符串0, date=Wed Jan 01 01:01:01 CST 2020, doubleData=1.0), DemoData(string=字符串1, date=Thu Jan 02 01:01:01 CST 2020, doubleData=2.0), DemoData(string=字符串2, date=Fri Jan 03 01:01:01 CST 2020, doubleData=3.0), DemoData(string=字符串3, date=Sat Jan 04 01:01:01 CST 2020, doubleData=4.0), DemoData(string=字符串4, date=Sun Jan 05 01:01:01 CST 2020, doubleData=5.0), DemoData(string=字符串5, date=Mon Jan 06 01:01:01 CST 2020, doubleData=6.0), DemoData(string=字符串6, date=Tue Jan 07 01:01:01 CST 2020, doubleData=7.0)]
// 读取到数据:[size=3][DemoData(string=字符串7, date=Wed Jan 08 01:01:01 CST 2020, doubleData=8.0), DemoData(string=字符串8, date=Thu Jan 09 01:01:01 CST 2020, doubleData=9.0), DemoData(string=字符串9, date=Fri Jan 10 01:01:01 CST 2020, doubleData=10.0)]

参考:EasyExcel官网读取示例代码

EasyExcel分页读取完整代码实现:

import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.function.Consumer;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;

/**
 * Excel工具类.
 * @author www@yiynx.cn
 */
public class ExcelUtil extends EasyExcel {
  private ExcelUtil() {}
  
  public static <T> ExcelReaderBuilder read(String pathName, Class<T> head, Integer pageSize, Consumer<List<T>> consumer) {
    return read(pathName, head, new EasyExcelConsumerListener<>(pageSize, consumer));
  }

  public static <T> ExcelReaderBuilder read(File file, Class<T> head, Integer pageSize, Consumer<List<T>> consumer) {
    return read(file, head, new EasyExcelConsumerListener<>(pageSize, consumer));
  }
  
  public static <T> ExcelReaderBuilder read(InputStream inputStream, Class<T> head, Integer pageSize, Consumer<List<T>> consumer) {
    return read(inputStream, head, new EasyExcelConsumerListener<>(pageSize, consumer));
  }
}

EasyExcelConsumerListener.java

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

/**
 * EasyExcel消费监听.
 * @author www@yiynx.cn
 * @param <T>
 * see <a href="https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java">DemoDataListener</a>
 */
public class EasyExcelConsumerListener<T> extends AnalysisEventListener<T> {
  private int pageSize;
  private List<T> list;
  private Consumer<List<T>> consumer;
  
  public EasyExcelConsumerListener(int pageSize, Consumer<List<T>> consumer) {
      this.pageSize = pageSize;
      this.consumer = consumer;
      list = new ArrayList<>(pageSize);
  }
  
  @Override
  public void invoke(T data, AnalysisContext context) {
      list.add(data);
      if (list.size() >= pageSize) {
          consumer.accept(list);
          list.clear();
      }
  }
  
  @Override
  public void doAfterAllAnalysed(AnalysisContext context) {
      consumer.accept(list);
  }
}
  • 另1:还可以在ExcelUtil中定义一个默认分页大小, 再次简化调用(省略pageSize参数)。
ExcelUtil.read(excelFile, DemoData.class, pageList -> {
    System.out.println(pageList.size());
}).sheet().doRead(); // 默认分页大小
  • 另2:可以封装一个Page类,不直接返回pageList,而是返回page对象,这样可以通过page类知道当前是第几页,共几页,总条数等,方便输出处理进度(向前端推送读取Excel的处理进度)。

说明:从30行到1行

简化后使用示例:

ExcelUtil.read(excelFile, DemoData.class, pageSize, pageList -> dataService.save(pageList)).sheet().doRead();

简化前使用示例(简化版-对读取监听器代码[2]进行了删减部分注释代码后代码30行左右):

EasyExcel.read(fileName, DemoData.class, new DemoDataListener(dataService)).sheet().doRead();

// DemoDataListener.java
package com.test.test.demo.read;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

/**
 * 模板的读取类
 * @author https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java
 */
public class DemoDataListener extends AnalysisEventListener<DemoData> {
    private static final int BATCH_COUNT = 5;
    private List<DemoData> list = new ArrayList<>();
    private DemoService demoService;

    public DemoDataListener(DemoService demoService) {
        this.demoService = demoService;
    }

    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        list.add(data);
        if (list.size() >= BATCH_COUNT) {
            saveData();
            list.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
    }

    private void saveData() {
        demoService.save(list);
    }
}

关键词:EasyExcel分页读取;EasyExcel读取封装;EasyExcel读取简化;EasyExcel读取处理前置;EasyExcel读取监听器泛型;EasyExcel DataListener 泛型;Java8;Consumer;


《大话设计模式》京东 电子书 ¥9.99​e.jd.com
7dc946bcd78c3ba8962349b03606dda4.png

对于编程思想和能力有重大提升的书有哪些? - 似懂非懂风格的话的回答 - 知乎 https://www.zhihu.com/question/35648714/answer/65081192

参考

  1. ^EasyExcel-读Excel https://alibaba-easyexcel.github.io/index.html
  2. ^abDemoDataListener.java https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值