一文搞定POI,再也不怕excel導入導出了 一文搞定POI,再也不怕excel導入導出了

一文搞定POI,再也不怕excel導入導出了

寫在前面

在Java日常開發過程中,實現Excel文件的導入導出功能是一項常見的需求。

通過使用相關的Java庫,如Apache POI、EasyPoi或EasyExcel,可以輕鬆地實現Excel文件的讀寫操作。

而這篇文章將介紹如何在Java中使用Apache POI、EasyPoi 和EasyExcel庫來進行Excel文件的導入和導出操作,幫助您快速掌握這一實用的技能。

一、使用場景

下面是excel導入導出的幾個最常用的使用場景。

企業管理系統:企業管理系統通常需要導入員工信息、客戶信息、銷售數據等大量數據到系統中,以及導出報表、數據分析結果等信息。

學校教務系統:學校教務系統可能需要導入學生信息、課程表、成績等數據,以及導出學生成績單、教師工資表等信息。

電子商務平臺:電子商務平臺需要導入商品信息、訂單數據等內容,以及導出銷售報表、庫存清單等信息,方便管理和分析。

④ 人力資源管理系統:人力資源管理系統需要導入員工檔案、薪資信息等數據,以及導出薪資條、考勤報表等信息,方便人力資源管理和工資結算。

⑤ 醫院信息系統:醫院信息系統可能需要導入患者信息、醫療記錄等數據,以及導出醫療報告、統計分析等信息,方便醫護人員進行醫療服務和管理。

以上僅是一些常見的使用場景,實際上各種系統中的Excel導入導出功能可以根據具體需求進行定製和擴展

二、三個庫簡介

1、Apache POI

Apache POI是一個流行的Java庫,用於處理Microsoft Office格式文件,包括Excel、Word和PowerPoint。它提供了豐富的API,可以創建、讀取和修改各種類型的Office文檔。

官網https://poi.apache.org/

優點:

  1. 功能強大:支持處理複雜的Excel文件,包括單元格、樣式、圖表等內容。

  2. 穩定性高:作爲一個成熟的開源項目,得到廣泛支持和持續維護。

  3. 靈活性:可以滿足各種定製化需求,可以實現複雜的Excel處理功能。

缺點:

  1. 學習曲線較陡:對於初學者來說,學習成本可能較高。
  2. 性能相對較低:在處理大量數據時,性能可能受到一定影響。

2、EasyPoi

easypoi功能如同名字easy,主打的功能就是容易,讓一個沒見接觸過poi的人員 就可以方便的寫出Excel導出,Excel模板導出,Excel導入,Word模板導出,通過簡單的註解和模板 語言(熟悉的表達式語法),完成以前複雜的寫法

官網: https://gitee.com/lemur/easypoi

優點:

  1. 簡單易用:EasyPoi 提供了簡潔的 API 接口,使得 Excel 操作更加便捷。
  2. 功能豐富:支持 Excel 文件的導入導出、模板導出、校驗等多種功能。
  3. 易於擴展:EasyPoi 基於 Apache POI 和 JexcelApi,可以方便地擴展和定製功能。
  4. 文檔齊全:EasyPoi 提供了詳細的文檔和示例,便於開發人員學習和使用。

缺點:

  1. 功能有限:相比於 Apache POI,EasyPoi 可能在一些高級功能上有所限制。
  2. 可能存在性能問題:由於封裝層的存在,EasyPoi 在處理大量數據時可能存在一定的性能損耗。

3、EasyExcel

EasyExcel是一個阿里巴巴基於Apache POI封裝的開源框架,專注於Excel文件的讀寫操作。它提供了簡潔易用的API,簡化了Excel處理的流程。

官網https://easyexcel.opensource.alibaba.com/

優點:

  1. 簡單易用:提供了簡潔的API,使用起來非常方便。
  2. 高性能:在處理大量數據時具有較高的性能,能夠快速導入導出Excel文件。
  3. 支持註解:支持使用註解配置Excel文件的導入導出規則,簡化了開發過程。

缺點:

  1. 功能相對有限:相比Apache POI,功能相對簡單,可能無法滿足某些複雜的Excel處理需求。
  2. 定製化能力較弱:定製化能力不如Apache POI靈活。

POI和EasyExcel區別

三 、各版本Excel 區別

不同版本的Excel在功能和格式上可能會有一些差異。所以後續在處理不同版本的excel時,會有少許不同

以下是一些常見的Excel版本之間的區別

1、Excel 97-2003(.xls)

  • 最大行數爲65536行,最大列數爲256列。
  • 支持的最大單元格格式有限。
  • 不支持新的Excel特性,如條件格式、表格樣式等。
  • 文件大小限制爲2GB。

2、Excel 2007及以上版本(.xlsx)

  • 最大行數和列數均有較大提升,支持數百萬行數和16384列。
  • 支持更多的單元格格式和樣式。
  • 引入了新的功能,如條件格式、表格樣式、數據透視表等。
  • 支持更多的圖表類型和圖表樣式。
  • 文件大小限制較大,最多可達16,384 x 1,048,576個單元格。

四 、Excel 基本結構介紹

Java是面向對象的操作語言,萬物皆對象。瞭解了Excel基本結構有助於我們將Excel與Java中對象關聯起來

  • 工作簿(Workbook): Excel文件以工作簿的形式存在,一個工作簿可以包含多個工作表(Sheet)
  • 工作表(Sheet): 每個工作表由行(Row)和列(Column)組成,交叉形成單元格(Cell),用於存儲數據、文本、公式等內容
  • 單元格(Cell): Excel中的最小單位,用於存儲數據或公式。每個單元格有一個唯一的地址,例如A1、B2等
  • 行(Row)和列(Column): 行是水平方向的一組單元格,列是垂直方向的一組單元格。行用數字標識,列用字母標識
  • 公式(Formula): Excel支持使用公式進行計算和數據處理。公式以等號(=)開頭,可以引用其他單元格的數值或內容進行運算
  • 函數(Function): Excel提供了大量的內置函數,用於進行各種複雜的計算和數據處理,如SUM(求和)、AVERAGE(平均值)、VLOOKUP(垂直查找)

