⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.iocoder.cn/Fight/chaoyue-EasyExcel-dexinyidai-Excel-chulishenqidanshengle/ 「芋道源码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

一年三连跳:EasyExcel → FastExcel → Apache Fesod

Java 圈最常用的 Excel 库,过去一年完成了一次罕见的「三连跳」:

  • 2024 年底:阿里官宣 EasyExcel 不再维护——5 年的头牌库进入「祝它好运」状态;
  • 2024-2025:原作者离开阿里后推出 FastExcel——API 完全兼容,主打「换 import 就能切」;
  • 2025-2026:FastExcel 再次”消失”——原作者把项目整套捐给了 Apache 软件基金会,更名为 Apache Fesod (Incubating)。最新版本 2.0.1-incubating 已于 2026-02-11 发布。

很多人一脸懵——「上次刚换完 import,怎么又没了?」

别紧张:这次不是停更,是升级到 Apache 一级开源项目——代码所有权从个人 / 公司转给基金会,长期维护、版本节奏跟 Apache POI、Maven、Tomcat 一个待遇。这是开源项目能拿到的最好结局。

说白了:它不是「比 FastExcel 更强的另一个轮子」,是「FastExcel 拿到了 Apache 终身保障」——对存量项目,是迁移成本最低、最值得切的接班选项。

横向对比:5 个 Excel 处理方案怎么选

把过去 5 年常见的 5 个方案放一张表,差距一目了然:

方案 维护状态 适用规模 内存模型 致命短板
Apache POI 活跃 任意 DOM(重) 十万行级写入容易 OOM
POI SXSSF 活跃 大文件 流式 写还行,读不擅长
HuTool ExcelReader / Writer 活跃 < 1 万行 简单 高级特性(合并 / 公式)受限
EasyExcel 2024 年起阿里停更 任意 流式 不再有新功能 / bug 修复
FastExcel 2025 年捐给 Apache、更名 Fesod 任意 流式 已是过渡命名,新项目别用
Apache Fesod (本文) Apache 孵化中,长期保障 任意 流式 仍在 Incubating 阶段,2.x API 微调

判断很简单:

  • 新项目 → 直接 Apache Fesod,少一次后续迁移;
  • 现有 EasyExcel / FastExcel 项目 → 切 Fesod,三步走(换坐标 + 改 import + 换入口类,详见「迁移指南」);
  • 极简场景(几行 Excel) → HuTool 一行调用即可,别上重武器;
  • 要做 Excel 转 PDF → Fesod 内置该能力,省得自己拼 itext。

3 个研发场景:什么时候它顶用

场景 1:百万行报表导出

财务、风控、运营部门要导出数十万到百万级订单数据。直接用 POI 一定 OOM——内存里塞百万 row 对象毕竟撑不住。

@GetMapping("/export/orders")
public void exportOrders(HttpServletResponse resp) throws IOException {
resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
String name = URLEncoder.encode("orders", "UTF-8");
resp.setHeader("Content-disposition", "attachment;filename*=utf-8''" + name + ".xlsx");

// 流式写入——分页查 DB 边读边写
try (ExcelWriter writer = FesodSheet.write(resp.getOutputStream(), Order.class).build()) {
WriteSheet sheet = FesodSheet.writerSheet("订单").build();
int page = 0, pageSize = 5000;
while (true) {
List<Order> data = orderMapper.pageQuery(page++, pageSize);
if (data.isEmpty()) break;
writer.write(data, sheet);
}
}
}

收益:流式写 + 分页查 DB(每批 5000 条),百万行导出内存稳定在 100MB 量级。

场景 2:用户上传 Excel 批量数据

客户给的 Excel 一上传上来就是上万行,逐行 INSERT DB 慢、一次性 readAll 又 OOM。Fesod 的事件监听器是为这个场景设计的:

public class OrderBatchListener extends AnalysisEventListener<OrderRow> {
private final List<OrderRow> buffer = new ArrayList<>();
private static final int BATCH_SIZE = 500;
private final OrderMapper mapper;

public OrderBatchListener(OrderMapper mapper) { this.mapper = mapper; }

@Override
public void invoke(OrderRow row, AnalysisContext ctx) {
buffer.add(row);
if (buffer.size() >= BATCH_SIZE) {
mapper.batchInsert(buffer);
buffer.clear();
}
}

@Override
public void doAfterAllAnalysed(AnalysisContext ctx) {
if (!buffer.isEmpty()) mapper.batchInsert(buffer);
}
}

关键设计:500 条凑一批 batchInsert——既不让 buffer 撑爆内存,又能利用批插提速。

场景 3:Excel 转 PDF(合同 / 工资单)

工资单、合同模板的常见诉求:导出的 Excel 同时给个 PDF 版方便归档 / 打印。

FesodSheet.convertToPdf(new File("excelFile.xlsx"), new File("pdfFile.pdf"), null, null);

底层依赖 Apache POI + itext-pdf——itext 商业用途需注意 AGPL 许可,企业项目要么走 itext 商业 license,要么换 OpenPDF。

接入 3 步:依赖 + 实体类 + 监听器

第 1 步:Maven 依赖(注意是 Apache 新坐标)

<dependency>
<groupId>org.apache.fesod</groupId>
<artifactId>fesod-sheet</artifactId>
<version>2.0.1-incubating</version>
</dependency>

