EasyExcel使用總結(一):寫Excel

說明

最近有很多數據要處理,需要導出Excel表格。在使用POI時發現非常耗內存,在GitHub上發現阿里開源的Easy Excel項目,基於java的讀寫Excel,十分省內存。本篇博文主要是總結記錄了使用EasyExcel進行寫Excel的方法。

正文

引入依賴

在pom.xml文件引入easyexcel依賴,我使用的是2.1.4版本,目前最新是2.1.6。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.4</version>
</dependency>

簡單寫Excel

這是最基本的使用方式。通過在pojo類的屬性上使用@ExcelProperty(“列名”)註解來指定該屬性所屬列名,通過@ExcelIgnore註解來忽略該屬性。不同與之前的1.x版本,數據的pojo類不需要再繼承BaseModel類。

官方指導文件中,提供了兩種簡單寫的方法:

  1. 直接通過EasyExcel調用write方法
EasyExcel.write(fileName, clazz).sheet(sheetName).doWrite(dataList);
  1. 分別創建ExcelWriter和WriteSheet對象,調用excelWriter的write方法,並且在寫完後要手動調用excelWriter的finish方法關閉流。
ExcelWriter excelWriter = EasyExcel.write(fileName, claxx).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
excelWriter.write(dataList, writeSheet);
excelWriter.finish();

在使用中,封裝了一個Util類,通過createExcel進行簡單的寫:

