当前位置:网站首页>POI和EasyExcel讲解

POI和EasyExcel讲解

2022-04-23 22:02:00 .G( );

全文内容来自官方文档和相关视频的讲解,本作者用做笔记!

常用场景:

  1. 将用户信息导出为Excel表格(导出xls数据…)
  2. 将Excel表中的信息录入到网站数据库(习题上传…公司找老师填写题目到excel再上传网站,网站会利用相关POI将数据回填到数据库,这样大大减轻网站录入量。)

开发中经常会设计到excel的处理,如导出Excel,导入Excel到数据库中!
操作Excel目前流行的就是Apache POI阿里巴巴 EasyExcel


Apache POI

Apache POI 官网:

Apache POI 官网:https://poi.apache.org/

  Apache POI 是Apache软件基金会的开放源码函数库,用Java编写的免费开源的跨平台的 Java API。Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。

基本功能:

HSSF - 提供读写Microsoft Excel XLS格式档案的功能。
XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
HWPF - 提供读写Microsoft Word DOC格式档案的功能。
HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
HDGF - 提供读Microsoft Visio格式档案的功能。
HPBF - 提供读Microsoft Publisher格式档案的功能。
HSMF - 提供读Microsoft Outlook格式档案的功能。

Excel 版本区别:03版和07版

03版本 2003版本.xls:行数只有65535行,多了放不了。
03版本
07版本 2007版本.xlsx:无限制
07版本


POI-Excel 写

创建普通Maven项目:

Java版本:1.8
maven

maven

创建完项目,导入依赖 pom.xml:

<!--导入依赖-->
    <dependencies>
      <!-- excel2003版本 xls -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.9</version>
        </dependency>

      <!-- excel 2007版本 xlsx -->
        <dependency>-->
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.9</version>
        </dependency>

        <!-- 日期格式化工具 -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.10.1</version>
        </dependency>

        <!-- test 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

请添加图片描述

Java编程,万物皆对象:

excel 表中的各个对象: 工作簿、工作表、行、列、单元格
java

实现类,写入

先创建工作簿,后创建工作表,再有行和列,最后组成了数据:

public class ExcelWriteTest {
     //03版本实现类

String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;//设置固定文件路径

    @Test  //创建03版本
    public void testWrite03() throws Exception{
    
        // 1.创建一个工作簿
        Workbook workbook = new HSSFWorkbook();  //对象存在差别 HSSF
        // 2.创建一个工作表
        Sheet sheet = workbook.createSheet("guo1");  //sheet 名字为:guo1
        // 3.创建一个行 (1,1)
        Row row11 = sheet.createRow(0);  //第一行
        // 4. 创建一个单元格
        Cell cell11 = row11.createCell(0);  //第一行,第一列的格子(0,0)
        cell11.setCellValue("今日人数");  //设置值

        //(1,2)
        Row row12 = sheet.createRow(1);
        Cell cell12 = row12.createCell(0);
        cell12.setCellValue(666);

        // 第二行
        Row row2 = sheet.createRow(1);
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("统计时间");
        // (2,2)
        Cell cell22 = row2.createCell(1);
        String time = new DateTime().toString("yyyy-mm-dd HH:mm:ss");
        cell22.setCellValue(time);

        //生成一张表(IO流) 03版本 就是使用xls结尾!
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03版本统计表.xls");

        //输出
        workbook.write(fileOutputStream);
        //关闭流
        fileOutputStream.close();

        System.out.println("03版本统计表.xls 生成完毕!");
    }
}
public class ExcelWriteTest {
     //07版本实现类 和03版本写在同一个类下
  //设置固定文件路径,与03相同
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;
    @Test //创建07版本
    public void testWrite07() throws Exception{
    

        // 1.创建一个工作簿
        Workbook workbook = new XSSFWorkbook();  //对象存在差别 XSSF
        // 2.创建一个工作表
        Sheet sheet = workbook.createSheet("guo2");  //sheet 名字为:guo1
        // 3.创建一个行 (1,1)
        Row row11 = sheet.createRow(0);  //第一行
        // 4. 创建一个单元格
        Cell cell11 = row11.createCell(0);  //第一行,第一列的格子(0,0)
        cell11.setCellValue("今日人数");  //设置值

        //(1,2)
        Row row12 = sheet.createRow(1);
        Cell cell12 = row12.createCell(0);
        cell12.setCellValue(666);

        // 第二行
        Row row2 = sheet.createRow(1);
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("统计时间");
        // (2,2)
        Cell cell22 = row2.createCell(1);
        String time = new DateTime().toString("yyyy-mm-dd HH:mm:ss");
        cell22.setCellValue(time);

        //生成一张表(IO流) 03版本 就是使用xlsx结尾! //这里存在差别
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07版本统计表.xlsx");

        //输出
        workbook.write(fileOutputStream);
        //关闭流
        fileOutputStream.close();

        System.out.println("07版本统计表.xlsx 生成完毕!")
    }
}