Excel基本結構

五、Apache POI基本操作

由於Excel分爲03版本和07版本,所以我們在使用的時候需要

注:

  • 處理03版本excel時,主要使用HSSFWorkbookHSSFSheetHSSFRowHSSFCell等對象來操作Excel文件;

  • 處理07版本及之後版本excel時,主要使用XSSFWorkbookXSSFSheetXSSFRowXSSFCell等對象來操作Excel文件

其他操作基本是一樣的,瞭解這個之後,後續操作就很簡單了~

5.1 基本寫操作

5.1.1 03版本寫excel

① 引入依賴

<!--poi 03版本依賴-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>
<!--單元測試-->
<dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.13.2</version>
     <scope>test</scope>
</dependency>
<!--日期-->
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.10</version>
</dependency>

②實例代碼

public class AppTest
{
    String filepath="E:\\xiezhrspace\\excel-demo\\fileoutput\\";
    @Test
    public void poiexcel03Test() throws  Exception{
        //1、創建一個工作簿
        Workbook workbook = new HSSFWorkbook();
        //2、創建一個工作表
        Sheet sheet = workbook.createSheet("第一個工作表");

        //3、創建一行

        //3.1 創建第一行
        Row row1 = sheet.createRow(0);
        //3.2 創建第二行
        Row row2 = sheet.createRow(1);
        //3.3 創建第三行
        Row row3 = sheet.createRow(2);

        //4 創建一個單元格
        //4.1 創建第一行第一個單元格
        Cell cell11 = row1.createCell(0);
        //4.2 創建第一行第二個單元格
        Cell cell12 = row1.createCell(1);
        //4.3 創建第二行第一個單元格
        Cell cell21 = row2.createCell(0);
        //4.4 創建第二行第二個單元格
        Cell cell22 = row2.createCell(1);
        //4.5 創建第三行第一個單元格
        Cell cell31 = row3.createCell(0);
        //4.6 創建第三行第二個單元格
        Cell cell32 = row3.createCell(1);

        // 5 設置單元格的值
        //5.1 設置第一行第一個單元格
        cell11.setCellValue("個人公衆號");
        //5.2 設置第一行第二個單元格
        cell12.setCellValue("XiezhrSpace");

        //5.3 設置第二行第一個單元格
        cell21.setCellValue("個人博客");
        //5.4 設置第二行第二個單元格
        cell22.setCellValue("www.xiezhr.cn");

        //5.5 設置第三行第一個單元格
        cell31.setCellValue("當前時間");
        //5.6 設置第三行第二個單元格
        String curdate = new DateTime().toString("yyyy-MM-dd HH:mm:ss");
        cell32.setCellValue(curdate);


        FileOutputStream fileOutputStream = new FileOutputStream(filepath + "poiexcel03.xls");
        workbook.write(fileOutputStream);
        fileOutputStream.close();
        workbook.close();

    }

}

③ excel寫出效果

image-20240303162520227

5.1.2 07版本寫excel

07 版本依賴與處理03版本的有點不一樣,代碼基本上不變

① 所需依賴

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

② 代碼修改

07版本操作與03版本操作基本沒什麼變化,我們只需將03版本代碼中new HSSFWorkbook() 修改成new XSSFWorkbook()

new FileOutputStream(filepath + "poiexcel03.xls") 修改成new FileOutputStream(filepath + "poiexcel07.xlsx") 即可

 Workbook workbook = new XSSFWorkbook();
 ...省略
 FileOutputStream fileOutputStream = new FileOutputStream(filepath + "poiexcel07.xlsx");

③ 最終效果

07版本操作

5.1.3 03版本批量寫excel

①代碼

@Test
    public void testBigDateExcelTest() throws Exception {
        Workbook workbook = new HSSFWorkbook();
        Sheet sheet = workbook.createSheet("大文件導出測試");

        long begin = System.currentTimeMillis();

        for (int rowNum = 0; rowNum <65536 ; rowNum++) {
            Row row = sheet.createRow(rowNum);
            for (int cellNum = 0; cellNum < 10 ; cellNum++) {
                Cell cell = row.createCell(cellNum);
                cell.setCellValue("("+(rowNum+1) + "," + (cellNum+1)+")");
            }

        }
        FileOutputStream fileOutputStream = new FileOutputStream(filepath + "03版本批量寫入.xls");
        workbook.write(fileOutputStream);
        fileOutputStream.close();
        workbook.close();

        long end = System.currentTimeMillis();
        System.out.println("耗時:"+(double)(end-begin)/1000+"秒");
    }

②最終效果

根據記錄時間,耗時:1.663秒

03版本批量寫入

5.1.4 07版本批量寫excel

① 代碼修改

我們只需將上面new HSSFWorkbook() 修改成new XSSFWorkbook()

new FileOutputStream(filepath + "03版本批量寫入.xls") 修改成new FileOutputStream(filepath + "07版本批量寫入.xlsx") 即可

Workbook workbook = new XSSFWorkbook();
 ...省略
FileOutputStream fileOutputStream = new FileOutputStream(filepath + "07版本批量寫入.xlsx");

② 最終效果

由於07及以上版本,沒有限制行數,所以在寫入數據時耗時相比較長。共耗時:10.959秒

07版本數據批量寫入


注意: 如果03版本寫入數據行數超過65536行會報如下錯誤,而07版本的不會報錯

65536超出報錯

5.1.5 07版本批量寫入優化

通過上面的列子,我們可以看出來在07版本中批量寫入大數據的時候耗時比較長,這小節,我們就使用apach提供新的類來優化代碼

① 代碼

代碼基本不用變,我們只需要將new XSSFWorkbook() 修改爲new SXSSFWorkbook()

