JavaEasyExcel使用方法

Posted Do_GH

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaEasyExcel使用方法相关的知识,希望对你有一定的参考价值。

文章目录

一、 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模式,在上层做了模型转换的封装,让使用者更加简单方便。

二、 EasyExcel核心类简述

2.1 EasyExcel

EasyExcel继承自EasyExcelFactory工厂类,是EasyExcel的入口类,用于构建读和写的方法,通过不同的参数可以实现不同方式读写文件。EasyFactory用于实现具体的方法。

调用EasyExcel类的静态方法read(),通过传入不同的参数实现不同方式读取数据,较为常用的是read(String pathName, Class head, ReadListener readListener)方法,参数pathName为要读取文件的文件路径,参数head为参照该实体类读取数据,参数readListener为在读取数据时所执行的监听器。返回值为ExcelReaderBuilder类。

其他读取Excel的方法:

方法参数返回值
read()ExcelReaderBuilder
read(File file)file 待读取文件ExcelReaderBuilder
read(File file, ReadListener readListener)file 待读取文件
readListener 监听器
ExcelReaderBuilder
read(File file, Class head, ReadListener readListener)file 读取文件
head 按照实体类读取数据
readListener 监听器
ExcelReaderBuilder
read(String pathName)pathName 待读取文件路径ExcelReaderBuilder
read(String pathName, ReadListener readListener)pathName 待读取文件路径
readListener 监听器
ExcelReaderBuilder
read(String pathName, Class head, ReadListener readListener)pathName 待读取文件路径
head 按照实体类读取数据
readListener 监听器
ExcelReaderBuilder
read(InputStream inputStream)inputStream 待读取文件文件流ExcelReaderBuilder
read(InputStream inputStream, ReadListener readListener)inputStream 待读取文件文件流
readListener 监听器
ExcelReaderBuilder
read(InputStream inputStream, Class head, ReadListener readListener)inputStream 待读取文件文件流
head 按照实体类读取数据
readListener 监听器
ExcelReaderBuilder

调用EasyExcel类的静态方法write(),通过传入不同的参数实现不同方式读取数据,较为常用的是write(String pathName, Class head)方法,参数pathName为要读取文件的文件路径,参数head为参考该实体类导出数据。返回值为ExcelWriterBuilder类。

其他写Excel方法:

方法参数返回值
write()ExcelWriterBuilder
write(File file)file 待输出文件ExcelWriterBuilder
write(File file, Class head)file 待输出文件
head 按照实体类输出数据
ExcelWriterBuilder
write(String pathName)pathName 待输出文件路径ExcelWriterBuilder
write(String pathName, Class head)pathName 待输出文件路径
head 按照实体类输出数据
ExcelWriterBuilder
write(OutputStream outputStream)inputStream 待输出文件文件流ExcelWriterBuilder
write(OutputStream outputStream, Class head)inputStream 待输出文件文件流
head 按照实体类输出数据
ExcelWriterBuilder

ExcelReaderBuilder提供读取Excel文件数据的读取方式以及一些工作簿属性的设置。

2.2 ExcelReaderBuilderExcelWriterBuilder

ExcelReaderBuilderExcelWriterBuilder用于创建ReadWorkbookWriteWorkbook,可以理解为用于构建Excel的文件。

2.2.1 ExcelReaderBuilder

  • 设置ReadWorkbook属性
方法参数返回值描述
ExcelReaderBuilder()//ExcelReaderBuilder类的构造方法,同时创建ReadWorkbook的实体类
excelType(ExcelTypeEnum excelType)excelType Excel类型(枚举类型)ExcelReaderBuilder设置Excel的文件类型,明确读取的是xls、xlsx还是cvs文件
autoCloseStream(Boolean autoCloseStream)autoCloseStream 是否自动关闭流(布尔类型)ExcelReaderBuilder设置读取完毕后是否自动关闭流,默认为自动关闭
ignoreEmptyRow(Boolean ignoreEmptyRow)ignoreEmptyRow 是否忽略空行(布尔类型)ExcelReaderBuilder设置是否忽略空行,默认自动忽略
extraRead(CellExtraTypeEnum extraType)extraType 单元格属性类型(枚举类型)ExcelReaderBuilder读取单元格的批注、超链接和合并单元格属性

  • 创建ExcelReader

ExcelReader作为EasyExcel的核心实现类,用于实现文件的读取,调用build()方法会返回一个ExcelReader对象,并传入设置好的readWorkbook属性。

public ExcelReader build() 
	return new ExcelReader(readWorkbook);


  • 创建ExcelReaderSheetBuilder

