此文章以獨家授權一下公眾號 :
【新華前后端開發】
【腳本之家】
目錄
【快速、簡單避免OOM的java處理Excel工具】 github上關於項目的介紹
簡介
poi使用userModel模式,這個模式的特點就是上手很容易。代碼寫起來很復雜。而且公用的地方很少。導致每次讀寫excel都需要重新編寫。
EasyExcel使用SAX模式使得easyexcel可以節省內存。而且easyexcel解決了內存泄漏問題。如果想了解SAX模式開發那成本需要3~5天學習。
導出excel常用的幾種方法
通過Java讀寫excel大概有以下幾種:
poi、csv、jxl、jxls 、easyPoi 、easyExcel
根據性能他們的排序:
jxl 、 easyexcel 、 csv 、 poi 、 easypoi 、 jxls
POI
- POI是apache的一個開源項目。他是基於微軟提供對Java程序的一個API。通過它我們能控制excel的單元格的內容及樣式的讀取寫入。
- 但是正是因為他的細節之處導致我們開發起來代碼很多。而且無法抽離。
CSV
- csv實際上就是一個文本,只不過通過office能夠打開的一中文本。真正的excel對象如果通過普通的文本工具打開你會發現實際是一個二進制文件。因為csv是一個文本,所以在讀寫他的時候實際就是文本的讀取。沒有POI的workbook、sheet、row 、cell 之說。所以讀寫的效率還是很快的。
- 但是因為是文本所以我們無法控制單元格的樣式。比如樣式、加下拉框、合並單元格之類的。
jxl
- jxl實際和POI差不多。兩者的理念一樣,都是通過表格對象--》單元頁--》行--》列--》單元格的邏輯去操作讀寫的。基本上常用的功能都是提供方法的。不同的是方法的傳參順序的不同。兩者在性能上的比較jxl性能更佳。
- 因為POI的風靡。jxl並不是很熟知。筆者也是整理的時候發現jxl。暫時不知道jxl的缺點。非要指出缺點那么就是他和poi的邏輯不一樣。編寫起來有點別扭。
jxls
- 這里需要值得注意的是jxls和jxl一點關系都沒有。兩者的使用方法的邏輯也是天差萬別的。jxls更佳側重的是excel本身的模板的編寫。jxls是通過模板在注入數據進行渲染的一個框架。他的最大的有點就是代碼量很少。基本上我們只需要准備好數據就可以進行導出了。
- 因為是基於模板的。所以jxls實現導出的很簡單。但是實現讀取數據這里就很不好辦了。這里筆者暫時不知道如何實現。 這個問題就留給聰明的讀者吧!!!
easypoi
- easypoi和easyexcel很相似。兩者都是通過注解的方式實現excel表頭與實體對象的一種映射。一個@Excel 另一個是@ExcelProperty . 相對easyexcel,easypoi功能就相對單一點。
- 兩者都可以在自身的功能不足的情況下,通過POI的功能實現自定義功能
easyexcel
- easyexcel是重點對象。他基於注解的方式將以前POI的復雜的代碼進模塊抽離。我們基本上的需求只需要在excelproperty注解中就可以解決。
- easyexcel最大的特點就是解決了內存泄漏的問題。以上幾種poi在導出excel的時候都受到了數據的影響.而且性能上還不是很好。easyexcel是POI系列產品的最佳之選
快速入門
easyexcel名字非常的符合他的個性。他是真的很easy.下面我們來實現一個導出學生信息的代碼
String fileName = EasyExcelTools.class.getResource("/").getPath() + "student" + System.currentTimeMillis() + ".xlsx";
ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(fileName, Student.class);
//excelWriterBuilder.registerConverter(new SexConverter()).registerWriteHandler(new AgeRowHandler()).registerWriteHandler(new SexCellWriteHandler());
ExcelWriter excelWriter = excelWriterBuilder.build();
WriteSheet writeSheet = EasyExcel.writerSheet("中化安元").build();
try {
excelWriter.write(ts, writeSheet);
} catch (Exception e) {
e.printStackTrace();
}finally {
excelWriter.finish();
}
代碼解讀
- Student是導出需要的實體。里面配置了表格的一些基本信息
- ts 是Student數據的一個集合
- fileName 是導出的文件地址
student
public class Student {
/**
* 學生索引id
*/
@ExcelProperty(value = {HeadConstant.FIRSTNAME,HeadConstant.SECONDNAME,"學號"})
private String id;
/**
* 姓名
*/
@ExcelProperty(value = {HeadConstant.FIRSTNAME,HeadConstant.SECONDNAME,"姓名"})
private String userName;
/**
* 用戶昵稱
*/
@ExcelProperty(value = {HeadConstant.FIRSTNAME,HeadConstant.SECONDNAME,"昵稱"})
@ExcelIgnore
private String userNick;
/**
* 年齡
*/
@ExcelProperty(value = {HeadConstant.FIRSTNAME,HeadConstant.SECONDNAME,"年齡"})
private Integer age;
/**
* 性別 true : 男 ; false : 女
*/
@ExcelProperty(value = {HeadConstant.FIRSTNAME,HeadConstant.SECONDNAME,"性別"})
private boolean sex;
/**
* 生日
*/
@ExcelProperty(value = {HeadConstant.FIRSTNAME,HeadConstant.SECONDNAME,"生日"})
private Date birth;
/**
* 身高
*/
@ExcelProperty(value = {HeadConstant.FIRSTNAME,HeadConstant.SECONDNAME,"身高"})
private Double height;
}
總結
- 通過easyexcel導出我們只需要准備好數據,然后兩行代碼導出。
常用API
- EasyExcel 入口類,用於構建開始各種操作
- ExcelReaderBuilder ExcelWriterBuilder 構建出一個 ReadWorkbook WriteWorkbook,可以理解成一個excel對象,一個excel只要構建一個
- ExcelReaderSheetBuilder ExcelWriterSheetBuilder 構建出一個 ReadSheet WriteSheet對象,可以理解成excel里面的一頁,每一頁都要構建一個
- ReadListener 在每一行讀取完畢后都會調用ReadListener來處理數據
- WriteHandler 在每一個操作包括創建單元格、創建表格等都會調用WriteHandler來處理數據
- 所有配置都是繼承的,Workbook的配置會被Sheet繼承,所以在用EasyExcel設置參數的時候,在EasyExcel...sheet()方法之前作用域是整個sheet,之后針對單個sheet
單元格樣式
- 因為被封裝了一層。如果easyexcel滿足不了我們的話,我們可以通過workbook去具體操作單元格內容和樣式。這種方法是萬不得已在使用。就比如我們想改變單元格樣式。easyexcel提供了開發接口CellWriteHandler。我們只需要實現這個接口並重寫他的
beforeCellCreate,afterCellCreate,afterCellDispose.其中afterCellDispose方法是在單元格創建后銷毀前的一個時機。這時候我們可以改變單元格內容。easyExcel提供了四種時間捕捉接口
CellWriteHandler
WorkbookWriteHandler
SheetWriteHandler
RowWriteHandler
合並單元格
- 在POI中我們實現合並單元格我們需要指定合並的范圍。但是在easyexcel中我們只需要在ExcelProperty注解中加入表頭的時候在對應位置加入相同的內容就會自動的合並單元格。


