天天看點

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

作者:樓下小黑哥

前言

博文位址:studyidea.cn/easyexcel

最近讀者小 H 給小黑哥發來私信:

小黑哥,最近我在負責公司報表平台開發,需要導出報表到 excel 中。每次使用 POI 開發,都要寫長長的一坨代碼,好幾次因為沒加入判空判斷,導緻生成失敗。想跟你請教下有沒有更加高效一點讀寫 excel 方法?

使用過 poi 的開發同學可能都有此體會,每次都要寫一坨代碼,最後的代碼如下面一樣:

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

這樣的代碼是不是又臭又長?當字段數量多的時候,一不小心還容易寫錯。小黑哥還記得當初使用 poi 導出一個二十多字段的 excel,不斷複制粘貼,行号一不小心就寫錯了,那叫個一個心酸。

今天小黑哥就來推薦一個阿裡開源的項目『EasyExcel』,帶大家徹底告别上面又長又臭的代碼,徹底解決這個問題。

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

EasyExcel

EasyExcel 是一個阿裡出品的開源項目 ,看名字就能看出這個項目是為了讓你更加簡單的操作 Excel。另外 EasyExcel 還解決了poi 記憶體溢出問題,修複了一些并發情況下一些 bug。

github 位址:github.com/alibaba/eas…

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

截止小黑哥寫文章時,已有 13.6k star 資料,可見這個項目還是深受大家歡迎。

廢話不多說,我們直接進入源碼實戰環節。

首先我們需要引入 EasyExcel pom 依賴:

com.alibaba    easyexcel    2.1.6
           

這裡建議大家使用 2.0 以上的正式版本,不要再使用 1.0 的老版本,兩者使用 API 差别很大。另外 beta 版本可能會存在某些 bug,大家謹慎使用。

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

普通方式

一行代碼生成 Excel

// 寫法1String fileName = "temp/" + "test" + System.currentTimeMillis() + ".xlsx";EasyExcel.write(fileName)        .head(head())// 設定表頭        .sheet("模闆")// 設定 sheet 的名字        // 自适應列寬        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())        .doWrite(dataList());// 寫入資料
           

生成 excel 代碼特别簡單,這裡使用鍊式語句,一行代碼直接搞定生成代碼。代碼中再也不用我們指定行号,列号了。

上面代碼中使用自适應列寬的政策。

下面我們來看下表頭與标題如何生成。

建立表頭

