? 新手必看!EasyExcel 数据导入导出实战教程 2025 最新版
一、为什么选择 EasyExcel?
如果你是 Java 开发者,在处理 Excel 文件时肯定遇到过内存溢出的问题。传统的 POI 框架虽然功能强大,但处理大文件时内存占用极高,一个 3M 的 Excel 用 POI 解析可能需要 100M 内存,而 EasyExcel 通过重构 POI 的解析逻辑,将内存占用降低到几 M,彻底解决了这个痛点。2025 年的最新版本进一步优化了性能,特别是在处理超大数据量时,通过内部算法调整减少了内存占用率,同时新增了更多实用功能,比如支持自定义样式、更灵活的 API 配置以及更清晰的错误提示机制。
二、环境搭建:快速上手 EasyExcel
Maven 依赖配置
在项目的pom.xml中添加 EasyExcel 依赖。2025 版推荐使用最新版本,目前稳定版是 3.3.1。注意,如果项目中已经使用了 POI,需要手动排除poi-ooxml-schemas依赖,避免版本冲突:
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>3.3.1version>
<exclusions>
<exclusion>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxml-schemasartifactId>
exclusion>
exclusions>
dependency>
JDK 版本兼容性
EasyExcel 3.0.0 及以上版本支持 JDK 8-21。如果你的项目使用 JDK 6 或 7,需要选择 2.0.0-beta1 至 2.2.11 版本,但不建议新项目使用旧版本。
三、数据导出实战:从简单到复杂
基础数据导出
首先创建一个实体类,用@ExcelProperty注解指定列名和顺序:
@Data
public class User {
@ExcelProperty(value = "姓名", index = )
private String name;
@ExcelProperty(value = "年龄", index = )
private Integer age;
}
然后编写导出代码:
List<User> userList = new ArrayList<>();
userList.add(new User("张三", ));
String fileName = "user_data.xlsx";
EasyExcel.write(fileName, User.class).sheet("用户数据").doWrite(userList);
运行后会生成一个包含用户数据的 Excel 文件,是不是很简单?
多工作表导出
如果需要在一个 Excel 文件中生成多个 Sheet,可以这样做:
EasyExcel.write(fileName)
.sheet("Sheet1")
.doWrite(userList)
.sheet("Sheet2")
.doWrite(anotherDataList);
每个 Sheet 可以独立设置样式和数据,满足不同业务需求。
自定义样式
2025 版增强了样式设置功能,支持自定义表头和内容样式。例如,设置表头居中对齐、加粗,内容单元格添加边框:
WriteCellStyle headStyle = new WriteCellStyle();
headStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
headStyle.setFillForegroundColor(IndexedColors.SEA_GREEN.getIndex());
WriteFont headFont = new WriteFont();
headFont.setBold(true);
headStyle.setWriteFont(headFont);
WriteCellStyle contentStyle = new WriteCellStyle();
contentStyle.setBorderLeft(BorderStyle.THIN);
contentStyle.setBorderRight(BorderStyle.THIN);
contentStyle.setBorderTop(BorderStyle.THIN);
contentStyle.setBorderBottom(BorderStyle.THIN);
HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(headStyle, contentStyle);
EasyExcel.write(fileName, User.class)
.registerWriteHandler(styleStrategy)
.sheet("用户数据")
.doWrite(userList);
这样生成的 Excel 文件会更美观、易读。
四、数据导入实战:高效处理用户上传
简单数据导入
创建一个监听器来处理读取到的数据:
public class UserListener extends AnalysisEventListener<User> {
private List<User> dataList = new ArrayList<>();
@Override
public void invoke(User user, AnalysisContext context) {
dataList.add(user);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 数据处理逻辑,例如保存到数据库
saveToDatabase(dataList);
}
}
然后编写导入代码:
String fileName = "user_upload.xlsx";
EasyExcel.read(fileName, User.class, new UserListener()).sheet().doRead();
EasyExcel 会逐行读取数据,避免一次性加载全量数据导致内存溢出。
复杂数据转换
如果 Excel 中的某些字段需要特殊处理,比如日期格式或枚举值,可以使用自定义转换器。例如,将字符串日期转换为LocalDate类型:
public class LocalDateConverter implements Converter<LocalDate> {
@Override
public Class<?> supportJavaTypeKey() {
return LocalDate.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public LocalDate convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
return LocalDate.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
}
在实体类字段上指定使用该转换器:
@ExcelProperty(value = "出生日期", index = , converter = LocalDateConverter.class)
private LocalDate birthDate;
这样 EasyExcel 在读取数据时会自动进行类型转换。
五、高级技巧:应对复杂业务场景
大数据量处理
处理百万级数据时,建议使用流式读取和分批次处理。例如,每读取 100 条数据就保存到数据库:
public class BigDataListener extends AnalysisEventListener<User> {
private static final int BATCH_SIZE = ;
private List<User> batchData = new ArrayList<>(BATCH_SIZE);
@Override
public void invoke(User user, AnalysisContext context) {
batchData.add(user);
if (batchData.size() >= BATCH_SIZE) {
saveBatch(batchData);
batchData.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
if (!batchData.isEmpty()) {
saveBatch(batchData);
}
}
}
这样可以有效降低内存占用,避免 OOM 问题。
动态表头生成
如果表头需要根据业务动态生成,可以使用head方法:
List<List<String>> head = new ArrayList<>();
head.add(Arrays.asList("姓名", "年龄", "性别"));
head.add(Arrays.asList("详细信息", "详细信息", "详细信息"));
EasyExcel.write(fileName)
.head(head)
.sheet("动态表头")
.doWrite(dataList);
这种方式适用于表头结构不确定的场景。
六、常见问题及解决方案
内存溢出
- 原因:一次性加载全量数据到内存。
- 解决:使用流式读取(
read方法)和分批次处理,避免将所有数据保存在内存中。
表头不匹配
- 原因:实体类字段的
@ExcelProperty注解值与 Excel 表头不一致。
- 解决:确保注解的
value值与表头完全一致,包括大小写和空格。
无参构造方法缺失
- 原因:实体类没有无参构造方法,导致 EasyExcel 无法实例化对象。
- 解决:为实体类添加无参构造方法。
POI 版本冲突
- 原因:项目中存在多个 POI 版本依赖。
- 解决:在 EasyExcel 依赖中排除
poi-ooxml-schemas,并手动指定 POI 版本。
七、性能优化建议
使用最新版本
2025 版的 EasyExcel 在性能和稳定性上都有显著提升,建议升级到最新版本以获得最佳体验。
合理配置批次大小
根据数据量和系统性能调整批次大小,平衡内存占用和处理速度。通常每批次 100-1000 条数据比较合适。
复用对象
在监听器中复用数据对象,减少垃圾回收压力。例如,使用对象池或预先创建对象。
异步写入
对于高并发场景,可以使用异步写入提升吞吐量。通过asyncSheet方法开启异步模式:
EasyExcel.write(fileName, User.class)
.asyncSheet("异步写入")
.doWrite(userList);
EasyExcel.write(fileName, User.class)
.asyncSheet("异步写入")
.doWrite(userList);
但需注意异步操作可能带来的线程安全问题。
通过以上步骤,你已经掌握了 EasyExcel 的核心用法和高级技巧。无论是简单的数据导入导出,还是复杂的大数据量处理,EasyExcel 都能轻松应对。现在就动手实践吧,让 Excel 处理变得高效又简单!
该文章由dudu123.com嘟嘟 ai 导航整理,嘟嘟 AI 导航汇集全网优质网址资源和最新优质 AI 工具