AnalysisEventListener#invoke()
-继承抽象类->
ReadListener#invoke()
-继承接口->
ReadListener#invoke(){接口}
DefaultAnalysisEventProcessor#dealData(AnalysisContext analysisContext)
{
ReadListener数据从analysisContext.currentReadHolder().readListenerList()获取
调用ReadListener.invoke()
}
–dealData()被同类方法endRow(AnalysisContext analysisContext)调用–>
DefaultAnalysisEventProcessor#endRow(AnalysisContext analysisContext){
这个方法只是判断了下context中的属性,打log
然后就直接传context给了dealData();
}
调用endRow的方法有以下三个:
RowTagHandler#startElement/endElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes)
---->
XlsxRowHandler#startElement/endElement((String uri, String localName, String name, Attributes attributes))
{
xlsxReadContext即Context是这个类中传入的。
}
这个类在
XlsxSaxAnalyser#execute()方法中被创建,并且Context属性是从这个类中传入的。
–这个类在哪被初始化的呢–>
ExcelAnalyserImpl#choiceExcelExecutor()
{
XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX);
}
Context是在这里被创建的。
-这个方法在ExcelAnalyserImpl(ReadWorkbook readWorkbook)初始化时被调用->
那么ExcelAnalyserImpl是在哪被初始化的呢
ExcelReader的构造器中被初始化的
public ExcelReader(ReadWorkbook readWorkbook) {
excelAnalyser = new ExcelAnalyserImpl(readWorkbook);
}
ExcelReader是在:
ExcelReaderBuilder#build()方法中创建的
public ExcelReader build() {
return new ExcelReader(readWorkbook);
}
这个方法被以下几个方法调用:
官方demo中的使用方法是:
EasyExcel.read(fileName, FormulaDataReadData.class, new FormulaHeadListener<>(serviceImpl)).sheet().doRead();
其中sheet()方法即使用了sheet(Integer,String)
我们还看到这个Demo后面调用了.doRead()方法
点进去可以看到:
public void doRead() {
if (excelReader == null) {
throw new ExcelGenerateException("Must use 'EasyExcelFactory.read().sheet()' to call this method");
}
excelReader.read(build());
excelReader.finish();
}
finish()是关闭流操作,可以从官网https://alibaba-easyexcel.github.io/quickstart/read.html的一个Demo可以看到
/**
* 读多个或者全部sheet,这里注意一个sheet不能读取多次,多次读取需要重新读取文件
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>
* 3. 直接读即可
*/
@Test
public void repeatedRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 读取全部sheet
// 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();
// 读取部分sheet
fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
ExcelReader excelReader = EasyExcel.read(fileName).build();
// 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
ReadSheet readSheet1 =
EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
ReadSheet readSheet2 =
EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
// 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能
excelReader.read(readSheet1, readSheet2);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
}
那么主要看
excelReader.read(build()){
build()为返回一个sheet,这个sheet
是构造ExcelReaderSheetBuilder也即doRead()方法所在类时new的一个ReadSheet
public ExcelReaderSheetBuilder() {
this.readSheet = new ReadSheet();
}
public ExcelReaderSheetBuilder(ExcelReader excelReader) {
this.readSheet = new ReadSheet();
this.excelReader = excelReader;
}
}
那么看看read(ReadSheet… readSheet)方法:
/**
* Parse the specified sheet锛孲heetNo start from 0
*
* @param readSheet
* Read sheet
*/
public ExcelReader read(ReadSheet... readSheet) {
return read(Arrays.asList(readSheet));
}
/**
* Read multiple sheets.
*
* @param readSheetList
* @return
*/
public ExcelReader read(List<ReadSheet> readSheetList) {
excelAnalyser.analysis(readSheetList, Boolean.FALSE);
return this;
}
excelAnalyser怎么获得的,主要有两个方法:
@Deprecated
public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent,
AnalysisEventListener eventListener, boolean trim){}
public ExcelReader(ReadWorkbook readWorkbook) {
excelAnalyser = new ExcelAnalyserImpl(readWorkbook);
}
所以主使用的是下面这个构造方法。
这个构造方法是在sheet()这个方法中被调用的:
public ExcelReaderSheetBuilder sheet(Integer sheetNo, String sheetName) {
ExcelReaderSheetBuilder excelReaderSheetBuilder = new ExcelReaderSheetBuilder(build());
if (sheetNo != null) {
excelReaderSheetBuilder.sheetNo(sheetNo);
}
if (sheetName != null) {
excelReaderSheetBuilder.sheetName(sheetName);
}
return excelReaderSheetBuilder;
}
然后看build()这个方法:
public ExcelReader build() {
return new ExcelReader(readWorkbook);
}
这个readWorkbook属性是在ExcelReaderBuilder的构造方法中赋值
public ExcelReaderBuilder() {
this.readWorkbook = new ReadWorkbook();
}
其实上面这些可以不用看的,因为都仅仅是new出一个对象,并没有进行更深层次的操作,影响不大。
我们现在主要看到了这个构造方法:
public ExcelReader(ReadWorkbook readWorkbook) {
excelAnalyser = new ExcelAnalyserImpl(readWorkbook);
}
这样我们就可以和前面写过的遥相呼应:
Listener是如何加入进去的呢?
主要是ExcelReaderBuilder中的readWorkbook成员变量。
ReadWorkbook继承了ReadBasicParameter
ReadBasicParameter中维护了一个private List customReadListenerList;
开始有些疑惑的点,后来理顺了:
XlsxRowHandler#startElement/endElement()在XlsxSaxAnalyser#execute()方法中被创建
那么这个方法如何被调用的呢?
调用流程如下:
ExcelReaderSheetBuilder#doRead()
--ExcelReader#read(ReadSheet… readSheet)–>
ExcelReader#read(List readSheetList)
--excelAnalyser.analysis(readSheetList, Boolean.FALSE)–>
ExcelAnalyserImpl#analysis(List readSheetList, Boolean readAll)
--excelReadExecutor.execute();
doRead()应该是EasyExcel中比较重要的方法了。