使用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<SimpleConnector> connectors = objectExcelListener.getDatas();
connectors.stream().forEach(connector ->{
    connector.setProjectId(projectId);
    connector.setArea(area);
    connector.setLocation(location);
});
connectorDao.insertBatch(connectors);

使用listener将数据读到内存中

public class ObjectExcelListener<T extends BaseEntity> extends AnalysisEventListener<T> {


    List<T> 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<T> getDatas() {
        return addList;
    }

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

实现过程中走的弯路

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

附上通用listener实现

public class ExcetListener<T extends BaseEntity> extends AnalysisEventListener<T> {

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

    ExcetListener(BaseDao<T> 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<T> {
    /**
     * 根据实体对象新增记录.
     *
     * @param entity
     *            .
     * @return id 返回插入数据的ID
     */
    long insert(T entity);

    int insertBatch(@Param("entities")List<T> 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<SimpleConnector>{
    @Select("select distinct position from simple_connector where project_id=#{projectId} and area= #{area} and location=#{location}")
    List<String> 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);
}
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
EasyExcel是一个开源的excel处理框架,可以用于取和写入Excel文件。使用EasyExcelExcel文件的步骤如下: 1. 创建一个ExcelReader对象,指定要取的Excel文件路径和要映射的实体类。例如: ```java ExcelReader reader = EasyExcel.read("/path/to/file.xlsx", MyModel.class, new MyListener()).build(); ``` 这里的`MyModel`是你自定义的实体类,用于映射Excel文件中的数据。 2. 调用`reader.read()`方法Excel文件中的数据。 3. 最后,记得调用`reader.finish()`方法关闭reader对象。 通过以上步骤,你可以使用EasyExcelExcel文件中的数据。 #### 引用[.reference_title] - *1* [JAVA 使用阿里EasyExcel完成对Excel文件进行写操作](https://blog.csdn.net/weixin_43878332/article/details/112808392)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [EasyExcel轻松Excel文件!](https://blog.csdn.net/qq_48607414/article/details/128250637)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值