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

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

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

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

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

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

EasyExcel

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

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

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

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

<code><dependency>
    <groupid>com.alibaba/<groupid>
    <artifactid>easyexcel/<artifactid>
    <version>2.1.6/<version>
/<dependency>/<code>

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

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

普通方式

一行代碼生成 Excel

<code>// 寫法1
String fileName = "temp/" + "test" + System.currentTimeMillis() + ".xlsx";
EasyExcel.write(fileName)
        .head(head())// 設置表頭
        .sheet("模板")// 設置 sheet 的名字
        // 自適應列寬
        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
        .doWrite(dataList());// 寫入數據
/<code>

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

上面代碼中使用自適應列寬的策略。

下面我們來看下錶頭與標題如何生成。

創建表頭

<code>/**
 * 創建表頭,可以創建複雜的表頭
 *
 * @return
 */
private static List<list>> head() {
    List<list>> list = new ArrayList<list>>();
    // 第一列表頭
    List<string> head0 = new ArrayList<string>();
    head0.add("第一列");

    head0.add("第一列第二行");
    // 第二列表頭
    List<string> head1 = new ArrayList<string>();
    head1.add("第一列");
    head1.add("第二列第二行");
    // 第三列
    List<string> head2 = new ArrayList<string>();
    head2.add("第一列");
    head2.add("第三列第二行");
    list.add(head0);
    list.add(head1);
    list.add(head2);
    return list;
}/<string>/<string>/<string>/<string>/<string>/<string>/<list>/<list>/<list>/<code>

上面每個 List<string> 代表一列的數據,集合內每個數據將會順序寫入這列每一行。如果每一列的相同行數的內容相同,將會自動合併單元格。通過這個規則,我們創建複雜的表頭。/<string>

最終創建表頭如下:

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

寫入表體數據

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

表體數據然後也是使用 List<list>>,但是與表頭規則不一樣。/<list>

每個 List<object> 代表一行的數據,數據將會按照順序寫入每一列中。/<object>

集合中數據 EasyExcel 將會按照默認的格式化轉換輸出,比如 date 類型數據就將會按照 yyyy-MM-dd HH:mm:ss 格式化。

如果需要轉化成其他格式,建議直接將數據格式化成字符串加入 List,不要通過EasyExcel 轉換。

最終效果如下:

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

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

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

註解方式

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

<code>String fileName = "temp/annotateWrite" + System.currentTimeMillis() + ".xlsx";
// 這裡 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字為模板 然後文件流會自動關閉

// 如果這裡想使用03 則 傳入excelType參數即可
EasyExcel
        .write(fileName, DemoData.class)
        .sheet("註解方式")
        .registerWriteHandler(createTableStyle())// Excel 表格樣式
        .doWrite(data());/<code>

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

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

<code>@ContentRowHeight(30)// 表體行高
@HeadRowHeight(20)// 表頭行高
@ColumnWidth(35)// 列寬
@Data
public 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;
}/<code>

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

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

  • @ExcelProperty 指定當前字段對應excel中的那一列,內部 value 屬性指定表頭列的名稱
  • @ExcelIgnore 默認所有字段都會和excel去匹配,加了這個註解會忽略該字段
  • @ContentRowHeight 指定表體行高
  • @HeadRowHeight 指定表頭行高
  • @ColumnWidth 指定列的寬度

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

  • @DateTimeFormat
  • @NumberFormat

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

<code>public class DemoEnumConvert implements Converter<demoenum> {
    @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());
    }
}/<demoenum>/<code>

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

使用方式如下:

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

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

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

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

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

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

<code>/***
 * 設置 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;
}/<code>

使用注意點

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 上相關文檔例子非常豐富,大家可以自行參考。


分享到:


相關文章: