如何高效使用EasyExcel实现Excel文件的导入导出操作?

2026-05-22 10:153阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1513个文字,预计阅读时间需要7分钟。

如何高效使用EasyExcel实现Excel文件的导入导出操作?

使用EasyExcel导入/导出Excel快速入门:

官方网站:https://github.com/alibaba/easyexcel

快速开始:https://www.yuque.com/easyexcel/doc/easyexcel

使用场景:在日常生活中,开发中我们难免需要导入/导出数据,使用EasyExcel可以轻松解决。

使用EasyExcel导入导出Excel 1、官方网站

github.com/alibaba/easyexcel

快速开始:www.yuque.com/easyexcel/doc/easyexcel

如何高效使用EasyExcel实现Excel文件的导入导出操作?

使用场景

在日常开发中 我们难免需要导入数据 可以用EasyExcel来解决

2、EasyExcel特点
  • Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。
  • EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
  • EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。
3、动起手来

创建一个普通maven项目 加入依赖

<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> 3.1excel示例

3.2 实体类

我们需要创建好与excel列名相对应的实体类

@ExcelProperty 表示excel列名

package com.atguigu.easyexcel.dto; @Data public class ExcelStudentDTO { @ExcelProperty("姓名") private String name; @ExcelProperty("生日") private Date birthday; @ExcelProperty("薪资") private Double salary; } 3.3 测试起来吧 1 简单的写

public class ExcelWriteTest { @Test public void simpleWriteXlsx() { String fileName = "d:/excel/simpleWrite.xlsx"; //需要提前新建目录 // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, ExcelStudentDTO.class).sheet("模板").doWrite(data()); } //辅助方法 private List<ExcelStudentDTO> data(){ List<ExcelStudentDTO> list = new ArrayList<>(); //算上标题,做多可写65536行 //超出:java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535) for (int i = 0; i < 65535; i++) { ExcelStudentDTO data = new ExcelStudentDTO(); data.setName("Helen" + i); data.setBirthday(new Date()); data.setSalary(123456.1234); list.add(data); } return list; } }

结果就是上面那张图片哈 不粘了

2 不同版本的写

@Test public void simpleWriteXls() { String fileName = "d:/excel/simpleWrite.xls"; // 如果这里想使用03 则 传入excelType参数即可 EasyExcel.write(fileName, ExcelStudentDTO.class).excelType(ExcelTypeEnum.XLS).sheet("模板").doWrite(data()); } 3 读的操作

参考文档www.yuque.com/easyexcel/doc/read

简单描述一下 读的操作 需要实现一个监听器 实现监听器的方法

@Slf4j public class ExcelStudentDTOListener extends AnalysisEventListener<ExcelStudentDTO> { /** * 这个每一条数据解析都会来调用 */ @Override public void invoke(ExcelStudentDTO data, AnalysisContext context) { log.info("解析到一条数据:{}", data); } /** * 所有数据解析完成了 都会来调用 */ @Override public void doAfterAllAnalysed(AnalysisContext context) { log.info("所有数据解析完成!"); } }

测试方法

public class ExcelReadTest { /** * 最简单的读 */ @Test public void simpleReadXlsx() { String fileName = "d:/excel/simpleWrite.xlsx"; // 这里默认读取第一个sheet EasyExcel.read(fileName, ExcelStudentDTO.class, new ExcelStudentDTOListener()).sheet().doRead(); } @Test public void simpleReadXls() { String fileName = "d:/excel/simpleWrite.xls"; EasyExcel.read(fileName, ExcelStudentDTO.class, new ExcelStudentDTOListener()).excelType(ExcelTypeEnum.XLS).sheet().doRead(); } } 实战

在真实的项目中 我们读取到 数据之后 肯定要持久化到数据库中 这个操作就由我们的监听器来完成

1、Mapper层批量插入

接口:DictMapper

void insertBatch(List<ExcelDictDTO> list);

xml:DictMapper.xml

<insert id="insertBatch"> insert into dict ( id , parent_id , name , value , dict_code ) values <foreach collection="list" item="item" index="index" separator=","> ( #{item.id} , #{item.parentId} , #{item.name} , #{item.value} , #{item.dictCode} ) </foreach> </insert> 2监听器的实现

import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.atguigu.srb.mapper.DictMapper; import com.atguigu.srb.pojo.dto.ExcelDictDTO; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; /** * 监听 * 再读取数据的同时 对数据进行插入操作 * @author : look-word * @date : 2022-05-10 21:35 **/ @Slf4j //@AllArgsConstructor //全参 @NoArgsConstructor //无参 public class ExcelDictDTOListener extends AnalysisEventListener<ExcelDictDTO> { /** * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 100; /** * 缓存的数据 */ private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); /** * 假设这个是一个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; } /** * 这个每一条数据解析都会来调用 * * @param data one row value. Is 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("存储数据库成功!"); } }

本文共计1513个文字,预计阅读时间需要7分钟。

如何高效使用EasyExcel实现Excel文件的导入导出操作?

使用EasyExcel导入/导出Excel快速入门:

官方网站:https://github.com/alibaba/easyexcel

快速开始:https://www.yuque.com/easyexcel/doc/easyexcel

使用场景:在日常生活中,开发中我们难免需要导入/导出数据,使用EasyExcel可以轻松解决。

使用EasyExcel导入导出Excel 1、官方网站

github.com/alibaba/easyexcel

快速开始:www.yuque.com/easyexcel/doc/easyexcel

如何高效使用EasyExcel实现Excel文件的导入导出操作?

使用场景

在日常开发中 我们难免需要导入数据 可以用EasyExcel来解决

2、EasyExcel特点
  • Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。
  • EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
  • EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。
3、动起手来

创建一个普通maven项目 加入依赖

<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> 3.1excel示例

3.2 实体类

我们需要创建好与excel列名相对应的实体类

@ExcelProperty 表示excel列名

package com.atguigu.easyexcel.dto; @Data public class ExcelStudentDTO { @ExcelProperty("姓名") private String name; @ExcelProperty("生日") private Date birthday; @ExcelProperty("薪资") private Double salary; } 3.3 测试起来吧 1 简单的写

public class ExcelWriteTest { @Test public void simpleWriteXlsx() { String fileName = "d:/excel/simpleWrite.xlsx"; //需要提前新建目录 // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, ExcelStudentDTO.class).sheet("模板").doWrite(data()); } //辅助方法 private List<ExcelStudentDTO> data(){ List<ExcelStudentDTO> list = new ArrayList<>(); //算上标题,做多可写65536行 //超出:java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535) for (int i = 0; i < 65535; i++) { ExcelStudentDTO data = new ExcelStudentDTO(); data.setName("Helen" + i); data.setBirthday(new Date()); data.setSalary(123456.1234); list.add(data); } return list; } }

结果就是上面那张图片哈 不粘了

2 不同版本的写

@Test public void simpleWriteXls() { String fileName = "d:/excel/simpleWrite.xls"; // 如果这里想使用03 则 传入excelType参数即可 EasyExcel.write(fileName, ExcelStudentDTO.class).excelType(ExcelTypeEnum.XLS).sheet("模板").doWrite(data()); } 3 读的操作

参考文档www.yuque.com/easyexcel/doc/read

简单描述一下 读的操作 需要实现一个监听器 实现监听器的方法

@Slf4j public class ExcelStudentDTOListener extends AnalysisEventListener<ExcelStudentDTO> { /** * 这个每一条数据解析都会来调用 */ @Override public void invoke(ExcelStudentDTO data, AnalysisContext context) { log.info("解析到一条数据:{}", data); } /** * 所有数据解析完成了 都会来调用 */ @Override public void doAfterAllAnalysed(AnalysisContext context) { log.info("所有数据解析完成!"); } }

测试方法

public class ExcelReadTest { /** * 最简单的读 */ @Test public void simpleReadXlsx() { String fileName = "d:/excel/simpleWrite.xlsx"; // 这里默认读取第一个sheet EasyExcel.read(fileName, ExcelStudentDTO.class, new ExcelStudentDTOListener()).sheet().doRead(); } @Test public void simpleReadXls() { String fileName = "d:/excel/simpleWrite.xls"; EasyExcel.read(fileName, ExcelStudentDTO.class, new ExcelStudentDTOListener()).excelType(ExcelTypeEnum.XLS).sheet().doRead(); } } 实战

在真实的项目中 我们读取到 数据之后 肯定要持久化到数据库中 这个操作就由我们的监听器来完成

1、Mapper层批量插入

接口:DictMapper

void insertBatch(List<ExcelDictDTO> list);

xml:DictMapper.xml

<insert id="insertBatch"> insert into dict ( id , parent_id , name , value , dict_code ) values <foreach collection="list" item="item" index="index" separator=","> ( #{item.id} , #{item.parentId} , #{item.name} , #{item.value} , #{item.dictCode} ) </foreach> </insert> 2监听器的实现

import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.atguigu.srb.mapper.DictMapper; import com.atguigu.srb.pojo.dto.ExcelDictDTO; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; /** * 监听 * 再读取数据的同时 对数据进行插入操作 * @author : look-word * @date : 2022-05-10 21:35 **/ @Slf4j //@AllArgsConstructor //全参 @NoArgsConstructor //无参 public class ExcelDictDTOListener extends AnalysisEventListener<ExcelDictDTO> { /** * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 100; /** * 缓存的数据 */ private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); /** * 假设这个是一个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; } /** * 这个每一条数据解析都会来调用 * * @param data one row value. Is 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("存储数据库成功!"); } }