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 ExcelReaderBuilder
与ExcelWriterBuilder
ExcelReaderBuilder
与ExcelWriterBuilder
用于创建ReadWorkbook
与WriteWorkbook
,可以理解为用于构建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 ExcelReaderSheetBuilder
与ExcelWriterSheetBuilder
ExcelReaderSheetBuilder
与ExcelWriterSheetBuilder
用于创建ExcelReader
和ExcelWriter
类,可以理解为创建Excel的工作表。
2.3.1 ExcelReaderSheetBuilder
- 设置
ReadSheet
属性
方法 | 参数 | 返回值 | 描述 |
---|---|---|---|
ExcelReaderSheetBuilder() | \\ | \\ | 构造函数,用于创建ReadSheet |
ExcelReaderSheetBuilder(ExcelReader excelReader) | ExcelReader excelReader | \\ | 构造函数,用于创建ReadSheet 和ExcelReader |
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 | \\ | 构造函数,用于创建WriteSheet 和ExcelWriter |
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 ExcelReader
与ExcelWriter
该类用于提供读和写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
注解避免将错误的至赋给实体类。
对于一些需要进行数据类型转换或格式化的属性可以使用@ExcelProperty
的converter
指定转换的实体类,对于时间格式可以使用@DateTimeFormat
注解对时间类型数据进行格式化,对于数值型可以使用@NumberFormat
注解格式化数值型,例如@NumberFormat("#.##%")
将值转为百分比。
也可以重写
ExcelReaderBuilder
继承自AbstractExcelReaderParameterBuilder
类的registerReadListener
方法,使用该方法后会对实体类虽有符合的属性进行转化,不如注解的形式灵活。
3.1.2 读取单元格的额外属性(超链接、批注、合并单元格信息)
除了对简单数据表读取功能外,EasyExcel还支持读取合并单元格、超链接、批注的信息读取。调用ExcelReaderBuilder
的extraRead()
方法设置要获取的属性。通过调用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.以上是关于JavaEasyExcel使用方法的主要内容,如果未能解决你的问题,请参考以下文章