03与07差别只有文件后缀不同!

数据批量写入:大文件写入HSSF (03版)

缺点:最多只能处理65536行,否则会抛出异常

java.lang.11legalArgumentException : Invalid row number (65536) outside allowable range (0..65535)

优点:过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快。

 //设置固定文件路径,与03相同
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;
   
    @Test  //03大量数据
    public void testWrite03BigData() throws IOException {
    
        //时间差 begin 和 end 的差值
        long begin = System.currentTimeMillis();

        // 创建工作簿
        Workbook workbook = new HSSFWorkbook(); //03版本对象 HSSF
        // 创建工作表
        Sheet sheet = workbook.createSheet();
        // 写入数据
        for( int rowNum = 0; rowNum < 65536; rowNum++){
     //65537会报错
            Row row = sheet.createRow(rowNum);    // 行
            for (int cellNum = 0; cellNum <10; cellNum++){
      //这里设置了10列
                Cell cell = row.createCell(cellNum);   // 列
                cell.setCellValue(cellNum);  //循环65536行,每一行都是10列的数据
            }
        }
        //运行完毕,输出文件流
        System.out.println("over");
        FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite03BigDATA.xls" );
        workbook.write(outputStream);  //写入
        // 关闭流
        outputStream.close();
        //时间差
        long end = System.currentTimeMillis();
        //计算时间差,强制转换double,按秒来
        System.out.println((double)(end - begin)/1000);
    }

大文件写入HSSF (07版)

缺点: 写数据时速度非常慢,非常耗内存,可能会发生内存溢出,如100万条。
优点,可以写入较大的数据量,如20万条数据。

//设置固定文件路径,与03相同
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;

    @Test //07大数据读取 耗时较长
    public void testWrite07BigData() throws IOException {
    
        //时间差 begin 和 end 的差值
        long begin = System.currentTimeMillis();

        // 创建工作簿
        Workbook workbook = new XSSFWorkbook(); //07版本对象 XSSF
        // 创建工作表
        Sheet sheet = workbook.createSheet();
        // 写入数据
        for( int rowNum = 0; rowNum < 1000000; rowNum++){
    
            Row row = sheet.createRow(rowNum);    // 行
            for (int cellNum = 0; cellNum <10; cellNum++){
      //这里设置了10列
                Cell cell = row.createCell(cellNum);   // 列
                cell.setCellValue(cellNum);  //循环65536行,每一行都是10列的数据
            }
        }
        //运行完毕,输出文件流
        System.out.println("over");
        FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite07BigDATA.xlsx" );
        workbook.write(outputStream);  //写入
        // 关闭流
        outputStream.close();
        //时间差
        long end = System.currentTimeMillis();
        //计算时间差,强制转换double,按秒来
        System.out.println((double)(end - begin)/1000);
    }

大文件写SXSSF (比07版,速度更快)

优点:可以写非常大的数据量,如100万条甚至更多条,写数据速度快,占用更少的内存
注意:过程中会产生临时文件,需要清理临时文件
原理:默认由100条记录保存在内存中,如果超出这数量,则最前面的数据最前面的数据被写入临时文件,如果想自定义内存中的数据的数量,可以使用new SXSSFWorkbook(数量)
SXSSFWorkbook 来至官方的解释,实现“BigGridDemo“策略的流式XSSFWorkbook版本,这允许写入非常大的文件而不会耗尽内存,因为任何时候只有可配置的行部分被保存在内存中。
请注意,仍然可能会消耗大量内存,这些内存基于您正在使用的功能,例如合并区域,注释,仍然只能存储在内存中,因此如果广泛使用,可能需要大量内存。

