EasyExcel监听器需在invoke中仅转换存储、禁throw异常,错误行缓存至doAfterAllAnalysed统一处理;@ExcelProperty映射须全字段标注或全用value匹配表头;大数据导出须分批write+flush,避免OOM。

EasyExcel 读取时监听器 AnalysisEventListener 怎么写才不丢数据
监听器里不能直接 return 或提前结束,否则后续行会被跳过。常见错误是读到空行或非法数据就 throw new RuntimeException(),结果整张表中断——EasyExcel 默认遇到异常会停止解析。
正确做法是把校验失败的行缓存起来,在 doAfterAllAnalysed 里统一处理(比如收集错误信息返回给前端),而不是中断流。
-
invoke方法里只做数据转换和临时存储,别做耗时操作(如 DB 写入) - 用
list或queue缓存解析出的对象,避免在invoke中反复 new 实例 - 如果需要按 Sheet 分批处理,重写
invokeHead判断表头,再用currentSheetIndex区分
实体类用 @ExcelProperty 映射列时为什么总读错顺序
默认按字段声明顺序匹配 Excel 列,不是按注解里的 index 或 value。如果你写了 @ExcelProperty(index = 2) 却没生效,大概率是因为没加 @ExcelProperty 的字段也被参与了顺序计数——哪怕它没加注解,也会占一个位置。
解决方式只有两个:要么所有字段都显式标注 @ExcelProperty,要么统一用 value(即列名)匹配,且 Excel 表头必须严格一致(区分大小写、空格)。
立即学习“Java免费学习笔记(深入)”;
- 用
index时,实体类字段顺序必须和 Excel 列顺序完全一致,且所有参与映射的字段都要有@ExcelProperty(index = N) - 用
value时,确保 Excel 表头单元格内容和@ExcelProperty("用户名")完全相同,包括不可见字符 - 导出时若想控制列序,也得靠字段声明顺序,
@ExcelProperty的index对导出无效
导出大数据量 Excel 时内存爆掉,write 方法怎么调才稳
EasyExcel 默认走内存模式,10 万行以上就容易 OOM。关键不是换 POI,而是改写法:用 ExcelWriter + WriteSheet + 流式写入,配合 table 分片和自定义 WriteHandler 控制样式。
最简稳态写法是不用 write(list, clazz) 一次性传全部数据,改用 write(dataList, writeSheet) 分批,每批 ≤ 5000 条,并在每次写完后调用 writer.fill() 或手动 flush。
- 务必设置
AutoCloseStream = true,否则文件流不关,Linux 下可能报Too many open files - 避免在
WriteHandler的afterCellCreate里做字符串拼接或正则匹配,CPU 和 GC 压力会陡增 - 如果导出含公式或复杂样式,优先用模板填充(
fill),别用动态列生成
IllegalArgumentException: No converter for class xxx 是什么情况
这是 EasyExcel 找不到对应类型的转换器,常见于自定义枚举、LocalDateTime、BigDecimal 等非基础类型,或者用了 Lombok 的 @Data 但没生成 getter/setter。
根本原因是 EasyExcel 的默认 converter 只覆盖 String/Number/Date/Boolean,其余都靠反射调 getter,一旦 getter 缺失、命名不规范(比如 isFinished 但没 getFinished),就会报这个错。
- 检查实体类所有字段是否有 public getter,Lombok 要加
@Getter显式声明 - 枚举建议实现
Converter<yourenum></yourenum>并用@Convert注解绑定 - LocalDateTime 推荐统一用
@DateTimeFormat注解,格式字符串要和 Excel 单元格实际格式一致(如"yyyy-MM-dd HH:mm:ss")
最容易被忽略的是:EasyExcel 的 read 和 write 使用的是两套独立的 converter 机制,同一个自定义 converter 类,读和写得分别注册,不能复用实例。


