/** * 建立表頭,可以建立複雜的表頭 * * @return */private static List> head() {    List> list = new ArrayList>();    // 第一清單頭    List head0 = new ArrayList();    head0.add("第一列");    head0.add("第一列第二行");    // 第二清單頭    List head1 = new ArrayList();    head1.add("第一列");    head1.add("第二列第二行");    // 第三列    List head2 = new ArrayList();    head2.add("第一列");    head2.add("第三列第二行");    list.add(head0);    list.add(head1);    list.add(head2);    return list;}
           

上面每個 List 代表一列的資料,集合内每個資料将會順序寫入這列每一行。如果每一列的相同行數的内容相同,将會自動合并單元格。通過這個規則,我們建立複雜的表頭。

最終建立表頭如下:

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

寫入表體資料

private static List dataList() {    List> list = new ArrayList>();    for (int i = 0; i < 10; i++) {        List data = new ArrayList();        data.add("點贊+" + i);        // date 将會安裝 yyyy-MM-dd HH:mm:ss 格式化        data.add(new Date());        data.add(0.56);        list.add(data);    }    return list;}
           

表體資料然後也是使用 List>,但是與表頭規則不一樣。

每個 List 代表一行的資料,資料将會按照順序寫入每一列中。

集合中資料 EasyExcel 将會按照預設的格式化轉換輸出,比如 date 類型資料就将會按照 yyyy-MM-dd HH:mm:ss 格式化。

如果需要轉化成其他格式,建議直接将資料格式化成字元串加入 List,不要通過 EasyExcel 轉換。

最終效果如下:

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

看完這個是不是想立刻體驗一下?等等,上面使用方式還是有點繁瑣,使用 EasyExcel 還可以更快。我們可以使用注解方式,無需手動設定表頭與表體。

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

注解方式

注解方式生成 Excel 代碼如下:

String fileName = "temp/annotateWrite" + System.currentTimeMillis() + ".xlsx";// 這裡 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字為模闆 然後檔案流會自動關閉// 如果這裡想使用03 則 傳入excelType參數即可EasyExcel        .write(fileName, DemoData.class)        .sheet("注解方式")        .registerWriteHandler(createTableStyle())// Excel 表格樣式        .doWrite(data());
           

這裡代碼與上面大體一緻,隻不過這裡需要在 write 方法傳入 DemoData 資料類型。EasyExcel 會根據 DemoData 類型自動生成表頭。

下面我們來看下 DemoData這個類到底内部到底是啥樣?

@ContentRowHeight(30)// 表體行高@HeadRowHeight(20)// 表頭行高@ColumnWidth(35)// 列寬@Datapublic class DemoData {    /**     * 單獨設定該列寬度     */    @ColumnWidth(50)    @ExcelProperty("字元串标題")    private String string;    /**     * 年月日時分秒格式     */    @DateTimeFormat("yyyy年MM月dd日HH時mm分ss秒")    @ExcelProperty(value = "日期标題")    private Date date;    /**     * 格式化百分比     */    @NumberFormat("#.##%")    @ExcelProperty("數字标題")    private Double doubleData;    @ExcelProperty(value = "枚舉類",converter = DemoEnumConvert.class)    private DemoEnum demoEnum;    /**     * 忽略這個字段     */    @ExcelIgnore    private String ignore;}
           

DemoData 就是一個普通的 POJO 類,上面使用 ExayExcel 相關注解,ExayExcel 将會通過反射讀取字段類型以及相關注解,然後直接生成 Excel 。

ExayExcel 提供相關注解類,直接定義 Excel 的資料模型:

  • @ExcelProperty 指定目前字段對應excel中的那一列,内部 value 屬性指定表頭列的名稱
  • @ExcelIgnore 預設所有字段都會和excel去比對,加了這個注解會忽略該字段
  • @ContentRowHeight 指定表體行高
  • @HeadRowHeight 指定表頭行高
  • @ColumnWidth 指定列的寬度

另外 ExayExcel 還提供幾個注解,自定義日期以及數字的格式化轉化。

  • @DateTimeFormat
  • @NumberFormat

另外我們可以自定義格式化轉換方案,需要實作 Converter 類相關方法即可。

public class DemoEnumConvert implements Converter {    @Override    public Class supportJavaTypeKey() {        return DemoEnum.class;    }    @Override    public CellDataTypeEnum supportExcelTypeKey() {        return CellDataTypeEnum.STRING;    }    /**     * excel 轉化為 java 類型,excel 讀時将會被調用     * @param cellData     * @param contentProperty     * @param globalConfiguration     * @return     * @throws Exception     */    @Override    public DemoEnum convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {        return null;    }    /**     * java 類型轉 excel 類型,excel 寫時将會被調用     * @param value     * @param contentProperty     * @param globalConfiguration     * @return     * @throws Exception     */    @Override    public CellData convertToExcelData(DemoEnum value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {        return new CellData(value.getDesc());    }}
           

最後我們還需要在 @ExcelProperty 注解上使用 converter 指定自定義格式轉換方案。

使用方式如下:

@ExcelProperty(value = "枚舉類",converter = DemoEnumConvert.class)private DemoEnum demoEnum;
           

最後我們運作一下,看下 Excel 實際效果如何:

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

怎麼樣,效果還是可以吧。

easyexcel生成excel_我去,還在這樣讀寫 excel 這也太低效了吧!

對了,預設的樣式表格樣式可不是這樣,這個效果是因為我們在 registerWriteHandler 方法中設定自定義的樣式,具體代碼如下:

/*** * 設定 excel 的樣式 * @return */private static WriteHandler createTableStyle() {    // 頭的政策    WriteCellStyle headWriteCellStyle = new WriteCellStyle();    // 背景設定為紅色    headWriteCellStyle.setFillForegroundColor(IndexedColors.PINK.getIndex());    // 設定字型    WriteFont headWriteFont = new WriteFont();    headWriteFont.setFontHeightInPoints((short) 20);    headWriteCellStyle.setWriteFont(headWriteFont);    // 内容的政策    WriteCellStyle contentWriteCellStyle = new WriteCellStyle();    // 這裡需要指定 FillPatternType 為FillPatternType.SOLID_FOREGROUND 不然無法顯示背景顔色.頭預設了 FillPatternType是以可以不指定    contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);    // 背景綠色    contentWriteCellStyle.setFillForegroundColor(IndexedColors.LEMON_CHIFFON.getIndex());    WriteFont contentWriteFont = new WriteFont();    // 字型大小    contentWriteFont.setFontHeightInPoints((short) 20);    contentWriteCellStyle.setWriteFont(contentWriteFont);    // 設定邊框的樣式    contentWriteCellStyle.setBorderBottom(BorderStyle.DASHED);    contentWriteCellStyle.setBorderLeft(BorderStyle.DASHED);    contentWriteCellStyle.setBorderRight(BorderStyle.DASHED);    contentWriteCellStyle.setBorderTop(BorderStyle.DASHED);    // 這個政策是 頭是頭的樣式 内容是内容的樣式 其他的政策可以自己實作    HorizontalCellStyleStrategy horizontalCellStyleStrategy =            new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);    return horizontalCellStyleStrategy;}
           

使用注意點

poi 沖突問題

理論上目前 easyexcel相容支援 poi 的3.17,4.0.1,4.1.0所有較新版本,但是如果項目之前使用較老版本的 poi,由于 poi 内部代碼調整,某些類已被删除,這樣直接運作時很大可能會抛出以下異常:

  • NoSuchMethodException
  • ClassNotFoundException
  • NoClassDefFoundError

是以使用過程中一定要注意統一項目中的 poi 的版本。

非注解方式自定義行高列寬

非注解方式自定義行高以及列寬比較麻煩,暫時沒有找到直接設定的入口。查了一遍 github 相關 issue,開發人員回複需要實作 WriteHandler 接口,自定義表格樣式。

總結

本文主要給各位小夥伴們安利 EasyExcel 強大的功能,介紹 EasyExcel 兩種生成 excel 方式,以及示範相關的示例代碼。 EasyExcel 除了寫之外,當然還支援快讀讀取 Excel 的功能,這裡就不再詳細介紹。Github 上相關文檔例子非常豐富,大家可以自行參考。

Github 文檔位址:alibaba-easyexcel.github.io/index.html

繼續閱讀