//设置固定文件路径,与03相同
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;

    @Test  //07大数据读取 耗时短
    public void testWrite07BigDataS() throws IOException{
    
        //时间差 begin 和 end 的差值
        long begin = System.currentTimeMillis();

        // 创建工作簿
        Workbook workbook = new SXSSFWorkbook(); //07版本对象 XSSF
        // 创建工作表
        Sheet sheet = workbook.createSheet();
        // 写入数据
        for( int rowNum = 0; rowNum < 100000; rowNum++){
    
            Row row = sheet.createRow(rowNum);    // 行
            for (int cellNum = 0; cellNum <10; cellNum++){
      //这里设置了10列
                Cell cell = row.createCell(cellNum);   // 列
                cell.setCellValue(cellNum);  //循环65536行,每一行都是10列的数据
            }
        }
        //运行完毕,输出文件流
        System.out.println("over");
        FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite07BigDATAS.xlsx" );
        workbook.write(outputStream);  //写入
        // 关闭流
        outputStream.close();
        
        //清除临时文件!
        ((SXSSFWorkbook)workbook).dispose();
        
        //时间差
        long end = System.currentTimeMillis();
        //计算时间差,强制转换double,按秒来
        System.out.println((double)(end - begin)/1000);
    }

POI-Excel 读

// workbook 代表工作簿,使用excel能操作的功能,workbook都可以操作
workbook.createCellStyle();//创建样式
workbook.createName();//创建名称
workbook.findFont();//找内容
workbook.getAllPictures();//得到一些图片
workbook.isHidden();//隐藏
workbook.removeName();//移除名字


//sheet 代表表中的设置 使用excel表能操作的功能,sheet都可以操作
sheet.createRow();//创建行
sheet.autoSizeColumn();//列的大小
sheet.getColumnWidth();//列的宽度
sheet.getDefaultRowHeightInPoints();//行间距

03版本,读数据:

 @Test//03版本读数据
    public void testRead03() throws Exception{
    

        //获取文件流
        FileInputStream inputStream =  new FileInputStream(PATH +"guo_poi03版本统计表.xls");

        // 1.创建一个工作簿 使用excel能操作的功能,workbook都可以操作
        Workbook workbook = new HSSFWorkbook(inputStream); // 流获取到工作簿
        // 2.得到表 表中的设置 
        Sheet sheet = workbook.getSheetAt(0); //拿去 get方法
        // 3.得到行
        Row row = sheet.getRow(0);   //得到第一行
        // 4.得到列
        Cell cell  = row.getCell(0); //得到第一列
        
        //读取值时需要类型判断!
        // 获得字符串
        System.out.println(cell.getStringCellValue());  //字符串类型 
                                                        //cell.getNumericCellValue()获取数字
        // 关闭流
        inputStream.close();
    }

07版本,读数据:

@Test  //07版本读数据
    public void testRead07() throws Exception{
    
        //获取文件流
        FileInputStream inputStream =  new FileInputStream(PATH +"guo_poi07版本统计表.xlsx");

        // 1.创建一个工作簿 使用excel能操作的功能,workbook都可以操作
        Workbook workbook = new XSSFWorkbook(inputStream); // 流获取到工作簿
        // 2.得到表 表中的设置
        Sheet sheet = workbook.getSheetAt(0); //拿去 get方法
        // 3.得到行
        Row row = sheet.getRow(0);   //得到第一行
        // 4.得到列
        Cell cell  = row.getCell(0); //得到第一列
        //读取值时需要类型判断!
        // 获得字符串
        System.out.println(cell.getNumericCellValue()); //获取数字
        // 关闭流
        inputStream.close();
    }

注意获取值的类型;