並且最終將數據寫入過程中產生的緩存文件刪除((SXSSFWorkbook) workbook).dispose();

 @Test
    public void batchWriteExcel07optTest() throws Exception {
        Workbook workbook = new SXSSFWorkbook();
        Sheet sheet = workbook.createSheet("大文件導出優化測試");

        long begin = System.currentTimeMillis();

        for (int rowNum = 0; rowNum <65536 ; rowNum++) {
            Row row = sheet.createRow(rowNum);
            for (int cellNum = 0; cellNum < 10 ; cellNum++) {
                Cell cell = row.createCell(cellNum);
                cell.setCellValue("("+(rowNum+1) + "," + (cellNum+1)+")");
            }

        }
        FileOutputStream fileOutputStream = new FileOutputStream(filepath + "07版本批量寫入優化.xlsx");
        workbook.write(fileOutputStream);
        // 清理臨時文件
        ((SXSSFWorkbook) workbook).dispose();
        fileOutputStream.close();
        workbook.close();

        long end = System.currentTimeMillis();
        System.out.println("耗時:"+(double)(end-begin)/1000+"秒");
    }

② 最終效果

同樣的數據大小,耗時明顯減少了

07批量寫入優化

5.2 基本讀操作

5.2.1 基本讀excel

① 03版本讀取

String filePath = "E:\\xiezhrspace\\excel-demo\\fileinput\\";

@Test
public void readExcel03Test() throws  Exception{

    FileInputStream fileInputStream = new FileInputStream(filePath + "poiexcel03.xls");

    Workbook workbook = new HSSFWorkbook(fileInputStream);
    Sheet sheet = workbook.getSheetAt(0);
    //獲取第一行
    Row row1 = sheet.getRow(0);
    //獲取第一行的第一個單元格
    Cell cell11 = row1.getCell(0);
    //獲取第一行第二個單元格
    Cell cell12 = row1.getCell(1);
    System.out.println("第一行第一個單元格的內容是:"+cell11.getStringCellValue());
    System.out.println("第一行第二個單元格的內容是:"+cell12.getStringCellValue());

    //獲取第一行
    Row row2 = sheet.getRow(1);
    //獲取第一行的第一個單元格
    Cell cell21 = row2.getCell(0);
    //獲取第一行第二個單元格
    Cell cell22 = row2.getCell(1);
    System.out.println("第一行第一個單元格的內容是:"+cell21.getStringCellValue());
    System.out.println("第一行第二個單元格的內容是:"+cell22.getStringCellValue());

}
//結果
第一行第一個單元格的內容是:個人公衆號
第一行第二個單元格的內容是:XiezhrSpace
第一行第一個單元格的內容是:個人博客
第一行第二個單元格的內容是:www.xiezhrspace.cn

②07版本讀取

只需將new FileInputStream(filePath + "poiexcel03.xls")修改爲new FileInputStream(filePath + "poiexcel07.xlsx")

new HSSFWorkbook(fileInputStream) 修改爲new XSSFWorkbook(fileInputStream)

String filePath = "E:\\xiezhrspace\\excel-demo\\fileinput\\";
@Test
    public void readExcel07Test() throws  Exception{

        FileInputStream fileInputStream = new FileInputStream(filePath + "poiexcel07.xlsx");

        Workbook workbook = new XSSFWorkbook(fileInputStream);
        Sheet sheet = workbook.getSheetAt(0);
        //獲取第一行
        Row row1 = sheet.getRow(0);
        //獲取第一行的第一個單元格
        Cell cell11 = row1.getCell(0);
        //獲取第一行第二個單元格
        Cell cell12 = row1.getCell(1);
        System.out.println("第一行第一個單元格的內容是:"+cell11.getStringCellValue());
        System.out.println("第一行第二個單元格的內容是:"+cell12.getStringCellValue());

        //獲取第一行
        Row row2 = sheet.getRow(1);
        //獲取第一行的第一個單元格
        Cell cell21 = row2.getCell(0);
        //獲取第一行第二個單元格
        Cell cell22 = row2.getCell(1);
        System.out.println("第一行第一個單元格的內容是:"+cell21.getStringCellValue());
        System.out.println("第一行第二個單元格的內容是:"+cell22.getStringCellValue());

    }
//結果
第一行第一個單元格的內容是:個人公衆號
第一行第二個單元格的內容是:XiezhrSpace
第一行第一個單元格的內容是:個人博客
第一行第二個單元格的內容是:www.xiezhr.cn

注:

如果上面獲取單元格數據的時候,取值的類型不對,即String 類型的數據通過cell22.getNumericCellValue() 獲取,則會報錯

其他類型不匹配情況類似

類型不匹配報錯

5.2.2 讀取不同類型數據

① 準備數據

現在有一張用戶訂單信息表,表內容如下,表中包含了各種類型的數據

用戶訂單信息表

②書寫代碼,將表格中的內容讀取出來輸出到控制檯

  @Test
    public void readExcel07ByTypeTest() throws Exception{
        FileInputStream fileInputStream = new FileInputStream(filePath + "用戶訂單信息表.xlsx");

        //根據文件輸入流獲取excel工作簿(Workbook)
        Workbook workbook = new XSSFWorkbook(fileInputStream);

        //根據工作簿獲取第一個sheet
        Sheet sheet = workbook.getSheetAt(0);
        //獲取表頭信息
        Row rowtitle = sheet.getRow(0);
        //獲取表頭有多少列
        int cells = rowtitle.getPhysicalNumberOfCells();

        for (int cellNum = 0; cellNum < cells; cellNum++) {
            Cell cell = rowtitle.getCell(cellNum);
            String cellValue = cell.getStringCellValue();
            System.out.print(cellValue + "\t");
        }
        //循環讀取數據
        //獲取行數
        int rows = sheet.getPhysicalNumberOfRows();
        //從第二行開始讀取數據
        for (int rowNum = 1; rowNum < rows; rowNum++) {
            //獲取行對象
            Row row = sheet.getRow(rowNum);
            int ofCells = row.getPhysicalNumberOfCells();
            //獲取列數
            for (int cellNum = 0; cellNum < ofCells; cellNum++) {

                System.out.print("第" + (rowNum + 1) + "行第" + (cellNum + 1) + "列");
                //獲取單元格
                Cell cell = row.getCell(cellNum);
                //獲取單元格數據類型
                if (cell!=null) {
                    CellType cellType = cell.getCellType();
                    //根據單元格數據類型獲取單元格數據
                    String cellvalue ="";
                    switch (cellType) {

                        case STRING : //判斷是否是字符串類型
                            System.out.print("【String】");
                            cellvalue = cell.getStringCellValue();
                            break;
                        case NUMERIC:  //判斷是否是數字類型
                            if (DateUtil.isCellDateFormatted(cell)) {
                                System.out.print("【date】");
                                Date date = cell.getDateCellValue();
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                                cellvalue = sdf.format(date);

                            } else {
                                System.out.print("【double】");
                                double numericCellValue = cell.getNumericCellValue();
                                cell.setCellType(CellType.STRING);
                                cellvalue = String.valueOf(numericCellValue);

                                }
                            break;
                        case BLANK:
                            System.out.print("【BLANK】");
                            break;
                        case BOOLEAN:
                            System.out.print("【BOOLEAN】");
                            boolean bool = cell.getBooleanCellValue();
                            cellvalue = String.valueOf(bool);
                            break;
                        case _NONE:
                            System.out.print("【_NONE】");
                            break;
                        case  ERROR:
                            System.out.print("【ERROR】");
                            byte errorCode = cell.getErrorCellValue();
                            cellvalue = String.valueOf(errorCode);
                            break;
                        case  FORMULA:
                            System.out.print("【FORMULA】");
                            XSSFFormulaEvaluator formulaEvaluator = new XSSFFormulaEvaluator((XSSFWorkbook) workbook);

                            String formula = cell.getCellFormula();
                            System.out.println("formula:"+formula);
                            CellValue evaluate = formulaEvaluator.evaluate(cell);
                            cellvalue= evaluate.formatAsString();
                            break;
                    }
                    System.out.println(cellvalue);
                }

            }

        }

    }

