需排除spring boot自带poi并显式声明5.2.4版本,读写大文件须分片flush,日期数字字段需配@datetimeformat/@numberformat,表头匹配优先用value+headrownumber校验。

EasyExcel 依赖怎么加才不冲突
Spring Boot 项目里直接加 easyexcel 依赖,大概率会和已有的 poi 版本打架——尤其你项目里还用了 poi-ooxml 4.1.2 或更老的版本。EasyExcel 3.x 默认要求 POI 5.2.4+,但 Spring Boot 2.7 自带的 poi 是 4.1.2,硬塞进去会报 NoClassDefFoundError: org/apache/poi/xxssf/usermodel/XSSFWorkbook 这类错。
实操建议:
- 用
spring-boot-starter-parent2.7.x 的项目,必须排除父 POM 自带的poi,显式声明兼容版本:<dependency><groupid>com.alibaba</groupid><artifactid>easyexcel</artifactid><version>3.3.2</version><exclusions><exclusion><groupid>org.apache.poi</groupid><artifactid>poi</artifactid></exclusion><exclusion><groupid>org.apache.poi</groupid><artifactid>poi-ooxml</artifactid></exclusion></exclusions></dependency><dependency><groupid>org.apache.poi</groupid><artifactid>poi</artifactid><version>5.2.4</version></dependency><dependency><groupid>org.apache.poi</groupid><artifactid>poi-ooxml</artifactid><version>5.2.4</version></dependency>
- 别用
easyexcel-spring-boot-starter—— 它封装太死,升级慢,且对自定义Converter和监听器支持差 - 如果项目还用了
Apache POI做其他 Excel 操作(比如生成图表),确保所有 POI 相关依赖版本统一,否则运行时类加载顺序一变就崩
读 Excel 时日期、数字类型自动转成奇怪的 double
EasyExcel 默认把 Excel 单元格按原始类型读:日期变成 java.util.Date,但如果你没配好格式或用了 @ExcelProperty 不带类型声明,它常会把日期当数字读成 Double(比如 44562.0),数字列也可能被识别成科学计数法字符串或 double。
实操建议:
- 读取含日期列时,字段类型必须是
java.util.Date或java.time.LocalDateTime,并配上@DateTimeFormat:@DateTimeFormat("yyyy-MM-dd")<br>private Date createTime; - 数字列想保持整型,别用
Integer接——Excel 里哪怕显示“123”,底层可能是浮点存储。稳妥做法是字段用BigDecimal,再配合@NumberFormat控制精度:@NumberFormat("#.##")<br>private BigDecimal amount; - 如果要完全关闭自动类型推断,读的时候传入
new AnalysisEventListener<yourclass>() { ... }</yourclass>,并在invoke方法里手动调用readRowHolder.getCellDataList()拿原始CellData,自己解析
写大文件时内存爆掉或导出卡死
EasyExcel 默认用 SAX 模式读、DOM 模式写,写 10 万行以上数据不设限,JVM 很快 OOM;而读超大文件(比如 50MB+)时如果监听器里做了耗时操作(如查数据库、发 HTTP 请求),也会卡住主线程导致超时。
实操建议:
- 写大文件必须用
WriteSheet+table分批写,每 1 万行 flush 一次:EasyExcel.write(outputStream, YourData.class) .sheet("数据表") .doWrite(dataList); // 别一股脑传百万条改成循环分片:for (List<yourdata> batch : Lists.partition(allData, 10000)) { EasyExcel.write(outputStream, YourData.class) .sheet("数据表") .doWrite(batch); }</yourdata> - 读大文件时,监听器里的
invoke方法务必轻量——禁止在里头做 DB 写入、远程调用;应先缓存到本地队列,另起线程批量处理 - JVM 启动参数至少加
-Xmx2g -XX:+UseG1GC,否则默认堆太小,写 5 万行就可能触发频繁 GC
@ExcelProperty 的 index 和 name 到底该用哪个
列位置变动是 Excel 解析最常见翻车点。用 index = 0 看似简单,但 Excel 表头增删列后,所有 index 全乱;用 value = "用户名" 看似灵活,但中英文空格、全角半角、隐藏字符一多,匹配就失败,日志里只打一句 Can not find column,很难定位。
实操建议:
- 优先用
value(即表头文字),但必须配合headRowNumber = 1显式指定表头在哪一行,并在读之前校验表头是否完整:public class MyListener extends AnalysisEventListener<yourdata> { @Override public void invokeHeadMap(Map<integer string> headMap, AnalysisContext context) { if (!headMap.containsValue("订单号")) { throw new IllegalArgumentException("缺少必要表头:订单号"); } } }</integer></yourdata> - 真要靠列序号(比如模板固定、不允许改表头),就别混用
index和value——一个类里要么全用index,要么全用value,否则 EasyExcel 会行为不一致 - 表头文字含特殊符号(如括号、斜杠)时,在
value里写全,别简写;Excel 复制过来的文本常带不可见 Unicode 字符,用headMap.values().forEach(System.out::println)打印出来肉眼核对
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