读取不同数据类型:(最麻烦)注意类型转换

 @Test //测试类型
    public void testCellType() throws Exception{
    
        //获取文件流
        FileInputStream inputStream =  new FileInputStream(PATH +"会员消费商品明细表.xls");

        // 创建一个工作簿 使用excel能操作的这边都可以操作
        Workbook workbook = new HSSFWorkbook(inputStream);  //03版本
        //获取表
        Sheet sheet = workbook.getSheetAt(0);
        //获取标题内容
        Row rowTitle = sheet.getRow(0); //最上面一行
        if(rowTitle != null){
    
            //一定要掌握 拿到所有的列
            int cellCount = rowTitle.getPhysicalNumberOfCells(); // 获取所有列数据,总数 比如:13个列
            for (int cellNum = 0; cellNum < cellCount;cellNum++){
    
                Cell cell = rowTitle.getCell(cellNum);
                if (cell != null){
    
                    CellType cellType = cell.getCellType(); //取出数据的类型
                    String cellValue = cell.getStringCellValue(); //获取数据 该数据是string 字符串类型
                    System.out.print(cellValue + "|"); //把数据打印出来,输出时不换行
                }
            }
            System.out.println();
        }

        //获取表中的内容
         int rowCount = sheet.getPhysicalNumberOfRows(); //获取所有的行 getPhysicalNumberOfCells()获取所有列
        for( int rowNum = 1;rowNum< rowCount;rowNum++){
    
            Row rowData = sheet.getRow(rowNum);
            if(rowData != null){
      //判空
                //读取列
                int cellCoumt = rowTitle.getPhysicalNumberOfCells();
                for (int cellNum = 0;cellNum < cellCoumt ; cellNum++){
    
                    System.out.print("["+(rowNum+1)+"-"+(rowNum+1)+"]");
                    Cell cell = rowData.getCell(cellNum);
                    // 匹配列的数据类型
                    if(cell != null){
    
                        CellType cellType = cell.getCellType();
                        String cellValue = "";

                        switch(cellType){
    
                            case STRING: //字符串类型
                                System.out.print("[String]");
                                cellValue = cell.getStringCellValue();
                                break;
                            case BOOLEAN: //布尔类型
                                System.out.print("[BOOLEAN]");
                                cellValue = String.valueOf(cell.getBooleanCellValue());
                                break;
                            case BLANK: //空
                                System.out.print("[BLANK]");
                                break;
                            case _NONE:
                                System.out.print("[NONE]");
                                break;
                            case NUMERIC: //数字(日期、普通数字)
                                System.out.print("[NUMERIC]");
                                if(DateUtil.isCellInternalDateFormatted(cell)) {
     //日期
                                    System.out.print("[日期]");
                                    Date date = cell.getDateCellValue();
                                    cellValue = new DateTime(date).toString("yyyy-MM-dd");
                                }else{
    
                                    //不是日期格式,防止数字过长!
                                    System.out.print("[转换为字符串输出]");
                                    cellValue = cell.toString();
                                }
                                break;
                            case ERROR: //错误
                                System.out.print("【数据类型错误】");
                                break;
                        }
                        System.out.println(cellValue);
                    }

                }
            }
        }
        inputStream.close(); //关闭流
      }
 @Test //测试类型 提取成工具类
    public void testCellType(FileInputStream inputStream) throws Exception{
    

        // 创建一个工作簿 使用excel能操作的这边都可以操作
        Workbook workbook = new HSSFWorkbook(inputStream);  //03版本
        //获取表
        Sheet sheet = workbook.getSheetAt(0);
        //获取标题内容
        Row rowTitle = sheet.getRow(0); //最上面一行
        if(rowTitle != null){
    
            //一定要掌握 拿到所有的列
            int cellCount = rowTitle.getPhysicalNumberOfCells(); // 获取所有列数据,总数 比如:13个列
            for (int cellNum = 0; cellNum < cellCount;cellNum++){
    
                Cell cell = rowTitle.getCell(cellNum);
                if (cell != null){
    
                    CellType cellType = cell.getCellType(); //取出数据的类型
                    String cellValue = cell.getStringCellValue(); //获取数据 该数据是string 字符串类型
                    System.out.print(cellValue + "|"); //把数据打印出来,输出时不换行
                }
            }
            System.out.println();
        }

        //获取表中的内容
        int rowCount = sheet.getPhysicalNumberOfRows(); //获取所有的行 getPhysicalNumberOfCells()获取所有列
        for( int rowNum = 1;rowNum< rowCount;rowNum++){
    
            Row rowData = sheet.getRow(rowNum);
            if(rowData != null){
      //判空
                //读取列
                int cellCoumt = rowTitle.getPhysicalNumberOfCells();
                for (int cellNum = 0;cellNum < cellCoumt ; cellNum++){
    
                    System.out.print("["+(rowNum+1)+"-"+(rowNum+1)+"]");
                    Cell cell = rowData.getCell(cellNum);
                    // 匹配列的数据类型
                    if(cell != null){
    
                        CellType cellType = cell.getCellType();
                        String cellValue = "";

                        switch(cellType){
    
                            case STRING: //字符串类型
                                System.out.print("[String]");
                                cellValue = cell.getStringCellValue();
                                break;
                            case BOOLEAN: //布尔类型
                                System.out.print("[BOOLEAN]");
                                cellValue = String.valueOf(cell.getBooleanCellValue());
                                break;
                            case BLANK: //空
                                System.out.print("[BLANK]");
                                break;
                            case _NONE:
                                System.out.print("[NONE]");
                                break;
                            case NUMERIC: //数字(日期、普通数字)
                                System.out.print("[NUMERIC]");
                                if(DateUtil.isCellInternalDateFormatted(cell)) {
     //日期
                                    System.out.print("[日期]");
                                    Date date = cell.getDateCellValue();
                                    cellValue = new DateTime(date).toString("yyyy-MM-dd");
                                }else{
    
                                    //不是日期格式,防止数字过长!
                                    System.out.print("[转换为字符串输出]");
                                    cellValue = cell.toString();
                                }
                                break;
                            case ERROR: //错误
                                System.out.print("【数据类型错误】");
                                break;
                        }
                        System.out.println(cellValue);
                    }

                }
            }
        }
        inputStream.close(); //关闭流
    }