讀取不同類型數據

六、EasyPoi 使用

Easypoi的目標不是替代poi,而是讓一個不懂導入導出的快速使用poi完成Excel和word的各種操作,而不是看很多api纔可以完成這樣工作

Easypoi 爲誰而開發?

  • 不太熟悉poi的
  • 不想寫太多重複太多的
  • 只是簡單的導入導出的
  • 喜歡使用模板的

6.1 所需依賴

<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>4.1.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-web</artifactId>
    <version>4.1.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>4.1.0</version>
</dependency>
  • 1.easypoi :父包–作用大家都懂得
  • 2.easypoi-annotation :基礎註解包,作用與實體對象上,拆分後方便maven多工程的依賴管理
  • 3.easypoi-base :導入導出的工具包,可以完成Excel導出,導入,Word的導出,Excel的導出功能
  • 4.easypoi-web :耦合了spring-mvc 基於AbstractView,極大的簡化spring-mvc下的導出功能
  • 5.sax :導入使用xercesImpl這個包(這個包可能造成奇怪的問題哈),word導出使用poi-scratchpad,都作爲可選包了

如果不使用spring mvc的便捷福利,直接引入easypoi-base 就可以了,easypoi-annotation

6.2 常用註解

EasyPoi 爲了方便我們操作,實現了實體和Excel的對應,model--row,filed--col,這樣利用註解,我們就可以輕輕鬆鬆實現excel的導入導出

  • @Excel 作用到filed上面,是對Excel一列的一個描述
  • **@ExcelCollection ** 表示一個集合,主要針對一對多的導出,比如一個老師對應多個科目,科目就可以用集合表示
  • @ExcelEntity 表示一個繼續深入導出的實體,但他沒有太多的實際意義,只是告訴系統這個對象裏面同樣有導出的字段
  • @ExcelIgnore 和名字一樣表示這個字段被忽略跳過這個導導出
  • @ExcelTarget 這個是作用於最外層的對象,描述這個對象的id,以便支持一個對象可以針對不同導出做出不同處理
6.2.1 @ExcelTarget

限定一個到處實體的註解,以及一些通用設置,作用於最外面的實體

①常用屬性

屬性 類型 默認值 功能
value String null 定義id唯一標識,不能重複
height double 10 定義單元格高度
fontSize short 11 設置文字大小

②使用

@ExcelTarget("users")
public class User implements Serializable {
 	//..... 省略屬性 相關GET,SET方法
}
6.2.2 @Excel

@Excel這個是必須使用的註解,用在filed(屬性)上面,是對Excel一列的一個描述

① 常用屬性

屬性 類型 默認值 功能
name String null 生成Excel表格中列名
needMerge boolean fasle 是否需要縱向合併單元格(用於含有list中,單個的單元格,合併list創建的多個row)
orderNum String "0" 指定生成Excel中列的順序,按照數字自然順序排序
replace String[] {} 值得替換 導出是{a_id,b_id} 導入反過來
savePath String “upload” 指定導入Excel中圖片的保存路徑
type int 1 導出類型 1 是文本 2 是圖片,3 是函數,10 是數字 默認是文本
width double 10 指定導出Excel時列的寬度
isImportField boolean true 校驗字段,看看這個字段是不是導入的Excel中有,如果沒有說明是錯誤的Excel,讀取失敗,
exportFormat String "" 導出Excel的時間格式
importFormat String "" 導入Excel的時間格式
format String "" 時間格式,相當於同時設置了exportFormat 和 importFormat
imageType int 1 導出類型 1 從file讀取 2 是從數據庫中讀取 默認是文件 同樣導入也是一樣的
suffix String "" 文字後綴,如% 90 變成90%
isWrap boolean true 是否換行 即支持\n
mergeVertical boolean fasle 縱向合併內容相同的單元格

②使用

@ExcelTarget("user")
public class User {
    @Excel(name = "姓名",orderNum = "1",width = 20 )
    private String name;
    @Excel(name = "年齡",orderNum = "2",width = 20 )
    private  Integer age;
    @Excel(name = "性別",orderNum = "3",width = 20,replace = {"男_1","女_2"})
    private String sex;
    @Excel(name = "生日",orderNum = "4",width = 20,format = "yyyy-MM-dd")
    private Date birthday;
    //...省略GET、SET方法
}
7.2.3 @ExcelEntity

來標記實體類中包含另一個實體類的字段的註解。通過在父實體類的字段上添加 @ExcelEntity 註解,可以將子實體類中的字段映射到 Excel 表格中

① 常用屬性

