悟耕开源easypoi - excel导入导出最佳实践总结

2,614 阅读4分钟

前言

从上家公司到师大教育,一直以来,使用EasyPOI做了不少导入导出的需求,导入导出数据量从10万级到现在百万级(excel峰值103万数据量),用到了EasyPOI来完成导入,通过该篇文章我详细的整理整理EasyPOI的导入导出的基础和高级用法。

本篇文章主要涵盖一下方面内容:

  1. 注解说明
  2. 定义EasyPoi导入实体类
  3. 基础的导入导出逻辑(数据校验)
  4. 不同类型数据的导入和导出(Map/Object)
  5. 基于多线程ForkJoin实现导入优化
  6. 自定义导入数据处理(数据校验)
  7. 导入组内数据重复校验实现
  8. 导入组内校验实现重复行定位并输出到错误日志

常见需求场景

excel导入导出几乎在很多中后台项目都会用到,特别是一写CRMOA商城企业应用等系统都十分常见,在开发的过程中我也遇到过很多excel大数据导入导出的功能,我稍微列举一些需求:

  • 大数据导出数据装换以及数据加密
  • excel导入数据校验,并提供错误日志下载

EasyPoi依赖

悟耕开源 EasyPoi 4.3.0版本(推荐最新)

image.png

一、注解说明

常见的5个注解类分别是:

  • @Excel 作用到filed上面,是对Excel一列的一个描述
  • @ExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,科目就可以用集合表示
  • @ExcelEntity 表示一个继续深入导出的实体,但他没有太多的实际意义,只是告诉系统这个对象里面同样有导出的字段
  • @ExcelIgnore 和名字一样表示这个字段被忽略跳过这个导导出
  • @ExcelTarget 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做出不同处理

二、定义EasyPOI实体类

carbon (1).png

三、基础的导入导出逻辑(数据校验)

easyPoi导入校验使用起来也很简单,以导入系统优化为例:

第一步,定义一个检验类SdSchoolSysUserVerify,通过实现IExcelModelIExcelDataModel,当我们需要输出导入校验错误信息的时候,它们两个就显的很重要了,IExcelModel负责设置错误信息,IExcelDataModel负责设置行号。

carbon (2).png

第二步,定义完实体之后,那么如何实现我们的校验逻辑呢,接着自定义一个系统用户导入校验处理器SdSchoolSysUserVerifyHandler,通过实现IExcelVerifyHandler<SdSchoolSysUserVerify>,处理器里编写我们的校验逻辑:

carbon (3).png

第三步,在完成第一、二步之后,我们只需要在导入的时候通过 params.setVerifyHandler(userVerifyHandler)params.setNeedVerfiy(true)即可以实现导入校验了。

四、不同类型数据的导入和导出(Map/Object)

在某些复杂的场景,我们导入的时候不想直接构造一个bean然后标记注解,但是中间需要处理一些字段逻辑没办法直接导入到数据库,这是用可以用map的形式导入,下面我以一个客户导入的需求演示一下如何通过map的方式导入数据:

SdCrmCustomerMapVerify

carbon (12).png

CustomerMapVerifyHandler

carbon (6).png

导入实现逻辑

carbon (8).png

核心方法:

//Map数据格式导入
ExcelImportResult<Map<String, Object>> importResult = ExcelImportUtil.importExcelMore(inputStream, Map.class, params);

// 获取导入检验通过的数据
List<Map<String, Object>> rightMapList = importResult.getList();
// 获取导入检验失败的数据
List<Map<String, Object>> failMapList = importResult.getFailList();

最后可以将校验失败的数据,通过excel错误日志输出,非常的方便。

五、基于多线程ForkJoin实现导入优化

在4.0后的版本,ExcelPoi导入支持了fork/join的线程支持,使用方法很简单 ImportParams 新加了两个参数,设置为true就可以了,多线程导入处理可以提高了导入的处理效率,比如:

params.setConcurrentTask(true);                     //4.1版本都支持基于fork/join的线程

六、自定义导入数据处理

这里列举说明一下EasyPoi的几个比较重要的接口和类:

  • IExcelDataHandler:当存在一下比较特殊的需求场景,easyPoi基础服务无法满足客户的需求时,可以通过实现IExcelDataHandler去自定义数据处理,比如数值转换器处理。
  • IExcelVerifyHandler:一般都是通过实现IExcelVerifyHandler接口实现自己的校验逻辑。
  • IExcelModel:自定义实体校验类时,主要用于输出错误日志,IExcelModel负责错误信息。
  • IExcelDataModel:自定义实体校验类时,主要用于输出错误日志,IExcelDataModel负责设置行号。

IExcelDataHandler

/**
 * Excel 导入导出 数据处理接口
 * 
 * @author JueYue
 *  2014年6月19日 下午11:59:45
 */
public interface IExcelDataHandler<T> {

    /**
     * 导出处理方法
     * 
     * @param obj   当前对象
     * @param name  前字段名称    
     * @param value 当前值  
     * @return
     */
    public Object exportHandler(T obj, String name, Object value);
 
 }

七、导入组内数据重复校验实现

可以通过ThreadLocal来实现组内校验,可以定位输出每一个错误数据的具体是哪一行,方便我们做导入排错:

carbon (10).png

核心代码:

threadLocalValue.forEach(e -> {
    if (e.getRegisterUserPhone().equals(customerVerify.getRegisterUserPhone())) {
        int lineNumber = e.getRowNum() + 1;
        joiner.add("数据与第" + lineNumber + "行重复");
    }
});
//添加本行数据对象到ThreadLocal中
threadLocalValue.add(customerVerify);
threadLocal.set(threadLocalValue);

八、导入组内校验实现重复行定位并输出到错误日志

参考:nullpointer.pw/easypoi%E5%…