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;}// 这个每一条数据解析都会来调用@Overridepublic void invoke(DemoData data, AnalysisContext context) {list.add(data);// 在这里可以做一些其他的操作 就考自己去拓展了// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (list.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listlist.clear();}}// 所有数据解析完成了 都会来调用@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库// 当然也可以有很多其他操作 比如有些需要触发其他的 可以在这里调用saveData();}// 加上存储数据库private void saveData() {demoDAO.save(list);}// 读取条额外信息:批注、超链接、合并单元格信息等@Overridepublic 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:}}//在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。@Overridepublic 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的时候指定 不然是不会生效的。
--------------最后感谢大家的阅读,愿大家技术越来越流弊!--------------
--------------也希望大家给我点支持,谢谢各位大佬了!!!--------------