屬性 類型 默認值 功能
id String null 定義ID

② 使用

@ExcelTarget("user")
public class User {
    //省略GET、SET方法和其他屬性
    @ExcelEntity(name = "用戶基本信息")
    private UserBaseInfo userBaseInfo;

}

@ExcelTarget("userBaseInfo")
class UserBaseInfo{
    @Excel(name = "手機號",orderNum = "5",width = 20)
    private String phone;
    @Excel(name = "郵箱",orderNum = "6",width = 20)
	//省略其他字段和方法
}

在上面的示例中, User 類中包含一個 UserBaseInfo 類型的字段 userBaseInfo ,通過在 userBaseInfo 字段上添加 @ExcelEntity 註解,可以將 UserBaseInfo 類中的字段映射到 Excel 表格中,並且在 Excel 表格中會顯示爲一個包含 手機號 和 郵箱 列的子表格。

6.2.4 @ExcelCollection

一對多的集合註解,來標記實體類中包含集合類型字段的註解。

通過在父實體類的集合字段上添加 @ExcelCollection 註解,可以將集合中的元素映射到 Excel 表格中

①常用屬性

屬性 類型 默認值 功能
id String null 定義ID
name String null 定義集合列名,支持nanm_id
orderNum int 0 排序,支持name_id
type Class<?> ArrayList.class 導入時創建對象使用

② 使用

@ExcelTarget("user")
public class User {
   //省略GET、SET 方法和其他屬性
    @ExcelCollection(name = "商品列表",orderNum = "10")
    private List<Product> products;

}
@ExcelTarget("product")
public class Product {
    @Excel(name = "商品名稱" )
    private String productName;
    @Excel(name = "商品價格")
    private double productPrice;
}

在上面的示例中, User 類中包含一個 List<Product> 類型的字段 products ,通過在 products 字段上添加 @ExcelCollection 註解,可以將 Product 類型的元素映射到 Excel 表格中,並且在 Excel 表格中會顯示爲一個包含多個商品信息的列表。

6.2.5 @ExcelIgnore

來標記實體類中不需要導出到 Excel 表格的字段的註解

① 使用

public class Product {
    @Excel(name = "商品名稱")
    private String name;
    
    @Excel(name = "價格")
    private double price;
    
    @ExcelIgnore
    private String description; // 不需要導出到 Excel 表格的字段
    
    // 其他字段和方法
}

在上面的示例中, Product 類中包含了 name 、 price 和 description 三個字段。通過在 description 字段上添加 @ExcelIgnore 註解,告訴 EasyPoi 在導出 Excel 表格時不導出該字段的內容。

6.3 註解使用導出Excel案例

6.3.1 導出基本數據

① 創建基本對象對象

@Data
@ExcelTarget("user")
public class User {
    @Excel(name = "姓名",orderNum = "1",width = 20,needMerge = true)
    private String name;
    @Excel(name = "年齡",orderNum = "2",width = 20,needMerge = true)
    private  Integer age;
    @Excel(name = "性別",orderNum = "3",width = 20,replace = {"男_1","女_2"},needMerge = true)
    private String sex;
    @Excel(name = "生日",orderNum = "4",width = 20,format = "yyyy-MM-dd",needMerge = true)
    private Date birthday;

}

②模擬測試數據

public List<User> testGetTestData(){
        List<User> users = new ArrayList<User>();
        for (int i = 0; i < 5; i++) {
            User user = new User();
            user.setName("小凡"+i);
            user.setAge(i+18);
            user.setSex("1");
            user.setBirthday(new Date());
            users.add(user);
        }
        return users;
    }

③導出數據

@Test
public void testExportExcel() throws Exception {
    ExportParams exportParams = new ExportParams("用戶列表", "測試sheet頁");
    //創建ExcelExportUtil對象,傳入參數爲ExportParams對象,User類,testGetTestData()方法
    Workbook workbook = ExcelExportUtil.exportExcel(exportParams, User.class, testGetTestData());
    //創建FileOutputStream對象,傳入參數爲文件路徑
    FileOutputStream fileOutputStream = new FileOutputStream("D:/test.xls");
    //將workbook寫入到文件輸出流中
    workbook.write(fileOutputStream);
    //關閉文件輸出流
    fileOutputStream.close();
    //關閉workbook
    workbook.close();
    System.out.println("導出成功");
}

④ 查看excel

導出基本excel

6.3.2 忽略某個字段

① 添加註解

@ExcelIgnore
private  Integer age;

②查看excel

忽略某個字段

6.3.3 導出對象中含有對象的數據

① 添加註解

@ExcelTarget("user")
public class User {
    //省略GET、SET方法和其他屬性
    @ExcelEntity(name = "用戶基本信息")
    private UserBaseInfo userBaseInfo;
}

② 新建UserBaseInfo類

@ExcelTarget("userBaseInfo")
class UserBaseInfo{
    @Excel(name = "手機號",orderNum = "5",width = 20)
    private String phone;
    @Excel(name = "郵箱",orderNum = "6",width = 20)
	//省略其他字段和方法
}

③ 測試數據中添加UserBaseInfo 對象

user.setUserBaseInfo(new UserBaseInfo("15288345678","[email protected]","雲南省昆明市","651219","532334125689558"));

④ 導出excel數據

對象中包含對象

6.3.4 導出含list集合數據

①我們新建Product 對象

@ExcelTarget("product")
public class Product {
    //省略GET、SET方法
    @Excel(name = "商品名稱" )
    private String productName;
    @Excel(name = "商品價格")
    private double productPrice;
}

② User 類中添加如下list集合

@ExcelCollection(name = "商品列表",orderNum = "10")
private List<Product> products;

③添加測試數據

public List<User> testGetTestData(){
    List<User> users = new ArrayList<User>();
    for (int i = 0; i < 5; i++) {
        User user = new User();
        user.setName("小凡"+i);
        user.setAge(i+18);
        user.setSex("1");
        user.setBirthday(new Date());
        user.setUserBaseInfo(new UserBaseInfo("15288345678","[email protected]","雲南省昆明市","651219","532334125689558"));
        Product pro1 = new Product("冰箱"+i, 5000);
        Product pro2 = new Product("洗衣機"+i, 3000);
        Product pro3 = new Product("空調"+i, 4000);
        List<Product> products = Arrays.asList(pro1, pro2, pro3);
        user.setProducts(products);
        users.add(user);
    }
    return users;
}