如果是指定读取某个工作簿的内容,可以先调用sheet()方法设置当前需要读取的是第几个工作簿或指定工作簿的名称。不指定参数则获取所有工作簿的内容。在调用ExcelReaderSheetBuilder类的doRead()doReadSync()方法读取数据。

方法参数返回值
sheet()/ExcelReaderSheetBuilder
sheet(Integer sheetNo)sheetNo 工作簿序号(从0开始)ExcelReaderSheetBuilder
sheet(String sheetName)sheetName 工作簿名称ExcelReaderSheetBuilder
sheet(Integer sheetNo, String sheetName)sheetNo 工作簿序号(从0开始)
sheetName 工作簿名称
ExcelReaderSheetBuilder

  • 读取数据

若需要读取全部工作簿的数据,可以直接调用doReadAll()方法。

public void doReadAll() 
    ExcelReader excelReader = build();
    excelReader.readAll();
    excelReader.finish();

如果需要将结果拿出来再处理,可以调用doReadAllSync()方法,可以返回List<T>对应的泛型集合。

public <T> List<T> doReadAllSync() 
    SyncReadListener syncReadListener = new SyncReadListener();
    registerReadListener(syncReadListener);
    ExcelReader excelReader = build();
    excelReader.readAll();
    excelReader.finish();
    return (List<T>)syncReadListener.getList();

2.2.2 ExcelWriterBuilder

  • 设置WriteWorkbook属性
方法参数返回值描述
ExcelWriterBuilder()//ExcelWriterBuilder类的构造方法,同时创建WriteWorkbook的实体类
excelType(ExcelTypeEnum excelType)excelType Excel类型(枚举类型)ExcelWriterBuilder设置Excel的文件类型,明确读取的是xls、xlsx还是cvs文件
autoCloseStream(Boolean autoCloseStream)autoCloseStream 是否自动关闭流(布尔类型)ExcelWriterBuilder设置读取完毕后是否自动关闭流,默认为自动关闭
inMemory(Boolean inMemory)inMemory 是否在内存中运行ExcelWriterBuilder设置是否将数据读取到内存中,默认为false

  • 创建ExcelWriter

ExcalWriter作为EasyExcel写文件的核心类,用于实现输出Excel,可以调用ExcelWriterBuilder类的build()方法创建ExcalWriter类,并将设置好的writeWorkbook。示例:

public ExcelWriter build() 
    return new ExcelWriter(writeWorkbook);


  • 创建ExcelWriterSheetBuilder

调用ExcelWriterBuilder类的sheet()方法,用于设置将该数据流写入文件的那个工作簿,并设置工作簿的名称

方法参数返回值
sheet()/ExcelWriterSheetBuilder
sheet(Integer sheetNo)sheetNo 工作簿序号(从0开始)ExcelWriterSheetBuilder
sheet(String sheetName)sheetName 工作簿名称ExcelWriterSheetBuilder
sheet(Integer sheetNo, String sheetName)sheetNo 工作簿序号(从0开始)
sheetName 工作簿名称
ExcelWriterSheetBuilder

如果不设置工作簿名称,则输出在第一个工作簿并且工作簿名称为0

  • 输出文件

调用ExcelWriter类的write(Collection<?> data, WriteSheet writeSheet, WriteTable writeTable)方法,参数data为需要输出的数据集合,参数writeSheet为需要写入的工作簿信息,参数writeTable为写入的table(若不同的几组数据写入同一个工作簿可以创建多个WriteTable,可以为空)。

public ExcelWriter write(Collection<?> data, WriteSheet writeSheet, WriteTable writeTable) 
    excelBuilder.addContent(data, writeSheet, writeTable);
    return this;

2.3 ExcelReaderSheetBuilderExcelWriterSheetBuilder

ExcelReaderSheetBuilderExcelWriterSheetBuilder用于创建ExcelReaderExcelWriter类,可以理解为创建Excel的工作表。

2.3.1 ExcelReaderSheetBuilder

  • 设置ReadSheet属性
方法参数返回值描述
ExcelReaderSheetBuilder()\\\\构造函数,用于创建ReadSheet
ExcelReaderSheetBuilder(ExcelReader excelReader)ExcelReader excelReader\\构造函数,用于创建ReadSheetExcelReader
sheetNo(Integer sheetNo)Integer sheetNo 工作表序号,从0开始ExcelReaderSheetBuilder用于设置读取哪个工作表
sheetName(String sheetName)String sheetName 工作表名称ExcelReaderSheetBuilder用于设置读取哪个工作表

  • 获取ReadSheet对象