读取并计算公式:

表格样式:
表格样式

 @Test //公式
    public void testFormula() throws Exception{
    
        //获取文件流
        FileInputStream inputStream =  new FileInputStream(PATH +"公式.xls");
        // 创建一个工作簿 使用excel能操作的这边都可以操作
        Workbook workbook = new HSSFWorkbook(inputStream);  //03版本
        //获取表
        Sheet sheet = workbook.getSheetAt(0);
        //获取第五行
        Row row = sheet.getRow(4);
        //获取第一列
        Cell cell = row.getCell(0);
        
        //拿到计算公式 eval函数 通过它来计算
        FormulaEvaluator formulaEvaluator =  new HSSFFormulaEvaluator((HSSFWorkbook)workbook);
        
        //输出单元格内容
        CellType cellType = cell.getCellType();
        switch (cellType){
    
            case FORMULA: //公式类型 需要和公式类型匹配,如果不匹配不会进入方法的
                String formula = cell.getCellFormula(); 
                System.out.println(formula);
                
                //计算
                CellValue evaluate = formulaEvaluator.evaluate(cell); // 用evaluate(cell)方法计算
                String cellValue = evaluate.formatAsString();//计算结果,列的值,格式化成字符串来输出
                System.out.println(cellValue); //输出结果
                break;
        }
    }

EasyExcel

EasyExcel:快速、简洁、解决大文件内存溢出的java处理Excel工具

POI一般底层仍会使用,弊端就是当数据量大的时候会报OOM异常,相比较POI相对简单一些!

EasyExcel :
EasyExcel官方地址:https://github.com/alibaba/easyexcel

官方简介:
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便

GitHub EasyExcel :
EasyExcel

官方文档:

官方文档:https://www.yuque.com/easyexcel/doc/easyexcel

EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存存储著称
EasyExcel 能大大减少占用内存的主要原因是在解析Excel是没有将数据一次性全部加载到内存中,而且是从磁盘上一行行读取数据,逐个解析。
内存问题:POI = 100w先加载到内存中(十分耗内存)再一次性写入文件中,当内存不够时可能会报OOM。而EasyExcel在写入文件中是通过磁盘一行一行读取的。
下图是EasyExcel和POI在解析Excel时的对比图。

官方文档:关于

pom.xml 依赖

  <!-- 导入easyexcel依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.5</version>
        </dependency>
       

        <!-- 可能需要导入的其他依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

