EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单,节省内存著称,EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
相对于poi个人感觉更加轻量与简捷,很容易上手,并且操作简单。
1.首先依然是导入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>版本</version>
</dependency>
<!--xls-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>版本</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>版本</version>
</dependency>
2.创建实体类
这里EasyExcel与poi的区别在于,提供了很多注解,可以更加方便灵活的配置字段,常用的注解有:
ExcelProperty
index 指定写到第几列,默认根据成员变量排序。value
指定写入的名称,默认成员变量的名字,多个value
可以参照快速开始中的复杂头
ExcelIgnore
默认所有字段都会写入excel,这个注解会忽略这个字段
DateTimeFormat
日期转换,将Date
写到excel会调用这个注解。里面的value
参照java.text.SimpleDateFormat
NumberFormat
数字转换,用Number
写excel会调用这个注解。里面的value
参照java.text.DecimalFormat
ExcelIgnoreUnannotated
默认不加ExcelProperty
的注解的都会参与读写,加了不会参与
写表格的例子:
@Data
public class DemoData {
//设置excel表头名称
@ExcelProperty(value = "学号",index = 0)
private Integer numbers;
@ExcelProperty(value = "姓名",index = 1)
private String name;
}
执行方法:
public class Test {
public static void main(String[] args) {
//实现excel写的操作
//1 设置写入文件夹地址和excel文件名称
String filename = "D:\\test.xlsx";
// 2 调用easyexcel里面的方法实现写操作
// write方法两个参数:第一个参数文件路径名称,第二个参数实体类class
EasyExcel.write(filename,DemoData.class).sheet("输出表").doWrite(getData());
}
//创建方法返回list集合
private static List<DemoData> getData() {
List<DemoData> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();
data.setNumbers(100+i);
data.setName("学生"+i);
list.add(data);
}
return list;
}
}
效果图:
读和写的注解类似,有如下注解:
ExcelProperty
指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。
ExcelIgnore
默认所有字段都会和excel去匹配,加了这个注解会忽略该字段
DateTimeFormat
日期转换,用String
去接收excel日期格式的数据会调用这个注解。里面的value
参照java.text.SimpleDateFormat
NumberFormat
数字转换,用String
去接收excel数字格式的数据会调用这个注解。里面的value
参照java.text.DecimalFormat
ExcelIgnoreUnannotated
默认不加ExcelProperty
的注解的都会参与读写,加了不会参与
通用参数
WriteWorkbook
,WriteSheet
,WriteTable
都会有的参数,如果为空,默认使用上级。
converter
转换器,默认加载了很多转换器。也可以自定义。
writeHandler
写的处理器。可以实现WorkbookWriteHandler
,SheetWriteHandler
,RowWriteHandler
,CellWriteHandler
,在写入excel的不同阶段会调用
relativeHeadRowIndex
距离多少行后开始。也就是开头空几行
needHead
是否导出头
head
与clazz
二选一。写入文件的头列表,建议使用class。
clazz
与head
二选一。写入文件的头对应的class,也可以使用注解。
autoTrim
字符串、表头等数据自动trim
WriteWorkbook(理解成excel对象)参数
excelType
当前excel的类型 默认xlsx
outputStream
与file
二选一。写入文件的流
file
与outputStream
二选一。写入的文件
templateInputStream
模板的文件流
templateFile
模板文件
autoCloseStream
自动关闭流。
password
写的时候是否需要使用密码
useDefaultStyle
写的时候是否是使用默认头
WriteSheet(excel的一个Sheet)参数
sheetNo
需要写入的编码。默认0
sheetName
需要些的Sheet名称,默认同sheetNo
WriteTable(就把excel的一个Sheet,一块区域看一个table)参数
举个读取的表格的例子:
1.依然是创建实体类
@Data
public class User {
@ExcelProperty(index = 0)
private String name;
@ExcelProperty(index = 1)
private int age;
}
2.创建监听器,用于解析读取的数据,这里需要注意的点,因为业务层的Listener 并没有交给Spring容器来管理,所以监听器代码无法注入Service ,
这里通过构造方法的方式传过来,从而完成对数据库的操作
/**
* 每解析一行会回调invoke()方法。
* 整个excel解析结束会执行doAfterAllAnalysed()方法
*/
//有个很重要的点,不能被spring管理,要每次读取excel都要new。
public class UserDataListener extends AnalysisEventListener<User> {
Logger logger = LoggerFactory.getLogger(UserDataListener.class);
//每次读取100条数据就进行保存操作
private static final int BATCH_COUNT = 100;
//由于每次读都是新new UserDataListener的,所以这个list不会存在线程安全问题
List<User> list = new ArrayList<>();
//这个组件是Spring中的组件,这边推荐两种方法注入这个组件
//第一种就是提供一个UserDataListener的构造方法,这个方法提供一个参数是UserDataListener类型
//另外一种方法就是将 UserDataListener 这个类定义成 UserService 实现类的内部类(推荐这种方式)
//private UserService userService;
@Override
public void invoke(User data, AnalysisContext analysisContext) {
logger.info("解析到一条数据:{}", JSON.toJSONString(data));
list.add(data);
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
logger.info("所有数据解析完成!");
}
private void saveData() {
logger.info("{}条数据,开始存储数据库!", list.size());
//保存数据
//userService.save(list);
logger.info("存储数据库成功!");
}
}
3.执行读取方法,调用监听器解析读取的数据
public class EasyExcelDemo {
public static void main(String[] args) throws Exception {
InputStream fis = new FileInputStream("D:\\user.xlsx");
AnalysisEventListener listener = new UserDataListener();
ExcelReader excelReader = EasyExcel.read(fis, User.class, listener).build();
ReadSheet readSheet = EasyExcel.readSheet(0).build();
ReadSheet readSheet2 = EasyExcel.readSheet(1).build();
excelReader.read(readSheet);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
}
}
经过上述三步就可以完成EasyExcel的读取解析工作了。
通用参数
ReadWorkbook
,ReadSheet
都会有的参数,如果为空,默认使用上级。
converter
转换器,默认加载了很多转换器。也可以自定义。
readListener
监听器,在读取数据的过程中会不断的调用监听器。
headRowNumber
需要读的表格有几行头数据。默认有一行头,也就是认为第二行开始起为数据。
head
与clazz
二选一。读取文件头对应的列表,会根据列表匹配数据,建议使用class。
clazz
与head
二选一。读取文件的头对应的class,也可以使用注解。如果两个都不指定,则会读取全部数据。
autoTrim
字符串、表头等数据自动trim
password
读的时候是否需要使用密码
ReadWorkbook(理解成excel对象)参数
excelType
当前excel的类型 默认会自动判断
inputStream
与file
二选一。读取文件的流,如果接收到的是流就只用,不用流建议使用file
参数。因为使用了inputStream
easyexcel会帮忙创建临时文件,最终还是file
file
与inputStream
二选一。读取文件的文件。
autoCloseStream
自动关闭流。
readCache
默认小于5M用 内存,超过5M会使用 EhCache
,这里不建议使用这个参数。
useDefaultListener
@since 2.1.4
默认会加入ModelBuildEventListener
来帮忙转换成传入class
的对象,设置成false
后将不会协助转换对象,自定义的监听器会接收到Map<Integer,CellData>
对象,如果还想继续接听到class
对象,请调用readListener
方法,加入自定义的beforeListener
、 ModelBuildEventListener
、 自定义的afterListener
即可。
ReadSheet(就是excel的一个Sheet)参数
sheetNo
需要读取Sheet的编码,建议使用这个来指定读取哪个Sheet
sheetName
根据名字去匹配Sheet,excel 2003不支持根据名字去匹配
评论(0)