EasyExcel(一)导入excel的分析监听器
关于easyExcel的基本用法我就不在多说了,有需要的可以自己点击该链接去学习基本的使用,主要对这里面经常用到的一些监听器和拦截器讲一下
一、准备工作
这是我用的easyexcel版本
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version></dependency>
二、讲解AnalysisEventListener< T>
- 监听器在有哪些方法
public abstract class AnalysisEventListener<T> implements ReadListener<T> { // 这是监听器的构造方法,一般我们可以通过构造方法传入一些我们需要在解析excel时使用的数据 public AnalysisEventListener() {} // 调用invokeHeadMap来获取表头数据 public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) { this.invokeHeadMap(ConverterUtils.convertToStringMap(headMap, context), context); }// 获取表头数据 public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {}// 读取条额外信息:批注、超链接、合并单元格信息等 public void extra(CellExtra extra, AnalysisContext context) {}// 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。 public void onException(Exception exception, AnalysisContext context) throws Exception {throw exception;} public boolean hasNext(AnalysisContext context) {return true;}}
其中可以看到AnalysisEventListener 实现了 ReadListener
然后看到ReadListener后 发现其中还有两个方法是AnalysisEventListener没有实现的,而且这两个方法还是很重要的
public interface ReadListener<T> extends Listener { void onException(Exception var1, AnalysisContext var2) throws Exception; void invokeHead(Map<Integer, CellData> var1, AnalysisContext var2);// 一行行读取表格内容 void invoke(T var1, AnalysisContext var2); void extra(CellExtra var1, AnalysisContext var2);// 读取完成后的操作 void doAfterAllAnalysed(AnalysisContext var1); boolean hasNext(AnalysisContext var1);}
- 实现监听器
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去public class DemoDataListener extends AnalysisEventListener<DemoData> { private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); //每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 private static final int BATCH_COUNT = 5; List<DemoData> list = new ArrayList<DemoData>(); //假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 private DemoDAO demoDAO; public DemoDataListener() { // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数 demoDAO = new DemoDAO(); } //如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 public DemoDataListener(DemoDAO demoDAO) { this.demoDAO = demoDAO; } // 这个每一条数据解析都会来调用 @Override public void invoke(DemoData data, AnalysisContext context) { list.add(data); // 在这里可以做一些其他的操作 就考自己去拓展了 // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM if (list.size() >= BATCH_COUNT) { saveData(); // 存储完成清理 list list.clear(); } } // 所有数据解析完成了 都会来调用 @Override public void doAfterAllAnalysed(AnalysisContext context) { // 这里也要保存数据,确保最后遗留的数据也存储到数据库 // 当然也可以有很多其他操作 比如有些需要触发其他的 可以在这里调用 saveData(); } // 加上存储数据库 private void saveData() { demoDAO.save(list); } // 读取条额外信息:批注、超链接、合并单元格信息等 @Override public void extra(CellExtra extra, AnalysisContext context) { LOGGER.info("读取到了一条额外信息:{}", JSON.toJSONString(extra)); switch (extra.getType()) { case COMMENT: LOGGER.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(), extra.getText()); break; case HYPERLINK: if ("Sheet1!A1".equals(extra.getText())) { LOGGER.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(), extra.getText()); } else if ("Sheet2!A1".equals(extra.getText())) { LOGGER.info( "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}," + "内容是:{}", extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(), extra.getLastColumnIndex(), extra.getText()); } else { Assert.fail("Unknown hyperlink!"); } break; case MERGE: LOGGER.info( "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}", extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(), extra.getLastColumnIndex()); break; default: } } //在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。 @Override public void onException(Exception exception, AnalysisContext context) { // 如果是某一个单元格的转换异常 能获取到具体行号 // 如果要获取头的信息 配合invokeHeadMap使用 if (exception instanceof ExcelDataConvertException) { ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(), excelDataConvertException.getColumnIndex()); } }}
// 在读的时候只需要new DemoDataListener 监听器传入就行了 EasyExcel.read(fileName, DemoData.class, new DemoDataListener()) // 需要读取批注 默认不读取 .extraRead(CellExtraTypeEnum.COMMENT) // 需要读取超链接 默认不读取 .extraRead(CellExtraTypeEnum.HYPERLINK) // 需要读取合并单元格信息 默认不读取 .extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();
简单描述一下这个的执行流程,最开始我们会传入DemoDataListener监听器,然后会每次解析一行的数据,解析完成无异常的情况下调用invoke方法,如果在该行出现异常就会调用onException方法,并且该行的数据会发生丢失。extra方法会在所有行都解析完后才回调用。并且需要在使用read的时候指定 不然是不会生效的。
--------------最后感谢大家的阅读,愿大家技术越来越流弊!--------------
--------------也希望大家给我点支持,谢谢各位大佬了!!!--------------