相關依賴(pom):
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
AnalysisEventListener<T>:
public abstract class AnalysisEventListener<T> implements ReadListener<T> {
// 這是監(jiān)聽器的構造方法,一般我們可以通過構造方法傳入一些我們需要在解析excel時使用的數(shù)據(jù)
//(在這里,AnalysisEventListener<T>實現(xiàn)ReadListener<T>)
public AnalysisEventListener() {}
// 調用invokeHeadMap來獲取表頭數(shù)據(jù)
public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) {
this.invokeHeadMap(ConverterUtils.convertToStringMap(headMap, context), context);
}
// 獲取表頭數(shù)據(jù)
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {}
// 讀取條額外信息:批注、超鏈接、合并單元格信息等
public void extra(CellExtra extra, AnalysisContext context) {}
// 在轉換異常 獲取其他異常下會調用本接口。拋出異常則停止讀取。如果這里不拋出異常則 繼續(xù)讀取下一行。
public void onException(Exception exception, AnalysisContext context) throws Exception {throw exception;}
public boolean hasNext(AnalysisContext context) {return true;}
}
相關常用方法:
// 有個很重要的點 DemoDataListener 不能被spring管理,要每次讀取excel都要new,然后里面用到spring可以構造方法傳進去
public class DemoDataListener extends AnalysisEventListener<DemoData> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
//每隔5條存儲數(shù)據(jù)庫,實際使用中可以3000條,然后清理list ,方便內存回收
private static final int BATCH_COUNT = 5;
List<DemoData> list = new ArrayList<DemoData>();
//假設這個是一個DAO,當然有業(yè)務邏輯這個也可以是一個service。當然如果不用存儲這個對象沒用。
private DemoDAO demoDAO;
public DemoDataListener() {
// 這里是demo,所以隨便new一個。實際使用如果到了spring,請使用下面的有參構造函數(shù)
demoDAO = new DemoDAO();
}
//如果使用了spring,請使用這個構造方法。每次創(chuàng)建Listener的時候需要把spring管理的類傳進來
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
// 這個每一條數(shù)據(jù)解析都會來調用
@Override
public void invoke(DemoData data, AnalysisContext context) {
list.add(data);
// 在這里進行相關操作
// 達到BATCH_COUNT了,需要去存儲一次數(shù)據(jù)庫,防止數(shù)據(jù)幾萬條數(shù)據(jù)在內存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存儲完成清理 list
list.clear();
}
}
// 所有數(shù)據(jù)解析完成了 都會來調用
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 這里也要保存數(shù)據(jù),確保最后遺留的數(shù)據(jù)也存儲到數(shù)據(jù)庫
//saveData();
}
// 加上存儲數(shù)據(jù)庫
private void saveData() {
demoDAO.save(list);
}
Excel表中存在額外信息時
// 讀取條額外信息:批注、超鏈接、合并單元格信息等
@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(
"額外信息是超鏈接,而且覆蓋了一個區(qū)間,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"
+ "內容是:{}",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex(), extra.getText());
} else {
Assert.fail("Unknown hyperlink!");
}
break;
case MERGE:
LOGGER.info(
"額外信息是超鏈接,而且覆蓋了一個區(qū)間,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex());
break;
default:
}
}
//在轉換異常 獲取其他異常下會調用本接口。拋出異常則停止讀取。如果這里不拋出異常則 繼續(xù)讀取下一行。
@Override
public void onException(Exception exception, AnalysisContext context) {
// 如果是某一個單元格的轉換異常 能獲取到具體行號
// 如果要獲取頭的信息 配合invokeHeadMap使用
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
LOGGER.error("第{}行,第{}列解析異常", excelDataConvertException.getRowIndex(),
excelDataConvertException.getColumnIndex());
}
}
}
代碼來源:EasyExcel(一)導入excel的分析監(jiān)聽器_Zack_tzh的博客-CSDN博客_easyexcel監(jiān)聽器
個人Demo:
public class DemoDateListener extends AnalysisEventListener<Demo>{
private ststic final Logger LOGGER = LoggerFactory.getLogger(DemoDateListener.class);
private static final BATCH_COUNT = 1;
Demo demo = new Demo();
int count = 0;
boolean headFlag = false;//表頭標識
boolean headFlag1 = false;//表頭標識
boolean headFlag2 = false;//數(shù)字標識
private DemoService demoService;
public DemoListener(DemoService demoservice){
this.demoService=demoService
}
public void invoke(Demo data, AnalysisContext context) {
System.out.println(JSON.toJSONString(data));
if (data.getTest() != null) {
if (data.getTest().equals("實驗對象"))
headFlag = true;
}
if (headFlag && headFlag1) {
demo = data;
demo.setExcelType("2");
insertData();
}
if (data.getTest() != null) {
if (data.getTest().equals("實驗對象") || data.getTest().equals("實驗對象"))
headFlag1 = true;
}
}
public void doAfterAllAnalysed(AnalysisContext context) {
LOGGER.info("所有數(shù)據(jù)解析完成!");
}
private void insertData() {
}
}
按照需求不同,建立對應的listener。