调用build()方法,可以返回ReadSheet属性。

public ReadSheet build() 
    return readSheet;


  • 读取文件
/**
 * Sax read
 */
public void doRead() 
    if (excelReader == null) 
        throw new ExcelGenerateException("Must use 'EasyExcelFactory.read().sheet()' to call this method");
    
    excelReader.read(build());
    excelReader.finish();


/**
 * Synchronous reads return results
 *
 * @return
 */
public <T> List<T> doReadSync() 
    if (excelReader == null) 
        throw new ExcelAnalysisException("Must use 'EasyExcelFactory.read().sheet()' to call this method");
    
    SyncReadListener syncReadListener = new SyncReadListener();
    registerReadListener(syncReadListener);
    excelReader.read(build());
    excelReader.finish();
    return (List<T>)syncReadListener.getList();

2.3.2 ExcelWriterSheetBuilder

  • 设置WriteSheet属性
方法参数返回值描述
ExcelWriterSheetBuilder()\\\\构造函数,用于创建WriteSheet
ExcelWriterSheetBuilder(ExcelWriter excelWriter)ExcelWriter excelWriter\\构造函数,用于创建WriteSheetExcelWriter
sheetNo(Integer sheetNo)Integer sheetNo 工作表序号ExcelWriterSheetBuilder设置工作表
sheetName(String sheetName)String sheetName 工作表名称ExcelWriterSheetBuilder设置工作表
  • 创建WriteSheet对象

调用build()方法,可以返回WriteSheet属性。

public WriteSheet build() 
    return writeSheet;

  • 创建文件

使用doWrite()方法可以向文件直接填充数据

public void doWrite(Collection<?> data) 
    if (excelWriter == null) 
        throw new ExcelGenerateException("Must use 'EasyExcelFactory.write().sheet()' to call this method");
    
    excelWriter.write(data, build());
    excelWriter.finish();


public void doWrite(Supplier<Collection<?>> supplier) 
    doWrite(supplier.get());


使用doFill()方法可以根据模板向文件填充数据

public void doFill(Object data) 
    doFill(data, null);


public void doFill(Object data, FillConfig fillConfig) 
    if (excelWriter == null) 
        throw new ExcelGenerateException("Must use 'EasyExcelFactory.write().sheet()' to call this method");
    
    excelWriter.fill(data, fillConfig, build());
    excelWriter.finish();


public void doFill(Supplier<Object> supplier) 
    doFill(supplier.get());


public void doFill(Supplier<Object> supplier, FillConfig fillConfig) 
    doFill(supplier.get(), fillConfig);

2.4 ExcelReaderExcelWriter

该类用于提供读和写Excel的实现方法

2.4.1 ExcelReader

方法参数描述
ExcelReader(ReadWorkbook readWorkbook)ReadWorkbook readWorkbook构造函数,用于创建ExcelAnalyser
readAll()\\读取所有工作表的数据
read(ReadSheet... readSheet)ReadSheet... readSheet读取指定的工作表
read(List<ReadSheet> readSheetList)List<ReadSheet> readSheetList读取指定的工作表

2.4.2 ExcelWriter

方法参数描述
ExcelWriter(WriteWorkbook writeWorkbook)WriteWorkbook writeWorkbook构造函数,用于创建ExcelBuilder
write(Collection<?> data, WriteSheet writeSheet)Collection<?> data 数据集
WriteSheet writeSheet 写工作表类
导出Excel文件
write(Collection<?> data, WriteSheet writeSheet, WriteTable writeTable)Collection<?> data 数据集
WriteSheet writeSheet 写工作表类
WriteTable writeTable 若为多个数据集写入一个表可以创建WriteTable分区导出
导出Excel文件
fill(Object data, WriteSheet writeSheet)Object data 数据集
WriteSheet writeSheet
使用模板填充数据
fill(Object data, FillConfig fillConfig, WriteSheet writeSheet)Object data 数据集
FillConfig fillConfig 填充配置
WriteSheet writeSheet
使用模板填充数据

三、示例

3.1 读

3.1.1 简单读取数据

为避免一次性读取过量数据导致内存崩溃,可以自己实现ReadListener接口分批读取数据,并在读取过程中进行数据处理(存储数据库等)操作。

实现示例:

@Test
public void simpleRead() 
    // 写法1:JDK8+ ,不用额外写一个DemoDataListener
    // since: 3.0.0-beta1
    String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
    // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
    // 这里每次会读取3000条数据 然后返回过来 直接调用使用数据就行
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener<DemoData>()).sheet().doRead();

