目錄git
此文章以獨家受權一下公衆號 :
【新華先後端開發】
【腳本之家】github
【快速、簡單避免OOM的java處理Excel工具】 github上關於項目的介紹數據庫
簡介
poi使用userModel模式,這個模式的特色就是上手很容易。代碼寫起來很複雜。並且公用的地方不多。致使每次讀寫excel都須要從新編寫。
EasyExcel使用SAX模式使得easyexcel能夠節省內存。並且easyexcel解決了內存泄漏問題。若是想了解SAX模式開發那成本須要3~5天學習。apache
導出excel經常使用的幾種方法
經過Java讀寫excel大概有如下幾種:
poi、csv、jxl、jxls 、easyPoi 、easyExcel
根據性能他們的排序:
jxl 、 easyexcel 、 csv 、 poi 、 easypoi 、 jxlswindows
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的功能實現自定義功能api
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併發寫入錯誤