數據樣式
- 數據樣式使我們Java開發中經常遇到的。比如說學生信息中的性別我們粗在數據庫中大部分情況都是通過0、1來控制的。但是我們導出的時候肯定是不能直接展示01的。這個時候我們就需要數據樣式了。說的在明白點就是數據格式轉換。在easyexcel中提供了Converter接口。
convertToJavaData: excel數據轉換成Java對象
convertToExcelData: Java對象轉換成excel數據
多sheet設置
- 多sheet頁實際上就是創建多個sheet。每個sheet有不同的編號。剩下的操作都是一樣的。
單元格添加超鏈接
- 通過CellWriteHandler實現在
afterCellDispose方法中實現
CreationHelper createHelper = writeSheetHolder.getSheet().getWorkbook().getCreationHelper();
Hyperlink hyperlink = createHelper.createHyperlink(HyperlinkType.URL);
hyperlink.setAddress("https://gitee.com/zxhTom");
cell.setHyperlink(hyperlink);
依賴
<dependency>
<groupId>net.sourceforge.javacsv</groupId>
<artifactId>javacsv</artifactId>
<version>2.0</version>
</dependency>
使用版本
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.0-beta4</version>
</dependency>
中流砥柱
- ExcelProperty: 實體屬性配置注解
- BaseRowModel : 編寫實體繼承的實體類
- WriteHandler : 用來控制單元格輸出,包括樣式和數據格式設置
- ExcelWriter : 用於導出excel
notes
系統時間
1900 windowing 1900年日期系統
1904 windowing 1904年日期系統
Excel for windows 使用1900
Excel2008 for mac 和之前版本 1904
excel 2016 for mac ; excel for mac 2011 1900
讀寫數據格式內置轉換器
- BigDecimalBooleanConverter()
- BigDecimalNumberConverter();
- BigDecimalStringConverter();
- BooleanBooleanConverter();
- BooleanNumberConverter();
- BooleanStringConverter();
- ByteBooleanConverter();
- ByteNumberConverter();
- ByteStringConverter();
- DateNumberConverter();
- DateStringConverter();
- DoubleBooleanConverter();
- DoubleNumberConverter();
- DoubleStringConverter();
- FloatBooleanConverter();
- FloatNumberConverter();
- FloatStringConverter();
- IntegerBooleanConverter();
- IntegerNumberConverter();
- IntegerStringConverter();
- LongBooleanConverter();
- LongNumberConverter();
- LongStringConverter();
- ShortBooleanConverter();
- ShortNumberConverter(Converter 數據轉換接口);
- ShortStringConverter();
- StringBooleanConverter();
- StringNumberConverter();
- StringStringConverter();
- StringErrorConverter();
ModelBuildEventListener
- ModelBuildEventListener 默認的也是第一個數據監聽器,主要功能就是將讀取到的當前行數據轉換成實體或者map
write
- FileUtils.createPoiFilesDirectory();
在初始化時創建臨時緩存目錄以避免POI並發寫入錯誤
讀寫流程分析
read

write

# 加入戰隊
微信公眾號