实体类:EasyExcel会根据实体类自动生成表

表

package easy;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

@Data
public class DemoData {
    
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /** * 忽略这个字段 */
    @ExcelIgnore
    private String ignore;
}

实现类:写数据

package easy;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.ListUtils;
import org.junit.Test;

import java.util.Date;
import java.util.List;

public class TestExcel {
    

    String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/" ;//设置固定文件路径

    //自动生成10个随机数,再把随机数放入list
    private List<DemoData> data() {
       //实体类加载过来
        List<DemoData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
    
            DemoData data = new DemoData();
            //设初值,返回到list中
            data.setString("字符串" + i);  
            data.setDate(new Date());
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

    //根据list 写入excel
    /** * 最简单的写 * <p> * 1. 创建excel对应的实体对象 参照{@link DemoData} * <p> * 2. 直接写即可 */
    @Test
    public void simpleWrite() {
    
        // 注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入

        // 最简单写法 JDK8+ 其余写法官方文档上都有
        String fileName = PATH  + "dataEasyTest.xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // write.(fileName,格式类) 格式类会根据注释自动生成表的属性
        // sheet("表名") 生成表的方法
        //dowrite.(数据) 写入数据 从前端或者数据库读取的数据
        EasyExcel.write(fileName, DemoData.class) //filename 数据流,DemoData.class 对应实体 标题生成
                .sheet("模板") //生成一个sheet为模版的表
                .doWrite(data());//dowrite(数据)
             //data() 这里就是写了一个简单的生成随机数,真实情况是从前端返过来或数据库中读取出来的一个list,绑定mapper就行
    }    
                    
}

成功运行:可以看到生成了dataEasyExcel.xlsx
实现
生成的数据
请添加图片描述

实现类:读数据

 //只写了方法,该方法也放在TestExcel中
    /** * 最简单的读 * <p> * 1. 创建excel对应的实体对象 参照{@link DemoData} * <p> * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} * <p> * 3. 直接读即可 */
    @Test
    public void simpleRead() {
    

        // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
        // 最简单写法 JDK8+ 其余写法官方文档上都有
        String fileName = PATH  + "dataEasyExcel.xlsx";
        // 这里 需要指定读哪个文件,用哪个class按格式输出,通过DemoDataListener监视器去判断逻辑然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
    }

持久层:DAO

package easy;

import java.util.List;

/** * 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。 **/
public class DemoDAO {
    
    public void save(List<DemoData> list) {
    
        //持久化操作,保存数据库!
        // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
    }
}

DemoDataListener:

package easy;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener extends AnalysisEventListener<DemoData> {
    

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);

    /** * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */
    private static final int BATCH_COUNT = 5;
    private List<DemoData> list = new ArrayList<DemoData>();

    //sprin 需要注入时使用
    /** * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 */
    private DemoDAO demoDAO;

    public DemoDataListener() {
    
        // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
        demoDAO = new DemoDAO();
    }

    /** * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 * * @param demoDAO */
    public DemoDataListener(DemoDAO demoDAO) {
    
        this.demoDAO = demoDAO;
    }


    //读取数据时会执行 invoke 方法
    // 读入
    // DemoData 类型
    // AnalysisContext 分析器 用来分析上下文
    /** * 这个每一条数据解析都会来调用 invoke 方法 * * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()} * @param context */
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
    
        //fastjson 导入Maven依赖
        System.out.println(JSON.toJSONString(data));  //读取到的每一条数据都会变成 JSON字符串
        list.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
    
            saveData(); //保存数据库 这里是空的
            // 存储完成清理 list
            list.clear();
        }
    }

    /** * 所有数据解析完成了 都会来调用 * * @param context */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
    
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成!");
    }

    /** * 加上存储数据库 */
    private void saveData() {
    
        log.info("{}条数据,开始存储数据库!", list.size());
        demoDAO.save(list);
        log.info("存储数据库成功!");
    }
}

读出数据
固定套路:

1. 写入,固定类格式的进行写入!
2. 读取,根据监听器设置的规则进行读取!
一切代码都在官方文档

官方文档:
官方文档:https://www.yuque.com/easyexcel/doc/easyexcel

版权声明
本文为[.G( );]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_45048331/article/details/124355610