④ 由於是一對多關係,所以需要添加合併單元格屬性needMerge = true

@Excel(name = "姓名",orderNum = "1",width = 20,needMerge = true)
private String name;
@Excel(name = "年齡",orderNum = "2",width = 20,needMerge = true)
//其他屬性類似省略。。。

⑤導出excel

導出list

6.3.5 導出圖片

User類中定義頭像avter字段

@Excel(name = "頭像",orderNum = "0",width = 20,type = 2,height = 20,needMerge = true) //type的值一定要指定爲2
private String avatar; //定義頭像 直接寫指定圖片路徑

② 構造測試數據

    public List<User> testGetTestData(){
        List<User> users = new ArrayList<User>();
        for (int i = 0; i < 5; i++) {
            User user = new User();
            user.setName("小凡"+i);
            user.setAge(i+18);
            user.setSex("1");
            user.setBirthday(new Date());
            user.setUserBaseInfo(new UserBaseInfo("15288345678","[email protected]","雲南省昆明市","651219","532334125689558"));
            Product pro1 = new Product("冰箱"+i, 5000);
            Product pro2 = new Product("洗衣機"+i, 3000);
            Product pro3 = new Product("空調"+i, 4000);
            List<Product> products = Arrays.asList(pro1, pro2, pro3);
            user.setAvatar("https://xiezhrspace.cn/medias/logo.png");
            user.setProducts(products);
            users.add(user);
        }
        return users;
    }

③ 導出excel

導出圖片

6.4 大數據導出

當我們導出得數據量爲幾十萬到幾百萬時,一次將所有數據加載到內存中,會對cpu、內存都產生巨大壓力。

當然了,EasyPoi作者也爲我們考慮了,專門提供exportBigExcel 方法來導出大數據

Workbook workbook1 = ExcelExportUtil.exportBigExcel(new ExportParams("用戶列表", "測試"), User.class, getUsers());
workbook1.write(outputStream);
ExcelExportUtil.closeExportBigExcel();

6.5 導入excel

6.5.1 導入基本數據

① 準備目標excel

目標excel

② 定義基本數據對象

@ExcelTarget("student")
public class Student implements Serializable {
    @Excel(name = "編號")
    private String id;
    @Excel(name = "姓名")
    private String name;
    @Excel(name = "性別", replace = {"男_1", "女_2"})
    private String gender;
    @Excel(name = "年齡")
    private Integer age;
    @Excel(name = "出生日期", importFormat = "yyyy-MM-dd")
    private Date birth;
    //省略GET、SET方法
}

③ 導入代碼

@Test
public void excelImportTest() throws Exception{
    // 創建導入參數配置
    ImportParams importParams = new ImportParams();
    // 設置標題行數
    importParams.setTitleRows(1);
    // 設置表頭行數
    importParams.setHeadRows(1);

    // 創建文件輸入流
    FileInputStream fileInputStream = new FileInputStream("E:\\xiezhrspace\\excel-demo\\fileinput\\學生信息表.xlsx");
    // 調用ExcelImportUtil的importExcel方法,傳入文件輸入流,實體類,參數配置,返回實體類列表
    List<Student> students = ExcelImportUtil.importExcel(fileInputStream, Student.class, importParams);
    // 遍歷實體類列表,輸出實體類信息
    students.forEach(System.out::println);
    // 關閉文件輸入流
    fileInputStream.close();

}

② 打印導入結果

Student(id=10001, name=張三, gender=1, age=25, birth=1992-02-23)
Student(id=10002, name=李四, gender=1, age=18, birth=2006-01-01)
Student(id=10003, name=王五, gender=1, age=26, birth=1998-01-01)
Student(id=10004, name=趙六, gender=2, age=26, birth=1998-03-01)
6.5.2 導入帶圖片數據

①excel數據

excel圖片數據

Student類設置圖片保存路徑

@ExcelTarget("student")
public class Student implements Serializable {
    @Excel(name = "編號")
    private String id;
    @Excel(name = "姓名")
    private String name;
    @Excel(name = "性別", replace = {"男_1", "女_2"})
    private String gender;
    @Excel(name = "年齡")
    private Integer age;
    @Excel(name = "出生日期", importFormat = "yyyy-MM-dd")
    private Date birth;
    @Excel(name = "頭像", type = 2,  savePath = "src/main/imgs")  //設置導入圖片的保存路徑
    private String avatar;
    //省略GET、SET 方法
}

③ 導入excel

關鍵部分

importParams.setNeedSave(false);

importParams.setSaveUrl("src/main/imgs");

@Test
public void excelImportTest() throws Exception{
    // 創建導入參數配置
    ImportParams importParams = new ImportParams();
    // 設置標題行數
    importParams.setTitleRows(1);
    // 設置表頭行數
    importParams.setHeadRows(1);

    // 設置是否需要保存
    importParams.setNeedSave(false);
    // 設置保存路徑
    importParams.setSaveUrl("src/main/imgs");

    // 創建文件輸入流
    FileInputStream fileInputStream = new FileInputStream("E:\\xiezhrspace\\excel-demo\\fileinput\\學生信息表.xlsx");
    // 調用ExcelImportUtil的importExcel方法,傳入文件輸入流,實體類,參數配置,返回實體類列表
    List<Student> students = ExcelImportUtil.importExcel(fileInputStream, Student.class, importParams);
    // 遍歷實體類列表,輸出實體類信息
    students.forEach(System.out::println);
    // 關閉文件輸入流
    fileInputStream.close();

}

④ 導入結果

Student(id=10001, name=張三, gender=1, age=25, birth=1992-02-23,avatar=src/main/imgs\pic33945659303.PNG)
Student(id=10002, name=李四, gender=1, age=18, birth=2006-01-01,avatar=src/main/imgs\pic31457305277.JPG)
Student(id=10003, name=王五, gender=1, age=26, birth=1998-01-01,avatar=src/main/imgs\pic71983821334.PNG)
Student(id=10004, name=趙六, gender=2, age=26, birth=1998-03-01,avatar=src/main/imgs\pic41577097054.PNG)

