EasyExcel通用上传监听器(泛型、断言、回调)

依赖版本

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.2.1</version>
        </dependency>

监听器

@Slf4j
public class UploadDataListener<T> implements ReadListener<T> {

  /** 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */
  private static final int BATCH_COUNT = 100;

  /** 缓存的数据 */
  private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

  /** Predicate用于过滤数据 */
  private Predicate<T> predicate;

  /** 调用持久层批量保存 */
  private Consumer<Collection<T>> consumer;

  public UploadDataListener(Predicate<T> predicate, Consumer<Collection<T>> consumer) {
    this.predicate = predicate;
    this.consumer = consumer;
  }

  public UploadDataListener(Consumer<Collection<T>> consumer) {
    this.consumer = consumer;
  }

  /**
   * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
   *
   * @param demoDAO
   */

  /**
   * 这个每一条数据解析都会来调用
   *
   * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
   * @param context
   */
  @Override
  public void invoke(T data, AnalysisContext context) {

    if (predicate != null && !predicate.test(data)) {
      return;
    }
    cachedDataList.add(data);

    // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
    if (cachedDataList.size() >= BATCH_COUNT) {
      try {
        // 执行具体消费逻辑
        consumer.accept(cachedDataList);

      } catch (Exception e) {

        log.error("Failed to upload data!data={}", cachedDataList);
        throw new BizException("导入失败");
      }
      // 存储完成清理 list
      cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    }
  }

  /**
   * 所有数据解析完成了 都会来调用
   *
   * @param context
   */
  @Override
  public void doAfterAllAnalysed(AnalysisContext context) {

    // 这里也要保存数据,确保最后遗留的数据也存储到数据库
    if (CollUtil.isNotEmpty(cachedDataList)) {

      try {
        // 执行具体消费逻辑
        consumer.accept(cachedDataList);
        log.info("所有数据解析完成!");
      } catch (Exception e) {

        log.error("Failed to upload data!data={}", cachedDataList);

        // 抛出自定义的提示信息
        if (e instanceof BizException) {
          throw e;
        }

        throw new BizException("导入失败");
      }
    }
  }
}

调用

try {

      EasyExcel.read(
              file.getInputStream(),
              HealthClassImportDTO.class,
              new UploadDataListener<HealthClassImportDTO>(
                  list -> {

                    // 校验数据
                    ValidationUtils.validate(list);

                    
                    // dao 保存···

                    log.info("从Excel导入数据一共 {} 行 ", list.size());
                  }))
          .sheet()
          .doRead();
    } catch (IOException e) {

      log.error("导入失败", e);
      throw new BizException("导入失败");
    }

转换器

public class LocalDateConverter implements Converter<LocalDate> {

    @Override
    public Class<LocalDate> supportJavaTypeKey() {
        return LocalDate.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public LocalDate convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        if(null==cellData) {
            return null;
        }
        LocalDate result=null;
        if(cellData.getType()==CellDataTypeEnum.NUMBER) {
            if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
                Date date= DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(),
                        globalConfiguration.getUse1904windowing(), null);
                result =date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            } else {
                Date date=  DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(),
                        contentProperty.getDateTimeFormatProperty().getUse1904windowing(), null);
                result =date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            }
        }if(cellData.getType()==CellDataTypeEnum.STRING) {
            String value=cellData.getStringValue();
            if(value.contains("-")) {
                try {
                    result= LocalDate.parse(cellData.getStringValue());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            else if(value.contains("/")) {
                try {
                    result= LocalDate.parse(new SimpleDateFormat("yyyy/MM/dd").format( value) );
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    @Override
    public WriteCellData<?> convertToExcelData(LocalDate value, ExcelContentProperty contentProperty,
                                               GlobalConfiguration globalConfiguration) {
        return new WriteCellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
    }

}
兼容时间格式(yyyy/MM/dd、yyyy-MM-ddd)

@Data
public class HealthClassImportDTO implements Serializable {

  private static final long serialVersionUID = -1753550934555684092L;

 

  @NotNull(message = "显示日期不能为空")
  @ExcelProperty(value = "显示日期", converter = LocalDateConverter.class, index = 1)
  private LocalDate viewDate;
}

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值