关于easyExcel的基本用法我就不在多说了,有需要的可以自己点击该链接去学习基本的使用,主要对这里面经常用到的一些监听器和拦截器讲一下
这是我用的easyexcel版本
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>2.2.6version>
dependency>
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的时候指定 不然是不会生效的。
--------------最后感谢大家的阅读,愿大家技术越来越流弊!--------------
--------------也希望大家给我点支持,谢谢各位大佬了!!!--------------