干掉POI内存溢出!阿里EasyExcel万字实战,搞定所有Excel导入导出场景
- 2026-09-23 19:09:49
干掉POI内存溢出!阿里EasyExcel万字实战,搞定所有Excel导入导出场景做Java后台开发,几乎没人能避开Excel导入导出的需求。报表导出、批量数据导入、数据备份、台账下载,这些都是业务系统的标配功能。但传统的Apache POI框架,总能让开发者踩满坑: ✅ 小数据量正常运行,十万级数据直接OOM内存溢出 ✅ 加载整个Excel文件到内存,内存占用极高 ✅ 代码冗余繁琐,样式、解析逻辑手写量大 ✅ 频繁出现合并单元格错乱、格式兼容问题 而EasyExcel,阿里开源的Excel处理组件,完美解决了POI的核心痛点。它以低内存、高性能、极简API、零OOM的优势,成为目前企业级项目Excel处理的首选方案。
Apache POI处理Excel的核心逻辑是:一次性将整个Excel文件全部加载到内存,再进行解析、写入操作。这就导致一个致命问题:当文件数据量较大(10万行以上),内存占用会瞬间飙升,极易触发OutOfMemoryError,线上环境直接崩服务。 除此之外,POI的API设计繁琐,实现一个简单的带表头导出,需要大量冗余代码,开发效率极低。 EasyExcel是基于POI封装的轻量化组件,彻底重构了读写逻辑,EasyExcel 通过 事件驱动 + 逐行处理 的设计理念,彻底解决了 Java 处理大文件 Excel 时的内存溢出问题。配合简洁的注解驱动 API,让开发者可以用极少的代码完成复杂的 Excel 导入导出功能, 核心亮点如下: 1. 极致低内存,杜绝OOM 采用逐行读取、流式写入机制,不加载全量文件到内存。读取百万级Excel文件,内存占用仅几MB,这是POI完全做不到的。 2. API极简,开箱即用 通过注解绑定实体与Excel列关系,几行代码即可实现导入导出,大幅减少样板代码。 3. 全面兼容 完美支持.xls(Excel97-2003)、.xlsx(Excel2007+) 两种格式,兼容所有办公软件。 4. 企业级能力齐全 支持自定义表头样式、单元格格式、多Sheet读写、模板填充、数据校验、大数据分片处理,完全满足复杂业务场景。 5. 持续维护、生态成熟 阿里开源、社区活跃,适配SpringBoot全版本,是国内企业项目的主流选型。
目前全新稳定版 4.0.3(新版重构版本,适配SpringBoot2.x/3.x,修复大量旧版BUG、优化流式读写性能),推荐项目直接升级使用,本文全部代码基于 4.0.3 版本适配。 无需额外引入POI依赖,EasyExcel已内置适配版本,避免版本冲突。 EasyExcel通过实体类注解映射Excel列,核心常用注解: @ExcelProperty:核心注解,绑定列名、列下标、表头名称 @ExcelIgnore:忽略该字段,不参与导入导出 @DateTimeFormat:统一日期格式化,解决Excel日期解析错乱问题 @NumberFormat:数字格式化,保留小数、千分位等
我们以用户数据为案例,实现最常用的Excel读写功能。 通过注解绑定Excel表头与实体字段映射关系,规范数据格式。 几行代码即可实现批量数据导出,自动生成标准Excel文件,自带表头。 EasyExcel读取采用监听器模式,逐行解析数据,避免内存积压,适配超大文件。
项目中90%的场景都是浏览器在线导入导出,直接响应流返回文件,无需生成本地文件。 通过HttpServletResponse输出流,直接返回Excel文件给浏览器,支持前端直接下载。 接收前端上传的Excel文件,在线解析、校验、批量入库,适配表单上传场景。
EasyExcel的逐行流式解析天然支持大数据量处理,核心优化方案: 禁止一次性加载全量数据到List,采用分片批量入库(推荐1000-2000条/批) 解析过程中及时清空临时集合,释放内存 关闭不必要的日志、格式化逻辑,提升解析速度 实测:100万行Excel数据,POI直接OOM,EasyExcel内存占用稳定在10MB以内,解析耗时仅2-3秒。 4.0.3版本优化了样式处理器底层逻辑,兼容更多Excel版本,避免旧版样式错乱问题,自适应列宽、自定义表头样式写法如下: 可自定义表头背景色、字体大小、加粗样式,满足报表美化需求。 一份Excel文件生成多个Sheet,适配多维度报表场景:
整理项目开发中最容易遇到的问题,直接规避BUG: 解决方案:严格使用URLEncoder编码文件名,适配IE、Chrome、Edge所有浏览器。 解决方案:实体字段必须添加 @DateTimeFormat、@NumberFormat 注解,统一格式解析规则。 解决方案:禁止一次性存储全量数据,必须分片处理、分批入库。 解决方案:4.x版本对表头解析逻辑优化,必须手动指定 headRowNumber(1) 定义表头行数,避免自动识别错位,适配各类不规则Excel模板。 解决方案:4.x版本已内置适配POI依赖,严禁手动引入、排除POI依赖,直接使用官方内置版本,彻底杜绝版本冲突。
EasyExcel凭借低内存、高性能、极简API、高稳定性,彻底替代了传统POI,成为Java项目Excel处理的最优解。 核心优势总结: 解决POI内存溢出痛点,支持百万级大数据处理 注解式开发,代码极简,大幅提升开发效率 适配所有Web场景,导入导出一键落地 样式、多Sheet、模板填充等进阶能力全覆盖 本文所有代码可直接复制落地,覆盖95%以上企业Excel业务场景,建议收藏备查!
前言
一、为什么放弃POI,选择EasyExcel?
1.1 传统POI的致命缺陷
1.2 EasyExcel核心优势
二、环境快速搭建(SpringBoot项目)
2.1 Maven依赖
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.3</version></dependency>
2.2 核心注解说明
三、核心实战:基础导入导出
3.1 定义数据实体类
import com.alibaba.excel.annotation.ExcelProperty;import com.alibaba.excel.annotation.format.DateTimeFormat;import com.alibaba.excel.annotation.format.NumberFormat;import lombok.Data;import java.util.Date;/*** 用户Excel导入导出实体*/@Datapublic class UserExcelDTO {// 表头名称:用户ID,对应Excel第一列@ExcelProperty(value = "用户ID", index = 0)private Long userId;// 表头名称:用户名@ExcelProperty(value = "用户名", index = 1)private String username;// 表头名称:手机号@ExcelProperty(value = "手机号", index = 2)private String phone;// 日期格式化:统一解析/导出为yyyy-MM-dd@ExcelProperty(value = "注册时间", index = 3)@DateTimeFormat("yyyy-MM-dd")private Date registerTime;// 数字格式化:保留2位小数@ExcelProperty(value = "账户余额", index = 4)@NumberFormat("#.00")private Double balance;// 忽略该字段,不导出、不解析@ExcelIgnoreprivate String token;}
3.2 实战1:Excel导出(本地文件写入)
import com.alibaba.excel.EasyExcel;import java.util.ArrayList;import java.util.Date;import java.util.List;public class ExcelWriteDemo {public static void main(String[] args) {// 1. 构造模拟数据List<UserExcelDTO> userList = new ArrayList<>();for (int i = 1; i <= 100; i++) {UserExcelDTO user = new UserExcelDTO();user.setUserId((long) i);user.setUsername("测试用户" + i);user.setPhone("1380000" + i);user.setRegisterTime(new Date());user.setBalance(100.55 + i);userList.add(user);}// 2. 写入Excel文件String filePath = "D:/user_list.xlsx";EasyExcel.write(filePath, UserExcelDTO.class).sheet("用户数据列表") // 设置sheet名称.doWrite(userList); // 写入数据System.out.println("Excel导出成功!");}}
3.3 实战2:Excel读取(解析本地文件)
步骤1:自定义读取监听器
import com.alibaba.excel.context.AnalysisContext;import com.alibaba.excel.event.AnalysisEventListener;import java.util.ArrayList;import java.util.List;/*** Excel读取监听器*/public class UserExcelListener extends AnalysisEventListener<UserExcelDTO> {// 存储解析后的批量数据private List<UserExcelDTO> dataList = new ArrayList<>();/*** 逐行解析数据(每行执行一次)*/@Overridepublic void invoke(UserExcelDTO user, AnalysisContext context) {dataList.add(user);// 可自定义分片处理:每解析1000条批量入库,避免一次性数据过多if (dataList.size() >= 1000) {saveData();dataList.clear();}}/*** 解析完成后执行*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 处理剩余数据saveData();System.out.println("Excel文件解析完成!");}/*** 模拟数据入库逻辑*/private void saveData() {// 此处可调用service批量保存数据库System.out.println("批量处理数据:" + dataList.size() + "条");}}
步骤2:执行文件读取
import com.alibaba.excel.EasyExcel;public class ExcelReadDemo {public static void main(String[] args) {String filePath = "D:/user_list.xlsx";// 读取文件,绑定实体类与监听器EasyExcel.read(filePath, UserExcelDTO.class, new UserExcelListener()).sheet() // 读取第一个sheet.doRead();}}
四、Web核心实战:前后端导入导出
4.1 Web端Excel导出(下载功能)
import com.alibaba.excel.EasyExcel;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.net.URLEncoder;import java.util.ArrayList;import java.util.Date;import java.util.List;@RestControllerpublic class ExcelController {/*** 在线导出用户Excel*/@GetMapping("/excel/export/user")public void exportUserExcel(HttpServletResponse response) throws IOException {// 1. 设置响应头,解决文件名乱码、浏览器下载问题response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("UTF-8");String fileName = URLEncoder.encode("用户数据报表", "UTF-8").replace("+", "%20");response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");// 2. 构造模拟数据List<UserExcelDTO> userList = new ArrayList<>();for (int i = 1; i <= 500; i++) {UserExcelDTO user = new UserExcelDTO();user.setUserId((long) i);user.setUsername("在线用户" + i);user.setPhone("1390000" + i);user.setRegisterTime(new Date());user.setBalance(200.88 + i);userList.add(user);}// 3. 流式写入响应流,直接下载EasyExcel.write(response.getOutputStream(), UserExcelDTO.class).sheet("用户数据").doWrite(userList);}}
4.2 Web端Excel导入(上传解析)
import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.multipart.MultipartFile;import java.io.IOException;@RestControllerpublic class ExcelImportController {/*** Excel批量导入用户数据*/@PostMapping("/excel/import/user")public String importUserExcel(@RequestParam("file") MultipartFile file) throws IOException {// 校验文件格式String fileName = file.getOriginalFilename();if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {return "文件格式错误,请上传Excel文件!";}// 解析上传文件EasyExcel.read(file.getInputStream(), UserExcelDTO.class, new UserExcelListener()).sheet().doRead();return "数据导入成功!";}}
五、进阶实战:复杂业务场景
5.1 百万级大数据量无OOM处理
5.2 自定义Excel样式(表头/内容)
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;// EasyExcel 4.0.3 专属样式写法:自适应列宽EasyExcel.write(response.getOutputStream(), UserExcelDTO.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("用户数据").doWrite(userList);
5.3 多Sheet导出
// 第一个SheetEasyExcel.write(filePath, UserExcelDTO.class).sheet(0, "用户数据").doWrite(userList);// 第二个SheetEasyExcel.write(filePath, OrderExcelDTO.class).sheet(1, "订单数据").doWrite(orderList);
六、高频踩坑避坑指南
坑1:Excel文件名中文乱码
坑2:日期、数字格式解析错乱
坑3:大文件导入内存溢出
坑4:表头行数不匹配,解析数据错位
坑5:依赖版本冲突
七、总结
补充
EasyExcel 已进入维护模式,对于新项目来说,继续依赖一个“退役”的库,风险不小。就在大家一筹莫展之际,EasyExcel 原作者公开了一个新项目 FastExcel,号称 EasyExcel 的“升级版”,FastExcel 还新增了实用功能:读取 Excel 指定行数,Excel 直接转 PDF。
关键时间线:
2024 年 12 月:FastExcel 1.0.0 发布
2025 年 8 月:FastExcel 1.3.0 发布(稳定版)
2025 年 9 月:进入 Apache 孵化器,更名为 Apache Fesod
迁移成本极低——完全兼容 EasyExcel,API 几乎一模一样,只需替换 Maven 依赖和包名即可
<!-- 从 EasyExcel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.3</version></dependency><!-- 迁移到 FastExcel --><dependency><groupId>cn.idev.excel</groupId><artifactId>fastexcel</artifactId><version>1.3.0</version></dependency>
Apache Fesod:社区化升级
2025 年 9 月 17 日,FastExcel 正式进入 Apache 孵化器,更名为 Apache Fesod(Incubating)。项目名称 “fesod” 是 “Fast Easy Spreadsheet and Other Documents” 的缩写。
目前 Fesod 已发布 2.0.2-incubating 版本,仍在 Apache 孵化中。
总结演进路径:
EasyExcel(停更)→ FastExcel(活跃)→ Apache Fesod(Apache 孵化)
本文来自网友投稿或网络内容,如有侵犯您的权益请联系我们删除,联系邮箱:wyl860211@qq.com 。