1. easyExcel简介
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
官网:https://easyexcel.opensource.alibaba.com/

本文主要介绍2.0版本。
注意事项:
1. 读写的对象都用到了Lombok,他会自动生成get,set ,如果不需要的话,自己创建对象并生成get,set
2. easyexcel默认是全部实体字段都会参与读写,不管你是否加了@ExcelProperty注解
- 如果您的版本低于2.1.6,建升级到以上版本
- 升级了还有,在类的最上面加入@ExcelIgnoreUnannotated注解,加入这个注解后只有加了@ExcelProperty才会参与读写。
3. 在读的时候Listener里面需要使用spring的@Autowired
- 给Listener创建成员变量,然后在构造方法里面传进去。必须不让spring管理Listener,每次读取都要new一个。
4. 如何获取所有sheet的列表或者名字
5. 如何获取excel的总条数
- 在监听器里面:analysisContext.readSheetHolder().getApproximateTotalRowNumber();
2. 快速入门——读Excel

/**
* 最简单的读
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>3. 直接读即可
*/
@Test
public void simpleRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
// EasyExcel 入口类,用于构建开始各种操作
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
/**
* excel对应的实体对象
* 这里的排序和excel里面的排序一致
*/
@Data
public class DemoData {
private String string;
private Date date;
private Double doubleData;
}
/**
* 模板的读取类
*/
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {
/**
* 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
/**
* 缓存的数据
*/
private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private DemoDAO demoDAO;
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param demoDAO
*/
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data one row value. It is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(DemoData data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
cachedDataList.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
demoDAO.save(cachedDataList);
log.info("存储数据库成功!");
}
}