如果是自己实现ReadListener类需要注意该实现类无法被Spring管理,同时也无法使用注解创建对象,所以可以定义一个私有属性通过构造函数将Spring管理的类传入

package com.alibaba.easyexcel.test.demo.read;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 模板的读取类
 *
 * @author Jiaju Zhuang
 */
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class DemoDataListener extends AnalysisEventListener<DemoData> 
    private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
    /**
     * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 3000;
    /**
     * 缓存的数据
     */
    private List<DemoData> list = new ArrayList<>(BATCH_COUNT);
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private DemoDAO demoDAO;

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

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as @link AnalysisContext#readRowHolder()
     * @param context
     */
    @Override
    public void invoke(DemoData data, AnalysisContext context) 
        LOGGER.info("解析到一条数据:", JSON.toJSONString(data));
        list.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) 
            saveData();
            // 存储完成清理 list
            list = new ArrayList<>(BATCH_COUNT);
        
    

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

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

对于Excel读取出来对应的实体类,如果不加注解会按照顺序对应实体类的属性,即第一列数据对应第一个属性依次类推。如果需要进行数据表与属性的绑定则需在实体类的属性上添加注解@ExcelProperty。该注解有两个参数,@value为属性与数据表的列名绑定,@index将属性与数据表的列数绑定,对于其他不需要绑定数据的属性可以添加@ExcelIgnore注解避免将错误的至赋给实体类。

对于一些需要进行数据类型转换或格式化的属性可以使用@ExcelPropertyconverter指定转换的实体类,对于时间格式可以使用@DateTimeFormat注解对时间类型数据进行格式化,对于数值型可以使用@NumberFormat注解格式化数值型,例如@NumberFormat("#.##%")将值转为百分比。

也可以重写ExcelReaderBuilder继承自AbstractExcelReaderParameterBuilder类的registerReadListener方法,使用该方法后会对实体类虽有符合的属性进行转化,不如注解的形式灵活。

3.1.2 读取单元格的额外属性(超链接、批注、合并单元格信息)

除了对简单数据表读取功能外,EasyExcel还支持读取合并单元格、超链接、批注的信息读取。调用ExcelReaderBuilderextraRead()方法设置要获取的属性。通过调用DemoExtraListener类重写的extra()获取读取的额外属性。示例:

@Test
public void extraRead() 
    String fileName = TestFileUtil.getPath() + "demo" + File.separator + "extra.xlsx";
    // 这里 需要指定读用哪个class去读,然后读取第一个sheet
    EasyExcel.read(fileName, DemoExtraData.class, new DemoExtraListener())
        // 需要读取批注 默认不读取
        .extraRead(CellExtraTypeEnum.COMMENT)
        // 需要读取超链接 默认不读取
        .extraRead(CellExtraTypeEnum.HYPERLINK)
        // 需要读取合并单元格信息 默认不读取
        .extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();

3.1.3 读取文件中的异常处理

在实际应用过程中,我们无法保证用户填写的文件百分百准确。所以在读取到无法解析的数据时需要做容错处理,对异常数据进行抛出。可以在监听器中调用onException()方法处理无法处理的数据。示例:

@Test
public void exceptionRead() 
    String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
    // 这里 需要指定读用哪个class去读,然后读取第一个sheet
    EasyExcel.read(fileName, ExceptionDemoData.class, new DemoExceptionListener()).sheet().doRead();

@Data
public class ExceptionDemoData 
    /**
     * 用日期去接字符串 肯定报错
     */
    private Date date;

package com.alibaba.easyexcel.test.demo.read;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.fastjson.JSON;

/**
 * 读取转换异常
 *
 * @author Jiaju Zhuang
 */
public class DemoExceptionListener extends AnalysisEventListener<ExceptionDemoData> 
    private static final Logger LOGGER = LoggerFactory.getLogger(DemoExceptionListener.class以上是关于JavaEasyExcel使用方法的主要内容,如果未能解决你的问题,请参考以下文章

JavaEasyExcel使用方法

想必大家在做参数验证的时候,都会遇到一个问题,就是如何验证枚举? 自定义annotation 自定义Validator

安装proe5.0之后,总是会出现错误日志,但还可以使用。就是每次打开也都会产生一个附带的日志???

使用手机地图时,比如搜狗地图、百度地图,都会出现“ERR:Network creat fail” ,这个是由于啥原因呢?

javascript做j简单的开关灯 就是两个按钮 按一下按钮整个页面都会变蓝 按另一个按钮 整个页面都胡变黑的

Dubbo面试18问!这些你都会吗?