使用easyexcel读excel(实现通用listener)

需求

有多张数据需要导入、导出,数据量巨大,决定采用easyExcel实现。

思路

easyExcel读web中的excel,由于不同的excel导入存在mysql中不同的表,若读取每类excel都新建一个ExcetListener处理save逻辑比较麻烦。考虑写一个通用的Listener,实现过程中发现由于excel中没有包含所有需要保存的字段(一部分字段由前端传到后台保存),故改为使用listener将数据读到内存中再进行批量保存处理。(隐患:数据量巨大时是否会导致内存问题)。

ObjectExcelListener objectExcelListener = new ObjectExcelListener();
EasyExcel.read(file.getInputStream(), SimpleConnector.class, objectExcelListener).
        sheet().doRead();
List connectors = objectExcelListener.getDatas();
connectors.stream().forEach(connector ->{
    connector.setProjectId(projectId);
    connector.setArea(area);
    connector.setLocation(location);
});
connectorDao.insertBatch(connectors);

使用listener将数据读到内存中

public class ObjectExcelListener extends AnalysisEventListener {


    List addList = new ArrayList<>();

    /**
     * 每解析一行都会回调invoke()方法
     * @param context 内容
     */

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        //解析结束销毁不用的资源
        //注意不要调用datas.clear(),否则getDatas为null
    }


    @Override
    public void invoke(T t, AnalysisContext analysisContext) {
        addList.add(t);
    }

    /**
     * 返回数据
     *
     * @return 返回读取的数据集合
     **/
    public List getDatas() {
        return addList;
    }

    /**
     * 设置读取的数据集合
     *
     * @param datas 设置读取的数据集合
     **/
    public void setDatas(List datas) {
        this.addList = datas;
    }
}

实现过程中走的弯路

1.查找网上的资料,通用的Listener使用BaseDao构造,在Listener中调用dao去批量save数据。

附上通用listener实现

public class ExcetListener extends AnalysisEventListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExcetListener.class);
    /**
     * 每隔30条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 30;
    List addList = new ArrayList<>();
    private BaseDao baseDao;

    ExcetListener(BaseDao baseDao) {
        this.baseDao = baseDao;
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param testCategory
     * @param analysisContext
     */
    @SneakyThrows
    @Override
    public void invoke(T testCategory, AnalysisContext analysisContext) {
            addList.add(testCategory);
        if (addList.size() >= BATCH_COUNT ) {
            saveData();
            addList.clear();
        }
    }

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

    /**
     * 加上存储数据库
     */
    private void saveData() {
        if (addList.isEmpty()) {
            return;
        }
        baseDao.insertBatch(addList);
    }

}

BaseDao代码,所有的Dao都可以继承BaseDao

@Qualifier("qualityDataSource")
public interface BaseDao {
    /**
     * 根据实体对象新增记录.
     *
     * @param entity
     *            .
     * @return id 返回插入数据的ID
     */
    long insert(T entity);

    int insertBatch(@Param("entities")List entities);

    /**
     * 更新实体对应的记录.
     *
     * @param entity
     *            .
     * @return
     */
    long update(T entity);

    /**
     * 根据ID查找记录.
     *
     * @param id
     *            .
     * @return entity .
     */
    T queryById(long id);

    /**
     * 根据ID删除记录.
     *
     * @param id
     *            .
     * @return
     */
    int deleteById(long id);

由于项目myBatis的配置,需要在对应的Mapper.xml中实现sql语句,子类的Dao接口仍然可以按原来的规则在接口中直接写BaseDao中没有的方法,例如

public interface SimpleConnectorDao extends BaseDao{
    @Select("select distinct position from simple_connector where project_id=#{projectId} and area= #{area} and location=#{location}")
    List getConnectorPosition(@Param("projectId") int projectId, @Param("area")String area, @Param("location")String location);
}

2.当前BaseDao为接口,没有实现类。实现类可自动生成Mapper.xml代码,不需要去自己写Mapper.xml的内容,参考github中https://github.com/xshiyu/mybatis-geneator-tool项目,注意点是由于项目采用多数据源配置,需要在注入时使用@Qualifier注明采用的数据源,下一步可实现在BaseDaoImpl中实现通用的inser,update等方法,即子类Dao不需要自己去实现增删改查。

当前项目BaseDaoImpl中的SqlSessionTemplate 注入方式

@Resource
@Qualifier("qualitySqlSessionTemplate")
private SqlSessionTemplate sessionTemplate;

@Autowired
@Qualifier("qualitySqlSessionFactory")
protected SqlSessionFactory sqlSessionFactory;


@Override
public SqlSession getSqlSession() {
    return super.getSqlSession();
}


@Autowired
@Qualifier("qualitySqlSessionFactory")
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory){

    super.setSqlSessionFactory(sqlSessionFactory);
}

你可能感兴趣的:(spring,spring,boot,excel)