圖片保存路徑

6.6 小結

以上小節爲easypoi的最基本操作,如果大家還想了解更多,可以關注官方文檔:http://doc.wupaas.com/docs/easypoi/

作者也給出了大量的實例:https://gitee.com/lemur/easypoi-test

八、EasyExcel使用

8.1 快速入門之寫excel

8.1.1 引入依賴

目前最新的依賴是3.3.3,我們這裏引入使用最多也最穩定的3.3.2版本

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>
8.1.2 構建數據對象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
    @ExcelProperty("員工編號")
    private  Integer id;
    @ExcelProperty("員工姓名")
    private  String name;
    @ExcelProperty("員工年齡")
    private  Integer age;
    @ExcelProperty("員工薪資")
    private  Double salary;
    @ExcelProperty("入職日期")
    private Date inDate;
}
8.1.3 構建測試數據
private List<Employee> data(long count) {
    List<Employee> list = ListUtils.newArrayList();
    for (int i = 0; i < count; i++) {
        Employee employee = new Employee();
        employee.setId(i);
        employee.setName("小陳"+i);
        employee.setAge(18+1);
        employee.setSalary(6.66+i);
        employee.setInDate(new Date());
        list.add(employee);
    }
    return list;
}

上面代碼根據傳入count,構建通用數據,後面不會重複寫

8.1.4 寫入數據
@Test
public void testbaseWrite() {
    String fileName = "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
    // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
    // 如果這裏想使用03 則 傳入excelType參數即可
    EasyExcel.write(fileName, Employee.class).sheet("測試模板").doWrite(data(10));

}

寫入的數據

8.2 快速入門之讀excel

8.2.1 準備目標excel

員工信息表

8.2.2 構建數據對象

這裏我們沿用8.1.2 小節中創建的employee對象

8.2.3 讀取數據

注: PageReadListener 爲默認easyexcel爲我們寫好的監聽類,當然了,我們也可以自己定義,在後面的進階操作中

我們會說到

@Test
public void testbaseReade(){
    String fileName = "E:\\xiezhrspace\\excel-demo\\fileinput\\" + "員工信息表.xlsx";
    EasyExcel.read(fileName, Employee.class, new PageReadListener<Employee>(dataList -> {
        for (Employee employee : dataList) {
            System.out.println(employee);
        }
    })).sheet().doRead();
}

讀取數據

8.3 進階操作

8.3.1 複雜表頭寫入

① 準備對象

@Data
public class Student {
    @ExcelProperty({"學生信息表","學生ID"})
    private  Integer id;
    @ExcelProperty({"學生信息表","學生姓名"})
    private String name;
    @ExcelProperty({ "學生信息表", "學生年齡" })
    private Integer age;
    @ExcelProperty({ "學生信息表", "生日" })
    private Date birth;
}

②代碼

public class UpEasyExcelTest {
    private List<Student> data(long count) {
        List<Student> list = ListUtils.newArrayList();
        for (int i = 0; i < count; i++) {
            Student student = new Student();
            student.setId(i);
            student.setName("小李" + i);
            student.setAge(22+i);
            student.setBirth(new Date());
            list.add(student);
        }
        return list;
    }

    @Test
    public void testUpWrite() {
        String fileName = "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "upWrite" + System.currentTimeMillis() + ".xlsx";
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        // 如果這裏想使用03 則 傳入excelType參數即可
        EasyExcel.write(fileName, Student.class).sheet("測試模板").doWrite(data(10));

    }
}

③excel寫入示例

複雜表頭

8.3.2 重複多次寫入(寫到單個或者多個Sheet)

① 準備對象

public class Employee {
    @ExcelProperty("員工編號")
    private  Integer id;
    @ExcelProperty("員工姓名")
    private  String name;
    @ExcelProperty("員工年齡")
    private  Integer age;
    @ExcelProperty("員工薪資")
    private  Double salary;
    @ExcelProperty(value = "入職日期")
    private Date inDate;
    //省略GET、SET 方法
}

②代碼

 @Test
public void testmanyDateWriter(){
    // 方法1: 如果寫到同一個sheet
    String fileName = "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "manydataWrite" + System.currentTimeMillis() + ".xlsx";
    // 這裏 需要指定寫用哪個class去寫
    try (ExcelWriter excelWriter = EasyExcel.write(fileName, Employee.class).build()) {
        // 這裏注意 如果同一個sheet只要創建一次
        WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
        // 去調用寫入,這裏我調用了五次,實際使用時根據數據庫分頁的總的頁數來
        for (int i = 0; i < 5; i++) {
            // 分頁去數據庫查詢數據 這裏可以去數據庫查詢每一頁的數據
            List<Employee> data = data(200000);
            excelWriter.write(data, writeSheet);
        }
    }

    // 方法2: 如果寫到不同的sheet 同一個對象
    fileName =  "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "manydataWrite" + System.currentTimeMillis() + ".xlsx";
    // 這裏 指定文件
    try (ExcelWriter excelWriter = EasyExcel.write(fileName, Employee.class).build()) {
        // 去調用寫入,這裏我調用了五次,實際使用時根據數據庫分頁的總的頁數來。這裏最終會寫到5個sheet裏面
        for (int i = 0; i < 5; i++) {
            // 每次都要創建writeSheet 這裏注意必須指定sheetNo 而且sheetName必須不一樣
            WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
            // 分頁去數據庫查詢數據 這裏可以去數據庫查詢每一頁的數據
            List<Employee> data = data(200000);
            excelWriter.write(data, writeSheet);
        }
    }

    // 方法3 如果寫到不同的sheet 不同的對象
    fileName =  "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "manydataWrite" + System.currentTimeMillis() + ".xlsx";
    // 這裏 指定文件
    try (ExcelWriter excelWriter = EasyExcel.write(fileName).build()) {
        // 去調用寫入,這裏我調用了五次,實際使用時根據數據庫分頁的總的頁數來。這裏最終會寫到5個sheet裏面
        for (int i = 0; i < 5; i++) {
            // 每次都要創建writeSheet 這裏注意必須指定sheetNo 而且sheetName必須不一樣。這裏注意DemoData.class 可以每次都變,我這裏爲了方便 所以用的同一個class
            // 實際上可以一直變
            WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(Employee.class).build();
            // 分頁去數據庫查詢數據 這裏可以去數據庫查詢每一頁的數據
            List<Employee> data = data(200000);
            excelWriter.write(data, writeSheet);
        }
    }
}

