在写代码的途中正好在这个问题上遇难题了就顺手记录下来了
按着我的代码一路走下来就不会错了
写的比较简单 直接上代码 直接代码复用就可以了,比其他的写的要实际,记得改类名和包名
这个首先要导入一个easyexcel和poi 的依赖进pom包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.10</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.16</version>
</dependency>
剩下的就是代码了
最主要的还是要多建立一个 ExcelListener 类用来写监听器(每写一个导入就要重新写一个监听)
package com.tunnel.boot.web.constructionriskcontrol.controller;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.tunnel.boot.web.constructionriskcontrol.dto.TunnelMaterialManagementDTO;
import com.tunnel.boot.web.constructionriskcontrol.service.TunnelMaterialManagementService;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
// 有个很重要的点 ExcelListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class ExcelListener extends AnalysisEventListener<TunnelMaterialManagementDTO> {
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 3000;
private final List<TunnelMaterialManagementDTO> list = new ArrayList<>();
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private final TunnelMaterialManagementService tunnelMaterialManagementService;
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*/
public ExcelListener(TunnelMaterialManagementService tunnelMaterialManagementService) {
this.tunnelMaterialManagementService = tunnelMaterialManagementService;
}
/**
* 这个每一条数据解析都会来调用
*/
@Override
public void invoke(TunnelMaterialManagementDTO tunnelMaterialManagementDTO, AnalysisContext analysisContext) {
log.info("解析到一条数据:========================{}", tunnelMaterialManagementDTO.toString());
// 数据存储到datas,供批量处理,或后续自己业务逻辑处理。
if (ObjectUtil.isNotEmpty(tunnelMaterialManagementDTO)) {
list.add(tunnelMaterialManagementDTO);
}
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理datas
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
saveData();//确保所有数据都能入库
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("=============================={}条数据,开始存储到数据库", list.size());
tunnelMaterialManagementService.saveList(list);
}
}
conroller 层
@RequestMapping("importExcel")
@ResponseBody
public String importExcel(@RequestParam(value = "file") MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), TunnelMaterialManagementDTO.class, new ExcelListener(tunnelMaterialManagementService)).sheet().doRead();
return "success";
}
service层
/**
* 一次性存储导入的excel文件
* @param list
*/
void saveList(List<TunnelMaterialManagementDTO> list);
impl层
/**
* 存列表,excel文件
*
* @param list
*/
@Override
@Transactional
public void saveList(List<TunnelMaterialManagementDTO> list) {
list.forEach(v->{
tunnelMaterialManagementMapper.insert(AppBeanUtil.convert(v,TunnelMaterialManagement.class));
});
}
mapper层
/**
*excel导入
*/
int saveList(List<TunnelMaterialManagementDTO> tunnelMaterialManagementDTOList);
xml层
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tunnel.boot.web.constructionriskcontrol.mapper.TunnelMaterialManagementMapper">
<!--一次性存储导入excel-->
<insert id="saveList" parameterType="java.util.List">
insert into tunnel_material_management (
task_name,
material_number,
specification,
model_number,
company,
inventory_quantity,
manager,
contact_information,
date_of_inventory,
material_storage_location,
remarks
)
values
<foreach collection="list" item="item" index="index" separator=",">
(
#{item.taskName},
#{item.materialNumber},
#{item.specification},
#{item.modelNumber},
#{item.company},
#{item.inventoryQuantity},
#{item.manager},
#{item.contactInformation},
#{item.dateOfInventory},
#{item.materialStorageLocation},
#{item.remarks},
#{item.typeOfMaterial}
)
</foreach>
</insert>
</mapper>