重点:groupId 是 org.apache.fesod——和 EasyExcel 的 com.alibaba.excel、FastExcel 的 cn.idev.excel 都不同。新项目直接用 Apache 坐标,少一次后续迁移。

第 2 步:实体类(@ExcelProperty 注解列名)

import org.apache.fesod.sheet.annotation.ExcelProperty;

@Setter @Getter @ToString
public class User {
@ExcelProperty("编号") private Integer id;
@ExcelProperty("名字") private String name;
@ExcelProperty("年龄") private Integer age;
}

第 3 步:事件监听器(流式处理是真活)

public class BaseExcelListener<T> extends AnalysisEventListener<T> {
private final List<T> dataList = new ArrayList<>();

@Override
public void invoke(T t, AnalysisContext ctx) { dataList.add(t); }

@Override
public void doAfterAllAnalysed(AnalysisContext ctx) {
log.info("读取完成,共 {} 条", dataList.size());
}

public List<T> getDataList() { return dataList; }
}

注意:监听器决定了内存模型。生产用法应该在 invoke 里累积 + 批量落库,而不是无脑 dataList.add——否则上百万行直接 OOM。

核心 API:写、读、转 PDF

写:

FesodSheet.write(response.getOutputStream(), User.class)
.sheet("模板")
.doWrite(buildData());

读:

FesodSheet.read(file.getInputStream(), User.class, listener)
.sheet()
.doRead();

Spring Boot 上传 + 处理:

@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) return ResponseEntity.badRequest().body("请选择文件");
try {
BaseExcelListener<User> listener = new BaseExcelListener<>();
FesodSheet.read(file.getInputStream(), User.class, listener).sheet().doRead();
log.info("上传 {} 条", listener.getDataList().size());
return ResponseEntity.ok("处理成功");
} catch (IOException e) {
return ResponseEntity.status(500).body("文件处理失败");
}
}

迁移指南:从 EasyExcel / FastExcel 切到 Fesod

Apache Fesod 官方建议分阶段迁移——先换坐标 + import,再换类名,每步都跑测试,降低风险。一张表对照三代变化:

项目 EasyExcel(阿里) FastExcel(过渡) Apache Fesod(最新)
groupId com.alibaba cn.idev.excel org.apache.fesod
artifactId easyexcel fastexcel fesod-sheet
版本 3.x(停更) 1.x 2.0.1-incubating
import 包 com.alibaba.excel.* cn.idev.excel.* org.apache.fesod.sheet.*
入口类 EasyExcel FastExcel FesodSheet(推荐)

迁移步骤:

  1. 改 pom:换 groupId / artifactId / version;
  2. 全局替换 import:IDE 一次性 cn.idev.excel → org.apache.fesod.sheet(或 com.alibaba.excel → 同上);
  3. 替换入口类:FastExcel.read/write → FesodSheet.read/write;
  4. 跑回归测试:流式写、监听器读、合并单元格、多 sheet 全过一遍。

API 完全兼容——上层调用方式(@ExcelProperty 注解、AnalysisEventListener 监听器、ExcelWriter 写入器)一行不动。

4 个真实使用边界

边界 1:仍在 Incubating 阶段,API 微调可能(最常见)

2.0.1-incubating 是孵化器版本——Apache 孵化项目惯例是 API 还可能有小幅调整。修法:① pom 锁死具体版本号;② 关注 fesod.apache.org 的 release notes;③ 升级前在测试环境跑全套回归。

边界 2:监听器不要把数据全留在内存(常见)

新人最容易写错的代码:

// ❌ 上百万行直接 OOM
public void invoke(T t, AnalysisContext ctx) { dataList.add(t); }

修法:累积到 batch 阈值后立刻 flush(DB / 队列 / 文件),buffer 清空再继续。

边界 3:Excel 转 PDF 的 itext 许可(少见但破坏力大)

iText 7+ 是 AGPL 许可——商用项目不买商业 license 不允许闭源。要避坑可以换 OpenPDF(LGPL)或 Aspose.PDF(商业)。法务环节别忽略。

边界 4:和 FastExcel 1.x 二进制不兼容(高级场景)

虽然 API 兼容,但 FastExcel 1.x 和 Fesod 2.x 在 Maven 依赖树上是两个不同 artifact——同一项目两个都引会出现类冲突。迁移时必须一刀切:删掉 cn.idev.excel:fastexcel,只留 org.apache.fesod:fesod-sheet。

我的判断

EasyExcel → FastExcel → Apache Fesod 的三连跳,看着折腾,但走到 Apache 这一步意味着这个工具终于有了一个不会再”消失”的家——基金会保 license、社区保维护、长期 roadmap 由社区共治,不再受单家公司 / 单个作者影响。好的开源接班不是另起炉灶,是把已有的轮子继续往前转——这次干脆转进了 Apache,连维护权都不用再担心。

仓库:github.com/apache/fesod | 官网:fesod.apache.org | 迁移指南:fesod.apache.org/docs/migration/from-fastexcel/

文章目录
  1. 1. 一年三连跳:EasyExcel → FastExcel → Apache Fesod
  2. 2. 横向对比:5 个 Excel 处理方案怎么选
  3. 3. 3 个研发场景:什么时候它顶用
  4. 4. 接入 3 步:依赖 + 实体类 + 监听器
  5. 5. 核心 API:写、读、转 PDF
  6. 6. 迁移指南:从 EasyExcel / FastExcel 切到 Fesod
  7. 7. 4 个真实使用边界
  8. 8. 我的判断