③Excel示例

100萬數據寫入

除了上面的常用例子外,還有更多玩法,大家可以參照官方文檔,裏面寫的很詳細,這裏就不一一例舉了~

8.4 excel填充

EasyExcel提供了數據填充的功能,可以將指定的數據填充到事先設計好帶有樣式和格式的Excel模板文,這樣我們就可以製作出更加優美的excel

8.4.1 簡單的填充

① 準備模板

image-20240310172107654

②準備對象

@Data
public class Student {
    @ExcelProperty({"學生信息表","學生ID"})
    private  Integer id;
    @ExcelProperty({"學生信息表","學生姓名"})
    private String name;
    @ExcelProperty({ "學生信息表", "學生年齡" })
    private Integer age;
    @ExcelProperty({ "學生信息表", "生日" })
    private Date birth;
}

③填充數據

根據對象填充

@Test
public void filebyObjFillTest() {
    // 模板注意 用{} 來表示你要用的變量 如果本來就有"{","}" 特殊字符 用"\{","\}"代替
    String templateFileName ="E:\\xiezhrspace\\excel-demo\\fileinput\\" +  "template.xlsx";

    // 方案1 根據對象填充
    String fileName = "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "fillWrite" + System.currentTimeMillis() + ".xlsx";

    Student student = new Student();
    student.setId(1);
    student.setName("張三");
    student.setAge(20);
    student.setBirth(new Date());
    // 這裏 會填充到第一個sheet, 然後文件流會自動關閉

    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(student);

}

根據map填充

@Test
public void filebyMapFillTest() {
    // 模板注意 用{} 來表示你要用的變量 如果本來就有"{","}" 特殊字符 用"\{","\}"代替
    String templateFileName ="E:\\xiezhrspace\\excel-demo\\fileinput\\" +  "template.xlsx";
    // 方案2 根據Map填充
    String fileName = "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "fillWrite" + System.currentTimeMillis() + ".xlsx";

    // 這裏 會填充到第一個sheet, 然後文件流會自動關閉
    Map<String, Object> map = MapUtils.newHashMap();
    map.put("id", "001");
    map.put("name", "張三");
    map.put("age", 20);
    map.put("birthday", new Date());
    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(map);
}

④最終效果

最終效果

8.4.2 填充列表數據

①準備模板

相比上一小節的模板,列表數據的模板{id}----->{.id} {name}--->{.name} 依此類推

列表模板

②填充對象

參照上一小節

③ 準備數據

private List<Student> data(long count) {
        List<Student> list = ListUtils.newArrayList();
        for (int i = 0; i < count; i++) {
            Student student = new Student();
            student.setId(i);
            student.setName("小李" + i);
            student.setAge(22+i);
            student.setBirth(new Date());
            list.add(student);
        }
        return list;
    }

④ 填充數據

@Test
public void listFill() {
    // 模板注意 用{} 來表示你要用的變量 如果本來就有"{","}" 特殊字符 用"\{","\}"代替
    // 填充list 的時候還要注意 模板中{.} 多了個點 表示list
    // 如果填充list的對象是map,必須包涵所有list的key,哪怕數據爲null,必須使用map.put(key,null)
    String templateFileName ="E:\\xiezhrspace\\excel-demo\\fileinput\\" +  "template-list.xlsx";

    // 方案1 一下子全部放到內存裏面 並填充
    String fileName = "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "fillWrite-list" + System.currentTimeMillis() + ".xlsx";
    // 這裏 會填充到第一個sheet, 然後文件流會自動關閉
    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(data(10));

}

⑤ 最終效果

最終效果

8.4.3 複雜填充

當excel模板相對複雜時,也可以填充

① 準備複雜模板

複雜模板

② 準備填充對象

參照8.4.1小節

③準備數據

參照8.4.1小節

④填充數據

@Test
public void complexFill() {
    // 模板注意 用{} 來表示你要用的變量 如果本來就有"{","}" 特殊字符 用"\{","\}"代替
    // {} 代表普通變量 {.} 代表是list的變量
    String templateFileName ="E:\\xiezhrspace\\excel-demo\\fileinput\\" +  "template-hard.xlsx";

    String fileName = "E:\\xiezhrspace\\excel-demo\\fileoutput\\" + "fillWrite-hard" + System.currentTimeMillis() + ".xlsx";
    // 方案1
    try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        // 這裏注意 入參用了forceNewRow 代表在寫入list的時候不管list下面有沒有空行 都會創建一行,然後下面的數據往後移動。默認 是false,會直接使用下一行,如果沒有則創建。
        // forceNewRow 如果設置了true,有個缺點 就是他會把所有的數據都放到內存了,所以慎用
        // 簡單的說 如果你的模板有list,且list不是最後一行,下面還有數據需要填充 就必須設置 forceNewRow=true 但是這個就會把所有數據放到內存 會很耗內存
        // 如果數據量大 list不是最後一行 參照下一個
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        excelWriter.fill(data(5), fillConfig, writeSheet);
        excelWriter.fill(data(5), fillConfig, writeSheet);
        Map<String, Object> map = MapUtils.newHashMap();
        map.put("date", "2024年03月10日17:28:28");
        map.put("total", 1000);
        excelWriter.fill(map, writeSheet);
    }
}

⑤ 最終效果

學生信息統計表

九、文章小節

文中只例舉出excel 常用操作,如果這些還不滿足你的需求,大家可以查看官方文檔。

官方文檔還是非常詳細的,並且都給出了具體的demo。

另外文中例舉出的代碼已提交到https://gitee.com/xiezhr/excel-demo.git 歡迎大家訪問查看

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