【軟體工具】easyExcel簡明使用指南
阿新 • • 發佈:2019-12-05
easyExcel簡介
Java領域解析、生成Excel比較有名的框架有Apache poi、jxl等。但他們都存在一個嚴重的問題就是非常的耗記憶體。如果你的系統併發量不大的話可能還行,但是一旦併發上來後一定會OOM或者JVM頻繁的full gc。
easyExcel是阿里巴巴開源的一個excel處理框架,以使用簡單、節省記憶體著稱。
64M記憶體1分鐘內讀取75M(46W行25列)的Excel(當然還有急速模式能更快,但是記憶體佔用會在100M多一點)
easyExcel能大大減少佔用記憶體的主要原因是在解析Excel時沒有將檔案資料一次性全部載入到記憶體中,而是從磁碟上一行行讀取資料,逐個解析。
下圖是easyExcel和POI在解析Excel時的對比圖。
easyExcel採用一行一行的解析模式,並將一行的解析結果以觀察者的模式通知處理(AnalysisEventListener)。
上面簡要介紹了easyExcel的特點和原理,關於easyExcel的其他問題可以先參考下這個文章。下面就通過程式碼來介紹下怎麼使用easyExcel。
快速使用指南
檔案上傳讀取Excel
下面通過一個讀取使用者資訊的列子來展示下怎麼使用easyExcel。
step1:建立使用者資訊類
@Data public class UserInfo extends BaseRowModel { @ExcelProperty(index = 0) private String name; @ExcelProperty(index = 1) private int age; @ExcelProperty(index = 2) private String address; }
step2:建立AnalysisEventListener子類
/** * 每解析一行會回撥invoke()方法。 * 整個excel解析結束會執行doAfterAllAnalysed()方法 */ //有個很重要的點 不能被spring管理,要每次讀取excel都要new。 //這邊就會有一個問題:如果UserInfoDataListener中需要用到Spring中的主鍵怎麼辦? public class UserInfoDataListener extends AnalysisEventListener<UserInfo> { Logger logger = LoggerFactory.getLogger(UserInfoDataListener.class); //每次讀取100條資料就進行儲存操作 private static final int BATCH_COUNT = 100; //由於每次讀都是新new UserInfoDataListener的,所以這個list不會存線上程安全問題 List<UserInfo> list = new ArrayList<>(); //這個元件是Spring中的元件,這邊推薦兩種方法注入這個元件 //第一種就是提供一個UserInfoDataListener的構造方法,這個方法提供一個引數是UserInfoDataListener型別 //另外一種方法就是將 UserInfoDataListener 這個類定義成 UserService 實現類的內部類(推薦這種方式) //private UserService userService; @Override public void invoke(UserInfo data, AnalysisContext analysisContext) { logger.info("解析到一條資料:{}", JSON.toJSONString(data)); list.add(data); if (list.size() >= BATCH_COUNT) { saveData(); // 儲存完成清理 list list.clear(); } } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { // 這裡也要儲存資料,確保最後遺留的資料也儲存到資料庫 saveData(); logger.info("所有資料解析完成!"); } private void saveData() { logger.info("{}條資料,開始儲存資料庫!", list.size()); //儲存資料 //userService.save(list); logger.info("儲存資料庫成功!"); } }
step3: 讀取excel
public class EasyExcelDemo {
public static void main(String[] args) throws Exception {
InputStream fis = new FileInputStream("D:\\UserInfo.xlsx");
AnalysisEventListener listener = new UserInfoDataListener();
ExcelReader excelReader = EasyExcel.read(fis, UserInfo.class, listener).build();
ReadSheet readSheet = EasyExcel.readSheet(0).build();
ReadSheet readSheet2 = EasyExcel.readSheet(1).build();
excelReader.read(readSheet);
// 這裡千萬別忘記關閉,讀的時候會建立臨時檔案,到時磁碟會崩的
excelReader.finish();
}
}
只需要上面3步就能進行Excel的讀取了。
檔案下載Excel
public class ExcelUtil {
public static OutputStream getOutputStream(String fileName, HttpServletResponse response)
throws Exception{
try{
fileName = URLEncoder.encode(fileName,"utf-8");
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//此處指定了檔案型別為xls,如果是xlsx的,請自行替換修改
response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xls");
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "no-store");
response.addHeader("Cache-Control", "max-age=0");
return response.getOutputStream();
} catch (IOException e){
throw new Exception("匯出檔案失敗!");
}
}
public static void writeExcel(HttpServletResponse response, List<? extends BaseRowModel> list, String fileName,
String sheetName, Class clazz) throws Exception {
ExcelWriter writer = new ExcelWriter(getOutputStream(fileName, response), ExcelTypeEnum.XLS);
Sheet sheet = new Sheet(1, 0, clazz);
sheet.setSheetName(sheetName);
writer.write(list, sheet);
writer.finish();
}
}
在Controller中我們只要像下面這種方式呼叫就行了。
@RequestMapping(value = "/file/testExcelDownload")
public void testExcelDownload(HttpServletRequest request,HttpServletResponse response){
//以下資訊從資料庫中查出
List<ExcelInfo> excelInfos = new ArrayList<>();
ExcelInfo info1 = new ExcelInfo();
ExcelInfo info2 = new ExcelInfo();
excelInfos.add(info1);
excelInfos.add(info2);
info1.setIssuerName("name1");
info1.setRiskLevel("level1");
info2.setIssuerName("name1");
info2.setRiskLevel("level1");
try {
String fileName = "excelInfo";
String sheetName = "sheet1";
ExcelUtil.writeExcel(response, excelInfos, fileName, sheetName, ExcelInfo.class);
} catch(Exception e){
log.error("模板下載失敗",e);
}
}
在匯出Excel的部分,easyExcel還提供了自定義樣式,插入表格,插入圖片等其他功能,還有一個比較有意思的功能就是Excel模板填充的功能。詳細的功能資訊參考官方文件