Loading...
Loading...
基于 Alibaba EasyExcel(com.alibaba:easyexcel:4.0.3)的 Excel 数据读取技能。覆盖监听器模式(ReadListener/AnalysisEventListener/PageReadListener)、同步读取(doReadSync)、多 Sheet 读取、@ExcelProperty(index/name)匹配、多行表头(headRowNumber)、日期数字自定义转换器(@DateTimeFormat/@NumberFormat/Converter)、监听器异常处理(onException + ExcelDataConvertException)、额外信息读取(批注/超链接/合并单元格,extraRead + CellExtra)、公式和单元格类型(CellData<T>)、不创建对象的读(ReadListener<Map<Integer,String>>)、Web 上传读取(MultipartFile→InputStream)。当用户需要解析 Excel(导入数据/批量入库/对账文件/用户上传/Excel 转对象/Excel 转 Map)时使用此技能,不适用于按预制模板填充(改用 easyexcel-fill)、不适用于程序化生成 Excel(改用 easyexcel-write)。
npx skill4agent add full-stack-skills/java-skills easyexcel-read官方文档:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read 官方示例:https://github.com/alibaba/easyexcel/blob/master/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java 当前版本:(Apache-2.0,仓库已归档,仅做 Bug 修复)com.alibaba:easyexcel:4.0.3
.xlsx.xlsheadRowNumberheadRowNumber@ExcelProperty#value()doReadSync()easyexcel-filleasyexcel-writeexcelType(CSV).xlsx// 写法 1:JDK8+ PageReadListener(since 3.0.0-beta1,最简洁)
EasyExcel.read(fileName, DemoData.class, new PageReadListener<DemoData>(dataList -> {
for (DemoData data : dataList) {
log.info("读取到数据: {}", JSON.toJSONString(data));
}
})).sheet().doRead();
// 写法 2:匿名 ReadListener
EasyExcel.read(fileName, DemoData.class, new ReadListener<DemoData>() {
@Override public void invoke(DemoData data, AnalysisContext context) { /* 每行回调 */ }
@Override public void doAfterAllAnalysed(AnalysisContext context) { /* 全部完成 */ }
}).sheet().doRead();
// 写法 3:自定义 ReadListener
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
// 写法 4:ExcelReader(一个文件一个 reader)
try (ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class,
new DemoDataListener()).build()) {
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
}官方原文:"PageReadListener 默认每次会读取100条数据 然后返回过来 直接调用使用数据就行"
@ExcelPropertyinvokedoAfterAllAnalysedonExceptioninvokeHeadextradoRead()excelReader.read(readSheet)数据规模?
├── < 1000 行 + 一次性返回 → 同步模式:doReadSync()
├── < 1 万行 + 简单处理 → PageReadListener
├── > 1 万行 + 入库 → ReadListener + 批量入库(每 2000 行)
└── 不需要对象 + 动态列 → ReadListener<Map<Integer, String>>
需要额外信息?
├── 批注 → extraRead(CellExtraTypeEnum.COMMENT)
├── 超链接 → extraRead(CellExtraTypeEnum.HYPERLINK)
└── 合并单元格 → extraRead(CellExtraTypeEnum.MERGE)
需要多 Sheet?
├── 全部 → doReadAll()
└── 部分 → ExcelReader.read(readSheet1, readSheet2, ...)@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {
/**
* 官方原文:"DemoDataListener 不能被spring管理,要每次读取excel都要new"
*/
private static final int BATCH_COUNT = 100;
private List<DemoData> cachedDataList =
ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
private DemoDAO demoDAO;
public DemoDataListener() {
demoDAO = new DemoDAO();
}
/**
* 官方原文:"如果使用了spring,请使用这个构造方法。
* 每次创建Listener的时候需要把spring管理的类传进来"
*/
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
@Override
public void invoke(DemoData data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
cachedDataList.add(data);
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData(); // ⚠️ 处理最后一批
log.info("所有数据解析完成!");
}
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
demoDAO.save(cachedDataList);
log.info("存储数据库成功!");
}
}
// 持久层(官方原文:"如果是mybatis,尽量别直接调用多次insert,
// 自己写一个mapper里面新增一个方法batchInsert")
public class DemoDAO {
public void save(List<DemoData> list) {
// mybatis batchInsert
}
}references/