public static <T> void createExcel(String filePath, List<T> dataList, String sheetName, Class<T> clazz) throws Exception {

    try {
        EasyExcel.write(filePath, clazz).sheet(sheetName).doWrite(dataList);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

動態生成複雜頭寫Excel

在導出數據要求中,需要針對每天的數據進行統計寫入表格,而日期範圍是不確定的,這就需要動態生成表頭,並且在要求中,數據統計還分多個維度。所以,寫excel的同時要先生成相對應的複雜頭。

在官方文檔中,有示例介紹如何實現負責頭的寫入。在pojo類中,對每個屬性使用了@ExcelProperty({“主標題”, “子標題”})註解指定了屬性對應列的複雜頭名稱。

示例:

public class ComplexHeadData {
    @ExcelProperty({"主標題", "字符串標題"})
    private String string;
    @ExcelProperty({"主標題", "日期標題"})
    private Date date;
    @ExcelProperty({"主標題", "數字標題"})
    private Double doubleData;
    
    ....省略set get方法
}

同樣通過在EasyExcel.write方法進行寫入。

我們知道了固定複雜頭的寫入方式,那麼動態複雜頭的寫入,第一步就是要創建複雜頭的List<List>。

如果要想得到與上示代碼同樣的複雜頭結構,則需要:

public List<List<String>> getHead() {
        List<List<String>> headList = new ArrayList<>();
        List<String> head1 = new ArrayList<>();
        head1.add("主標題");
        head1.add("字符串標題");
        headList.add(head1);

        List<String> head2 = new ArrayList<>();
        head2.add("主標題");
        head2.add("日期標題");
        headList.add(head2);

        List<String> head3 = new ArrayList<>();
        head3.add("主標題");
        head3.add("數字標題");
        headList.add(head3);

        List<String> head4 = new ArrayList<>();
        head4.add("主標題II");
        headList.add(head4);
        return headList;
}

在構造數據時,也應該是List<List>,每個List表示表格中的一行數據。注意,list中數據中的順序要和生成頭中列名的順序保持一致。

public List<List<String>> getdata() {
    List<List<String>> dataList = new ArrayList<>();
    List<String> list1 = new ArrayList<>();
    list1.add("1");
    list1.add("2");
    list1.add("3");
    list1.add("4");
    dataList.add(list1);
    List<String> list2 = new ArrayList<>();
    list2.add("5");
    list2.add("6");
    list2.add("7");
    list2.add("8");
    dataList.add(list2);
    return dataList;
}

導出表格示例:
在這裏插入圖片描述

同樣,在Util類中封裝了creatExcelDynamicHead方法。

public static <T> void createExcelDynamicHead(String filePath, List<T> dataList, List<List<String>> head, String sheetName) throws Exception {
    try {
        EasyExcel.write(filePath).head(head).sheet(sheetName).doWrite(dataList);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

重複多個sheet寫Excel

在數據要求中,需要一個Excel中包含多個sheet,這就需要一個excel多次寫入。在官方文檔中,對此重複多次寫入(寫到單個或者多個Sheet)有詳細的介紹。總共介紹了三種方法,每種實現不同的功能:

  1. 數據分批寫到同一個sheet
// 這裏 需要指定寫用哪個class去寫
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 這裏注意 如果同一個sheet只要創建一次
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// 去調用寫入,這裏我調用了五次,實際使用時根據數據庫分頁的總的頁數來
for (int i = 0; i < 5; i++) {
  // 分頁去數據庫查詢數據 這裏可以去數據庫查詢每一頁的數據
  List<DemoData> data = data();
  excelWriter.write(data, writeSheet);
}
// 千萬別忘記finish 會幫忙關閉流
excelWriter.finish();
  1. 寫到多個不同的sheet
// 方法2 如果寫到不同的sheet 同一個對象
fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
// 這裏 指定文件
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 去調用寫入,這裏我調用了五次,實際使用時根據數據庫分頁的總的頁數來。這裏最終會寫到5個sheet裏面
for (int i = 0; i < 5; i++) {
  // 每次都要創建writeSheet 這裏注意必須指定sheetNo
  writeSheet = EasyExcel.writerSheet(i, "模板").build();
  // 分頁去數據庫查詢數據 這裏可以去數據庫查詢每一頁的數據
  List<DemoData> data = data();
  excelWriter.write(data, writeSheet);
}
// 千萬別忘記finish 會幫忙關閉流
excelWriter.finish();
  1. 寫多個sheet,數據不同
    與第二種方法類似,但不同的是,在每次新建WriteSheet對象時,需要指定不同的數據類對象。
for (int i = 0; i < 5; i++) {
  // 每次都要創建writeSheet 這裏注意必須指定sheetNo。這裏注意DemoData.class 可以每次都變,我這裏爲了方便 所以用的同一個class 實際上可以一直變
  writeSheet = EasyExcel.writerSheet(i, "模板").head(DemoData.class).build();
  .....
}

在Util類中,封裝了createExcelManySheets方法,該方法是對第二種使用相同的數據寫入多個sheet方法的封裝。datMap的key爲不同sheet的名稱。

public static <T> void createExcelManySheets(String filePath, Map<String, List<T>> dataMap, Class<T> clazz) throws Exception {
    ExcelWriter excelWriter = EasyExcel.write(filePath, clazz).build();
    try {
        int index = 0;
        for (Map.Entry<String, List<T>> entry : dataMap.entrySet()) {
            String sheetName = entry.getKey();
            List<T> data = entry.getValue();
            WriteSheet sheet = EasyExcel.writerSheet(index++, sheetName).build();
            excelWriter.write(data, sheet);
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        if (excelWriter != null) {
            excelWriter.finish();
        }
    }
}

web中的寫入下載

通過該方法對生成的excel進行下載。在官方文檔中也有詳細的示例:
將數據寫入到HttpServletResponse的輸出流outputstream中。

@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
    // 這裏注意 有同學反應使用swagger 會導致各種問題,請直接用瀏覽器或者用postman
    response.setContentType("application/vnd.ms-excel");
    response.setCharacterEncoding("utf-8");
    // 這裏URLEncoder.encode可以防止中文亂碼 當然和easyexcel沒有關係
    String fileName = URLEncoder.encode("測試", "UTF-8");
    response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
    EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}

可以發現,與以上調用EasyExcel.write方法進行寫入不同的是將filename替換爲了response的輸出流。

EasyExcelUtil

public class EasyExcelUtil {

    public static <T> void createExcel(String filePath, List<T> dataList, String sheetName, Class<T> clazz) throws Exception {

        try {
            EasyExcel.write(filePath, clazz).sheet(sheetName).doWrite(dataList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> void createExcelDynamicHead(String filePath, List<T> dataList, List<List<String>> head, String sheetName) throws Exception {
        try {
            EasyExcel.write(filePath).head(head).sheet(sheetName).doWrite(dataList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> void createExcelManySheets(String filePath, Map<String, List<T>> dataMap, Class<T> clazz) throws Exception {
        ExcelWriter excelWriter = EasyExcel.write(filePath, clazz).build();
        try {
            int index = 0;
            for (Map.Entry<String, List<T>> entry : dataMap.entrySet()) {
                String sheetName = entry.getKey();
                List<T> data = entry.getValue();
                WriteSheet sheet = EasyExcel.writerSheet(index++, sheetName).build();
                excelWriter.write(data, sheet);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    public static <T> void createExcelWeb(OutputStream outputStream, List<T> dataList, String sheetName, Class<T> clazz) throws Exception{
        try {
            EasyExcel.write(outputStream, clazz).sheet(sheetName).doWrite(dataList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> void createExcelDynamicHeadWeb(OutputStream outputStream, List<T> dataList, List<List<String>> head, String sheetName) throws Exception {
        try {
            EasyExcel.write(outputStream).head(head).sheet(sheetName).doWrite(dataList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> void createExcelManySheetsWeb(OutputStream outputStream, Map<String, List<T>> dataMap, Class<T> clazz) throws Exception {
        ExcelWriter excelWriter = EasyExcel.write(outputStream, clazz).build();
        try {
            int index = 0;
            for (Map.Entry<String, List<T>> entry : dataMap.entrySet()) {
                String sheetName = entry.getKey();
                List<T> data = entry.getValue();
                WriteSheet sheet = EasyExcel.writerSheet(index++, sheetName).build();
                excelWriter.write(data, sheet);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }
}

更多的使用方式請查閱官方文檔。


參考資料:
https://alibaba-easyexcel.github.io/index.html

https://www.cnblogs.com/oukele/p/11444234.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章