阿里停更EasyExcel后,我毫不犹豫换了这个库
2025年9月,阿里把EasyExcel的GitHub仓库归档了。
这个消息在Java圈子里炸开没多久,它的作者就放出了一个大招——FastExcel,并在同月正式进入Apache孵化器,改名Fesod。
说实话,这个交接完成得相当漂亮。
一波三折的故事
EasyExcel当年为什么火?就是因为POI太难用,数据量大了还OOM。EasyExcel基于SAX流式解析,不用把整个Excel加载到内存,100万行照样跑得稳稳的。
但阿里在2024年11月宣布停更,这下很多人不淡定了——线上跑得好好的库,以后谁来维护?
答案来得很快。FastExcel是EasyExcel原作者离开阿里后重新维护的加强版:
- • 2024年12月:FastExcel 1.0.0发布
- • 2025年8月:FastExcel 1.3.0发布(当前稳定版)
- • 2025年9月:进入Apache孵化器,更名Fesod
关键点:完全兼容EasyExcel,API几乎一模一样,迁移过来就是换个包名的事。还新增了两个实用功能——读取Excel指定行数、Excel直接转PDF。
我有个朋友在电商公司做后端,订单导出动不动几十万行。之前用EasyExcel跑得好好的,得知停更消息后焦虑了一阵子。迁移到FastExcel后,他跟我说:"就改了两个地方,一个依赖一个import,一天搞定,跑了两个月没出过问题。"
这不是个案。FastExcel社区挺活跃,issue响应也快。
怎么选
Apache Fesod是FastExcel进入Apache后的新名字,全称是"Fast Easy Spreadsheet and Other Documents"。现在还处于孵化阶段,但已经有1.3.0稳定版可用。
我的建议是:现在用FastExcel,观望Fesod。两者代码基本一致,等Fesod正式毕业了再切换也不迟。
| | | | |
|---|
| 最新版本 | | | | |
| 维护状态 | | | | |
| 内存占用 | | | | |
| 学习成本 | | | | |
| 生态完善度 | | | | |
| 适用场景 | | | | |
| 推荐度 | | | | |
简单说:新项目直接FastExcel,老项目逐步迁移,别再新建POI项目了。
<!-- FastExcel(当前稳定版) --><dependency> <groupId>cn.idev.excel</groupId> <artifactId>fastexcel</artifactId> <version>1.3.0</version></dependency>
快速上手
加依赖:
<dependency> <groupId>cn.idev.excel</groupId> <artifactId>fastexcel</artifactId> <version>1.3.0</version></dependency>
1. 定义实体类
用@ExcelProperty注解映射Excel列,value指定表头名称,index指定列顺序:
public class User { // index从0开始对应Excel的A列,不写index则按属性字母顺序 @ExcelProperty(value = "编号", index = 0) private Integer id; @ExcelProperty(value = "姓名", index = 1) private String name; @ExcelProperty(value = "年龄", index = 2) private Integer age; // 忽略字段,不写入Excel @ExcelIgnore private String password;}
2. 导出Excel
完整示例,包含响应头设置、防乱码、多个Sheet写入:
@RestController@RequestMapping("/api/user")public class UserController { @GetMapping("/export") public void export(HttpServletResponse response) throws IOException { // 设置响应头,防止中文文件名乱码 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("用户列表", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); // 构建数据 List<User> users = buildUsers(); // 写入Excel,可多次调用sheet()写入多个Sheet FastExcel.write(response.getOutputStream(), User.class) .sheet("第一页") .doWrite(users); // 写第二个Sheet的示例 // FastExcel.write(response.getOutputStream, User.class) // .sheet("第二页") // .doWrite(users2); } // 模拟数据,实际从数据库查询 private List<User> buildUsers() { List<User> users = new ArrayList<>(); for (int i = 1; i <= 10; i++) { User user = new User(); user.setId(i); user.setName("用户" + i); user.setAge(18 + i); // 密码字段,不写入Excel user.setPassword("123456"); users.add(user); } return users; }}
3. 导入Excel
导入需要自定义监听器,FastExcel采用SAX模式逐行读取,不会把整个文件加载到内存:
// 监听器,用于处理每行读取的数据public class UserImportListener extends AnalysisEventListener<User> { // 存储读取的数据 private final List<User> users = new ArrayList<>(); // 每解析一行数据都会调用invoke @Override public void invoke(User user, AnalysisContext context) { users.add(user); System.out.println("解析到数据:" + user); } // 全部解析完成后调用 @Override public void doAfterAllAnalysed(AnalysisContext context) { System.out.println("共解析:" + users.size() + " 条数据"); } // 提供外部访问数据的方法 public List<User> getUsers() { return users; }}
接口接收上传文件并解析:
@PostMapping("/import")public String importUsers(@RequestParam("file") MultipartFile file) throws IOException { if (file.isEmpty()) { return "请选择文件"; } UserImportListener listener = new UserImportListener(); // 读取Excel第一个Sheet FastExcel.read(file.getInputStream(), User.class, listener) .sheet() .doRead(); // 获取解析结果,批量保存到数据库 List<User> users = listener.getUsers(); userService.saveBatch(users); return "成功导入:" + users.size() + " 条数据";}
4. 大数据量导入(防止OOM)
数据量大时需要分批处理,避免数据全部堆积在内存:
public class BatchUserImportListener extends AnalysisEventListener<User> { private static final int BATCH_SIZE = 500; // 每500条处理一次 private final List<User> batch = new ArrayList<>(BATCH_SIZE); private final UserService userService; public BatchUserImportListener(UserService userService) { this.userService = userService; } @Override public void invoke(User user, AnalysisContext context) { batch.add(user); // 达到批量大小时写入数据库,然后清空缓冲区 if (batch.size() >= BATCH_SIZE) { saveBatch(); } } @Override public void doAfterAllAnalysed(AnalysisContext context) { // 处理遗留的零头数据 if (!batch.isEmpty()) { saveBatch(); } } private void saveBatch() { userService.saveBatch(new ArrayList<>(batch)); System.out.println("批量写入:" + batch.size() + " 条"); // 清空缓冲区,准备下一批数据 batch.clear(); }}
总结
选FastExcel,理由很直接:
- • 作者靠谱:EasyExcel原班人马,不是野路子
- • 背靠Apache:虽然还在孵化,但至少不会突然消失
如果你的项目还在用POI或者老版本EasyExcel,强烈建议迁移。好的技术选型,不是选最"权威"的,而是选有人在认真维护、且足够稳定的。
三行代码搞定的事,何必绕那么远。