创建一个@Test测试方法:
@Test
public void simpleRead() {
// 写法1:JDK8+ ,不用额外写一个DemoDataListener
// since: 3.0.0-beta1
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
System.out.println(fileName);
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
// 这里每次会读取3000条数据 然后返回过来 直接调用使用数据就行
EasyExcel.read(fileName, DemoData.class, new PageReadListener<DemoData>(dataList -> {
for (DemoData demoData : dataList) {
//log.info("读取到一条数据{}", JSON.toJSONString(demoData));
System.out.println("读取到一条数据{}".format(JSON.toJSONString(demoData)));
}
})).sheet().doRead();
}
设置断点,主要想窥探EasyExcel.read().sheet().doRead();这行代码的执行流程:
0、new PageReadListener()
1、.read()
2、.sheet()
3、.doRead()
PageReadListener定义
package com.alibaba.excel.read.listener;
import java.util.List;
import java.util.function.Consumer;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.util.ListUtils;
import org.apache.commons.collections4.CollectionUtils;
/**
* page read listener
*
* @author Jiaju Zhuang
*/
public class PageReadListener<T> implements ReadListener<T> {
/**
* Single handle the amount of data
*/
public static int BATCH_COUNT = 100;
/**
* Temporary storage of data
*/
private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* consumer
*/
private final Consumer<List<T>> consumer;
public PageReadListener(Consumer<List<T>> consumer) {
this.consumer = consumer;
}
@Override
public void invoke(T data, AnalysisContext context) {
cachedDataList.add(data);
if (cachedDataList.size() >= BATCH_COUNT) {
consumer.accept(cachedDataList);
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
if (CollectionUtils.isNotEmpty(cachedDataList)) {
consumer.accept(cachedDataList);
}
}
}
根据狂神视频这个监听的作用是和spring框架配合使用,估计是创建监听后,等待被调用。
我感觉PageReadListener像带控制开关的一个容器,当容器中的数据满了(达到100),就执行操作过程,但是具体操作过程在consumer中。
private final Consumer<List<T>> consumer;还不知道这个消费者作用
new PageReadListener<DemoData>(dataList -> {
for (DemoData demoData : dataList) {
//log.info("读取到一条数据{}", JSON.toJSONString(demoData));
System.out.println("读取到一条数据{}".format(JSON.toJSONString(demoData)));
}
})
这里new PageReadListener对象的参数是一个匿名函数,这个匿名函数被复制给consumer,将来读取操作后,就执行这个匿名函数的代码。
明白了这一点,后面的都可以不看。
ReadListener接口的定义:
package com.alibaba.excel.read.listener;
import java.util.Map;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.Listener;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.metadata.data.ReadCellData;
/**
* Interface to listen for read results
*
* @author Jiaju Zhuang
*/
public interface ReadListener<T> extends Listener {
/**
* All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the
* entire read will terminate.
*
* @param exception
* @param context
* @throws Exception
*/
default void onException(Exception exception, AnalysisContext context) throws Exception {
throw exception;
}
/**
* When analysis one head row trigger invoke function.
*
* @param headMap
* @param context
*/
default void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {}
/**
* When analysis one row trigger invoke function.
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context analysis context
*/
void invoke(T data, AnalysisContext context);
/**
* The current method is called when extra information is returned
*
* @param extra extra information
* @param context analysis context
*/
default void extra(CellExtra extra, AnalysisContext context) {}
/**
* if have something to do after all analysis
*
* @param context
*/
void doAfterAllAnalysed(AnalysisContext context);
/**
* Verify that there is another piece of data.You can stop the read by returning false
*
* @param context
* @return
*/
default boolean hasNext(AnalysisContext context) {
return true;
}
}
EasyExcel.read()定义
package com.alibaba.excel;
/**
* This is actually {@link EasyExcelFactory}, and short names look better.
*
* @author jipengfei
*/
public class EasyExcel extends EasyExcelFactory {}
package com.alibaba.excel;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.builder.ExcelWriterTableBuilder;
/**
* Reader and writer factory class
*
* <h1>Quick start</h1>
* <h2>Read</h2>
* <h3>Sample1</h3>
*
* <h3>Sample2</h3>
*
* <h2>Write</h2>
*
* <h3>Sample1</h3>
*
* <h3>Sample2</h3>
*
*
*
* @author jipengfei
*/
public class EasyExcelFactory {
/**
* Build excel the write
*
* @return
*/
public static ExcelWriterBuilder write() {
return new ExcelWriterBuilder();
}
/**
* Build excel the write
*
* @param file
* File to write
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(File file) {
return write(file, null);
}
/**
* Build excel the write
*
* @param file
* File to write
* @param head
* Annotate the class for configuration information
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(File file, Class head) {
ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder();
excelWriterBuilder.file(file);
if (head != null) {
excelWriterBuilder.head(head);
}
return excelWriterBuilder;
}
/**
* Build excel the write
*
* @param pathName
* File path to write
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(String pathName) {
return write(pathName, null);
}
/**
* Build excel the write
*
* @param pathName
* File path to write
* @param head
* Annotate the class for configuration information
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(String pathName, Class head) {
ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder();
excelWriterBuilder.file(pathName);
if (head != null) {
excelWriterBuilder.head(head);
}
return excelWriterBuilder;
}
/**
* Build excel the write
*
* @param outputStream
* Output stream to write
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(OutputStream outputStream) {
return write(outputStream, null);
}
/**
* Build excel the write
*
* @param outputStream
* Output stream to write
* @param head
* Annotate the class for configuration information.
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(OutputStream outputStream, Class head) {
ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder();
excelWriterBuilder.file(outputStream);
if (head != null) {
excelWriterBuilder.head(head);
}
return excelWriterBuilder;
}
/**
* Build excel the <code>writerSheet</code>
*
* @return Excel sheet writer builder
*/
public static ExcelWriterSheetBuilder writerSheet() {
return writerSheet(null, null);
}
/**
* Build excel the <code>writerSheet</code>
*
* @param sheetNo
* Index of sheet,0 base.
* @return Excel sheet writer builder.
*/
public static ExcelWriterSheetBuilder writerSheet(Integer sheetNo) {
return writerSheet(sheetNo, null);
}
/**
* Build excel the 'writerSheet'
*
* @param sheetName
* The name of sheet.
* @return Excel sheet writer builder.
*/
public static ExcelWriterSheetBuilder writerSheet(String sheetName) {
return writerSheet(null, sheetName);
}
/**
* Build excel the 'writerSheet'
*
* @param sheetNo
* Index of sheet,0 base.
* @param sheetName
* The name of sheet.
* @return Excel sheet writer builder.
*/
public static ExcelWriterSheetBuilder writerSheet(Integer sheetNo, String sheetName) {
ExcelWriterSheetBuilder excelWriterSheetBuilder = new ExcelWriterSheetBuilder();
if (sheetNo != null) {
excelWriterSheetBuilder.sheetNo(sheetNo);
}
if (sheetName != null) {
excelWriterSheetBuilder.sheetName(sheetName);
}
return excelWriterSheetBuilder;
}
/**
* Build excel the <code>writerTable</code>
*
* @return Excel table writer builder.
*/
public static ExcelWriterTableBuilder writerTable() {
return writerTable(null);
}
/**
* Build excel the 'writerTable'
*
* @param tableNo
* Index of table,0 base.
* @return Excel table writer builder.
*/
public static ExcelWriterTableBuilder writerTable(Integer tableNo) {
ExcelWriterTableBuilder excelWriterTableBuilder = new ExcelWriterTableBuilder();
if (tableNo != null) {
excelWriterTableBuilder.tableNo(tableNo);
}
return excelWriterTableBuilder;
}
/**
* Build excel the read
*
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read() {
return new ExcelReaderBuilder();
}
/**
* Build excel the read
*
* @param file
* File to read.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(File file) {
return read(file, null, null);
}
/**
* Build excel the read
*
* @param file
* File to read.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(File file, ReadListener readListener) {
return read(file, null, readListener);
}
/**
* Build excel the read
*
* @param file
* File to read.
* @param head
* Annotate the class for configuration information.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(File file, Class head, ReadListener readListener) {
ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
excelReaderBuilder.file(file);
if (head != null) {
excelReaderBuilder.head(head);
}
if (readListener != null) {
excelReaderBuilder.registerReadListener(readListener);
}
return excelReaderBuilder;
}
/**
* Build excel the read
*
* @param pathName
* File path to read.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(String pathName) {
return read(pathName, null, null);
}
/**
* Build excel the read
*
* @param pathName
* File path to read.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(String pathName, ReadListener readListener) {
return read(pathName, null, readListener);
}
/**
* Build excel the read
*
* @param pathName
* File path to read.
* @param head
* Annotate the class for configuration information.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(String pathName, Class head, ReadListener readListener) {
ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
excelReaderBuilder.file(pathName);
if (head != null) {
excelReaderBuilder.head(head);
}
if (readListener != null) {
excelReaderBuilder.registerReadListener(readListener);
}
return excelReaderBuilder;
}
/**
* Build excel the read
*
* @param inputStream
* Input stream to read.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(InputStream inputStream) {
return read(inputStream, null, null);
}
/**
* Build excel the read
*
* @param inputStream
* Input stream to read.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(InputStream inputStream, ReadListener readListener) {
return read(inputStream, null, readListener);
}
/**
* Build excel the read
*
* @param inputStream
* Input stream to read.
* @param head
* Annotate the class for configuration information.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(InputStream inputStream, Class head, ReadListener readListener) {
ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
excelReaderBuilder.file(inputStream);
if (head != null) {
excelReaderBuilder.head(head);
}
if (readListener != null) {
excelReaderBuilder.registerReadListener(readListener);
}
return excelReaderBuilder;
}
/**
* Build excel the 'readSheet'
*
* @return Excel sheet reader builder.
*/
public static ExcelReaderSheetBuilder readSheet() {
return readSheet(null, null);
}
/**
* Build excel the 'readSheet'
*
* @param sheetNo
* Index of sheet,0 base.
* @return Excel sheet reader builder.
*/
public static ExcelReaderSheetBuilder readSheet(Integer sheetNo) {
return readSheet(sheetNo, null);
}
/**
* Build excel the 'readSheet'
*
* @param sheetName
* The name of sheet.
* @return Excel sheet reader builder.
*/
public static ExcelReaderSheetBuilder readSheet(String sheetName) {
return readSheet(null, sheetName);
}
/**
* Build excel the 'readSheet'
*
* @param sheetNo
* Index of sheet,0 base.
* @param sheetName
* The name of sheet.
* @return Excel sheet reader builder.
*/
public static ExcelReaderSheetBuilder readSheet(Integer sheetNo, String sheetName) {
ExcelReaderSheetBuilder excelReaderSheetBuilder = new ExcelReaderSheetBuilder();
if (sheetNo != null) {
excelReaderSheetBuilder.sheetNo(sheetNo);
}
if (sheetName != null) {
excelReaderSheetBuilder.sheetName(sheetName);
}
return excelReaderSheetBuilder;
}
}
有个空的class,还有个工厂class,实际是一样的,EasyExcel是EasyExcelFactory 的别名。
EasyExcelFactory 是最终代码的出处,有五个功能函数(及函数的重写):
write()、writerSheet()、writerTable()、read()、readSheet()
本例实际调用的是这个函数:
/**
* Build excel the read
*
* @param pathName
* File path to read.
* @param head
* Annotate the class for configuration information.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(String pathName, Class head, ReadListener readListener) {
ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
excelReaderBuilder.file(pathName);
if (head != null) {
excelReaderBuilder.head(head);
}
if (readListener != null) {
excelReaderBuilder.registerReadListener(readListener);
}
return excelReaderBuilder;
}
其中,ExcelReaderBuilder的作用是为 读取对象“ExcelReader”配置参数。比如
读取路径:
excelReaderBuilder.file(pathName);
注册监听:
excelReaderBuilder.registerReadListener(readListener);
package com.alibaba.excel.read.builder;
import java.io.File;
import java.io.InputStream;
import java.util.HashSet;
import java.util.List;
import javax.xml.parsers.SAXParserFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.ReadCacheSelector;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.event.SyncReadListener;
import com.alibaba.excel.read.listener.ModelBuildEventListener;
import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.support.ExcelTypeEnum;
/**
* Build ExcelWriter
*
* @author Jiaju Zhuang
*/
public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder<ExcelReaderBuilder, ReadWorkbook> {
/**
* Workbook
*/
private ReadWorkbook readWorkbook;
public ExcelReaderBuilder() {
this.readWorkbook = new ReadWorkbook();
}
public ExcelReaderBuilder excelType(ExcelTypeEnum excelType) {
readWorkbook.setExcelType(excelType);
return this;
}
/**
* Read InputStream
* <p>
* If 'inputStream' and 'file' all not empty, file first
*/
public ExcelReaderBuilder file(InputStream inputStream) {
readWorkbook.setInputStream(inputStream);
return this;
}
/**
* Read file
* <p>
* If 'inputStream' and 'file' all not empty, file first
*/
public ExcelReaderBuilder file(File file) {
readWorkbook.setFile(file);
return this;
}
/**
* Read file
* <p>
* If 'inputStream' and 'file' all not empty, file first
*/
public ExcelReaderBuilder file(String pathName) {
return file(new File(pathName));
}
/**
* Mandatory use 'inputStream' .Default is false.
* <p>
* if false, Will transfer 'inputStream' to temporary files to improve efficiency
*/
public ExcelReaderBuilder mandatoryUseInputStream(Boolean mandatoryUseInputStream) {
readWorkbook.setMandatoryUseInputStream(mandatoryUseInputStream);
return this;
}
/**
* Default true
*
* @param autoCloseStream
* @return
*/
public ExcelReaderBuilder autoCloseStream(Boolean autoCloseStream) {
readWorkbook.setAutoCloseStream(autoCloseStream);
return this;
}
/**
* Ignore empty rows.Default is true.
*
* @param ignoreEmptyRow
* @return
*/
public ExcelReaderBuilder ignoreEmptyRow(Boolean ignoreEmptyRow) {
readWorkbook.setIgnoreEmptyRow(ignoreEmptyRow);
return this;
}
/**
* This object can be read in the Listener {@link AnalysisEventListener#invoke(Object, AnalysisContext)}
* {@link AnalysisContext#getCustom()}
*
* @param customObject
* @return
*/
public ExcelReaderBuilder customObject(Object customObject) {
readWorkbook.setCustomObject(customObject);
return this;
}
/**
* A cache that stores temp data to save memory.
*
* @param readCache
* @return
*/
public ExcelReaderBuilder readCache(ReadCache readCache) {
readWorkbook.setReadCache(readCache);
return this;
}
/**
* Select the cache.Default use {@link com.alibaba.excel.cache.selector.SimpleReadCacheSelector}
*
* @param readCacheSelector
* @return
*/
public ExcelReaderBuilder readCacheSelector(ReadCacheSelector readCacheSelector) {
readWorkbook.setReadCacheSelector(readCacheSelector);
return this;
}
/**
* Whether the encryption
*
* @param password
* @return
*/
public ExcelReaderBuilder password(String password) {
readWorkbook.setPassword(password);
return this;
}
/**
* SAXParserFactory used when reading xlsx.
* <p>
* The default will automatically find.
* <p>
* Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
*
* @see SAXParserFactory#newInstance()
* @see SAXParserFactory#newInstance(String, ClassLoader)
* @param xlsxSAXParserFactoryName
* @return
*/
public ExcelReaderBuilder xlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) {
readWorkbook.setXlsxSAXParserFactoryName(xlsxSAXParserFactoryName);
return this;
}
/**
* Read some extra information, not by default
*
* @param extraType
* extra information type
* @return
*/
public ExcelReaderBuilder extraRead(CellExtraTypeEnum extraType) {
if (readWorkbook.getExtraReadSet() == null) {
readWorkbook.setExtraReadSet(new HashSet<CellExtraTypeEnum>());
}
readWorkbook.getExtraReadSet().add(extraType);
return this;
}
/**
* Whether to use the default listener, which is used by default.
* <p>
* The {@link ModelBuildEventListener} is loaded by default to convert the object.
*
* @param useDefaultListener
* @return
*/
public ExcelReaderBuilder useDefaultListener(Boolean useDefaultListener) {
readWorkbook.setUseDefaultListener(useDefaultListener);
return this;
}
public ExcelReader build() {
return new ExcelReader(readWorkbook);
}
public void doReadAll() {
ExcelReader excelReader = build();
excelReader.readAll();
excelReader.finish();
}
/**
* Synchronous reads return results
*
* @return
*/
public <T> List<T> doReadAllSync() {
SyncReadListener syncReadListener = new SyncReadListener();
registerReadListener(syncReadListener);
ExcelReader excelReader = build();
excelReader.readAll();
excelReader.finish();
return (List<T>)syncReadListener.getList();
}
public ExcelReaderSheetBuilder sheet() {
return sheet(null, null);
}
public ExcelReaderSheetBuilder sheet(Integer sheetNo) {
return sheet(sheetNo, null);
}
public ExcelReaderSheetBuilder sheet(String sheetName) {
return sheet(null, sheetName);
}
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;
}
@Override
protected ReadWorkbook parameter() {
return readWorkbook;
}
}
这是excelReaderBuilder.file(pathName);的定义和调用的内部函数,最终执行了readWorkbook.setFile(file);将读取的文件保存在内部对象readWorkbook中。
/**
* Read file
* <p>
* If 'inputStream' and 'file' all not empty, file first
*/
public ExcelReaderBuilder file(File file) {
readWorkbook.setFile(file);
return this;
}
/**
* Read file
* <p>
* If 'inputStream' and 'file' all not empty, file first
*/
public ExcelReaderBuilder file(String pathName) {
return file(new File(pathName));
}
这是excelReaderBuilder.registerReadListener(readListener);的定义,从抽象类的名称AbstractExcelReaderParameterBuilder可以看出,这个类和它的子类就是用于设置参数的:
package com.alibaba.excel.read.builder;
import com.alibaba.excel.metadata.AbstractParameterBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadBasicParameter;
import com.alibaba.excel.util.ListUtils;
/**
* Build ExcelBuilder
*
* @author Jiaju Zhuang
*/
public abstract class AbstractExcelReaderParameterBuilder<T extends AbstractExcelReaderParameterBuilder,
C extends ReadBasicParameter> extends AbstractParameterBuilder<T, C> {
/**
* Count the number of added heads when read sheet.
*
* <p>
* 0 - This Sheet has no head ,since the first row are the data
* <p>
* 1 - This Sheet has one row head , this is the default
* <p>
* 2 - This Sheet has two row head ,since the third row is the data
*
* @param headRowNumber
* @return
*/
public T headRowNumber(Integer headRowNumber) {
parameter().setHeadRowNumber(headRowNumber);
return self();
}
/**
* Whether to use scientific Format.
*
* default is false
*
* @param useScientificFormat
* @return
*/
public T useScientificFormat(Boolean useScientificFormat) {
parameter().setUseScientificFormat(useScientificFormat);
return self();
}
/**
* Custom type listener run after default
*
* @param readListener
* @return
*/
public T registerReadListener(ReadListener<?> readListener) {
if (parameter().getCustomReadListenerList() == null) {
parameter().setCustomReadListenerList(ListUtils.newArrayList());
}
parameter().getCustomReadListenerList().add(readListener);
return self();
}
}
注册监听的定义用到了ReadListener接口作为参数类型。parameter()函数应该是其父类AbstractParameterBuilder的函数。