content: package com.alibaba.easyexcel.test.demo.read;
  
  import java.util.List;
  import java.util.Map;
  
  import com.alibaba.excel.context.AnalysisContext;
  import com.alibaba.excel.exception.ExcelDataConvertException;
  import com.alibaba.excel.metadata.data.ReadCellData;
  import com.alibaba.excel.read.listener.ReadListener;
  import com.alibaba.excel.util.ListUtils;
  import com.alibaba.fastjson2.JSON;
  
  import lombok.extern.slf4j.Slf4j;
  
  /**
   * 读取转换异常
   *
   * @author Jiaju Zhuang
   */
  @Slf4j
  public class DemoExceptionListener implements ReadListener<ExceptionDemoData> {
      /**
       * 每隔5条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
       */
      private static final int BATCH_COUNT = 5;
  
      private List<ExceptionDemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
  
      /**
       * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
       *
       * @param exception
       * @param context
       * @throws Exception
       */
      @Override
      public void onException(Exception exception, AnalysisContext context) {
          log.error("解析失败，但是继续解析下一行:{}", exception.getMessage());
          // 如果是某一个单元格的转换异常 能获取到具体行号
          // 如果要获取头的信息 配合invokeHeadMap使用
          if (exception instanceof ExcelDataConvertException) {
              ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
              log.error("第{}行，第{}列解析异常，数据为:{}", excelDataConvertException.getRowIndex(),
                  excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
          }
      }
  
      /**
       * 这里会一行行的返回头
       *
       * @param headMap
       * @param context
       */
      @Override
      public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
          log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
      }
  
      @Override
      public void invoke(ExceptionDemoData data, AnalysisContext context) {
          log.info("解析到一条数据:{}", JSON.toJSONString(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());
          log.info("存储数据库成功！");
      }
  }
  