EasyExcel 框架使用-讀
EasyExcel 框架使用
官方介紹:JAVA解析Excel工具EasyExcel
Java解析、生成Excel比較有名的框架有Apache poi、jxl。但他們都存在一個嚴重的問題就是非常的耗內存,poi有一套SAX模式的API可以一定程度的解決一些內存溢出的問題,但POI還是有一些缺陷,比如07版Excel解壓縮以及解壓後存儲都是在內存中完成的,內存消耗依然很大。easyexcel重寫了poi對07版Excel的解析,能夠原本一個3M的excel用POI sax依然需要100M左右內存降低到幾M,並且再大的excel不會出現內存溢出,03版依賴POI的sax模式。在上層做了模型轉換的封裝,讓使用者更加簡單方便
EasyExcel 版本
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.9</version>
</dependency>
在EasyExcel 使用之前先要講一下EasyExcel 的Listener
Listener 里有處理每一條數據的方法
ReadListener源碼:
public interface ReadListener<T> extends Listener {
// 當解析拋出異常,會被此方法進行捕獲
void onException(Exception exception, AnalysisContext context) throws Exception;
// 解析表數據的表頭,headMap 默認表格第一行數據
void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context);
// 講一條數據解析後的對象 data,可以在這個方法中進行再次處理
void invoke(T data, AnalysisContext context);
// 官方介紹:返回額外信息調用,沒使用過
void extra(CellExtra extra, AnalysisContext context);
// 解析完成後,會運行此方法
void doAfterAllAnalysed(AnalysisContext context);
// 校驗是否繼續解析,默認true
boolean hasNext(AnalysisContext context);
}
這個方法會有一個傳入的泛型,就是將表格每一行數據解析成的對象
舉個例子:如果我們就想轉換成List
我們就可以轉換了,當然官方有一個默認List
但是你想獲取解析表格的數據最好自己重寫AnalysisEventListener,這樣你能把我數據的處理流程
EasyExcel 使用
讀數據
EasyExcel 讀數據有許多不同的方法,我們使用NoModelDataListener來看一下可以怎麼解析表格數據
public void test() {
// file 可以是文件,可以是流,也可以是文件路徑 但必須是.xsl或.xslx文件
File file = new File("");
// 讀取讀取傳入excel文件中某一張表的數據
// 第一種:sheet() 默認(不傳參數)為第一種表
// sheetNo 也可以指定第幾張表,表以0開始計數
// sheetName 也可以指定表名
// 讀取成功後文件流會自動關閉
EasyExcel.read(file,new NoModelDataListener()).sheet(0,"").doRead();
// 第一種:sheet() 默認為第一張表,也可以指定第幾張表,表以0開始計數
ExcelReader reader = EasyExcel.read(file, new NoModelDataListener()).build();
// 第一種:readSheet() 默認(不傳參數)為第一種表
// sheetNo 也可以指定第幾張表,表以0開始計數
// sheetName 也可以指定表名
//sheet不能讀取多次,多次讀取需要重新讀取文件
ReadSheet sheet = EasyExcel.readSheet().build();
reader.read(sheet);
// 記得關閉ExcelReader
reader.finish();
// EasyExcel 也可以替換成 EasyExcelFactory
// EasyExcel 繼承 EasyExcelFactory,EasyExcel沒有對EasyExcelFactory進行任何重寫
// 所以EasyExcel與EasyExcelFactory相當於同一個類
// 讀取讀取傳入excel文件,所有的表數據
// 第一種
// 但是如果解析失敗拋出異常或者Listener的hasNext方法返回false後就不會繼續往下執行
EasyExcel.read(file,new NoModelDataListener()).doReadAll();
// 第二種
// 但是如果解析失敗拋出異常,停止解析但是會關閉一些excelReader的數據,需要重新新建excelReader才能繼續循環執行
// Listener的hasNext方法返回false後就不會繼續往下執行,不會出現上面的問題
ExcelReader excelReader = EasyExcel.read(file, new NoModelDataListener()).build();
List<ReadSheet> readSheets = excelReader.excelExecutor().sheetList();
for (ReadSheet readSheet : readSheets) {
excelReader.read(readSheet);
}
// 記得關閉ExcelReader
excelReader.finish();
}
自定義Listener
上面說了讀取方式,下面說一下自定義Listener
其實我們可以封裝一個通用的Listener
這是我自己封裝的Listener
@Slf4j
public class DefaultExcelListener<T> extends AnalysisEventListener<T> {
// 解析後的數據
private final List<T> rows = new ArrayList();
// 解析表數據的表頭,headMap 默認表格第一行數據
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
log.info("======================================================");
log.info("解析第一行數據:{}" + JSON.toJSONString(headMap));
log.info("======================================================");
}
// 講一條數據解析後的對象 data,將解析後的數據保存到 rows中
@Override
public void invoke(T object, AnalysisContext context) {
rows.add(object);
}
// 讀取完excel數據後的操作
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
log.info("成功讀取【" + rows.size() + "】條數據");
}
// 在讀取excel異常 獲取其他異常下會調用本接口。拋出異常則停止讀取。如果這裡不拋出異常則 繼續讀取下一行。
@Override
public void onException(Exception exception, AnalysisContext context) {
System.out.println("解析失敗,但是繼續解析下一行:{}" + exception.getMessage());
}
public List<T> getRows() {
return rows;
}
}
我們傳入泛型對象(對象屬性添加EasyExcel 註解)就可以進行解析,最後獲取rows就可以得到解析後的數據
當然也可以根據自己的理解進行修改
使用中的問題
說一下在使用過程中遇到的問題
1.想要停止解析的問題
EasyExcel 想要解析需要拋出ExcelAnalysisStopException才能停止解析
例如你想檢驗表頭,表頭不匹配就不進行解析
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
// 不匹配
throw new ExcelAnalysisStopException();
}
拋出異常後會被onException方法進行捕獲
那就在onException中再拋出ExcelAnalysisStopException就可以拋出
@Override
public void onException(Exception exception, AnalysisContext context) {
if (exception instanceof ExcelAnalysisStopException) {
throw new ExcelAnalysisStopException("");
}
System.out.println("解析失敗,但是繼續解析下一行:{}" + exception.getMessage());
}
但是就一些的版本是不能拋出這個異常,onException會被上層進行捕獲,重新拋 出一個異常
所以想要停止解析,通過hasNext是比較保險的
2.將表格中單元格數據進行轉換成對象時,不會校驗字符串「」
將單元格數據轉換成對象使用有專門的轉換器Converter
Converter接口
public interface Converter<T> {
// 轉換後對象的類型
Class supportJavaTypeKey();
// 單元格數據類型
CellDataTypeEnum supportExcelTypeKey();
// cellData單元格數據
// T轉換後的對象
// 將單元格數據轉化成對象:主要是讀的時候使用
T convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws Exception;
// 將對象轉化成對象單元格數據:主要是寫的時候使用
CellData convertToExcelData(T value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration)
throws Exception;
}
EasyExcel 有一些基礎類型的默認轉換器,也是繼承Converter接口
如果我們需要自定義轉換器也可以繼承這個接口對方法進行重寫
在EasyExcel 使用轉換器的時候會默認使用String轉基本對象的方法
但是其中沒有進行對字符串””的校驗,所以在轉換Data等對象時會報錯
我是自定義進行解決的,不知道是不是我使用方式不對,還是已經有解決但是我沒有使用到,如果大家發現是我沒有發現,希望能告訴我一下
EasyExcel 默認轉換器都是使用自定義的基礎類型utils進行轉換
自定義Converter
說一下自定義Converter的使用
當我們自定義Converter後可以通過@ExcelProperty()指定對象中的某個屬性使用自定義轉換器
也可以在EasyExcel.read()後指定
EasyExcel.read(fileName, ConverterData.class, new ConverterDataListener())
// 這裡注意 我們也可以registerConverter來指定自定義轉換器, 但是這個轉換變成全局了, 所有java為string,excel為string的都會用這個轉換器。
// 如果就想單個字段使用請使用@ExcelProperty 指定converter
.registerConverter(new CustomStringStringConverter())
// 讀取sheet
.sheet().doRead();
@ExcelProperty()
用於屬性:與表頭進行匹配
value表頭名稱,可以配置多級表頭
index表序列號
converter自定義轉換器,將單元格數據轉換成對象
到這裡我們就可以使用EasyExcel 進行讀取數據進行處理,目前我就使用到了EasyExcel 讀取,後面使用到寫數據再更新寫出數據