Springboot项目实现easyExcel批量导入到数据库
Springboot项目实现easyexcel批量导入到数据库
- 1.导入依赖
- 2. 构建实体类
- 3.Controller层
- 4.Service层
1.导入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
2. 构建实体类
注意:
- 在导入数据的时候 在excel表中的列名顺序要和实体类中的字段顺序一致,它会按照顺序进行一一导入数据,如果顺序不一致,会导致传入的值和字段对应不上的情况;
- 如果有字段不需要导入,可以使用注解
@ExcelIgnore
忽略; @ExcelProperty
中的值也要和excel表中的列名称完全对应;
以下是我的实体类:
@Data
public class LayerMessage {
private Integer markerId;
@ExcelProperty("图层名称")
private String markerName;
private String descInfo;
@ExcelProperty("备注")
private String remark;
@ExcelProperty("操作时间")
private Date opDate;
@ExcelIgnore
private Integer isDel;
3.Controller层
@PostMapping(value = "/import")
@ApiOperation(value = "批量导入")
public R importLayer(@RequestPart("layerfile") MultipartFile layerfile){
return layerManagementService.importLayer(layerfile);
}
若是项目中没有配置swagger不需要写@ApiOperation
注解
4.Service层
/**
* 批量导入
* @param layerfile
*/
@Override
public R importLayer(MultipartFile layerfile) {
try{
logger.info("开始导入:{}", layerfile.getOriginalFilename());
// LayerMessageListener layerMessageListener = new LayerMessageListener();
layerMessageListener.setRes(new ArrayList<>());
layerMessageListener.setCount(0);
EasyExcel.read(layerfile.getInputStream(),LayerMessage.class,layerMessageListener).sheet().doRead();
return layerMessageListener.resMess();
}catch (Exception e){
throw new ValidateException("导入失败");
}
}
在service中为了返回详细的错误提示,在读取数据之前,先将存储错误信息的list以set的形式给初始化;在数据插入结束之后调用listener中的函数返回错误信息。
对数据的插入部分我写到了listener中,也可以写到Service中。
Listener文件如下:
@Component
@Scope("prototype")
@Slf4j
public class LayerMessageListener extends AnalysisEventListener<LayerMessage> {
@Autowired
private LayerMessageMapper layerMessageMapper;
/**
* 每隔100条处理下,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 100;
//计数
@Setter
private int count;
/**
* 缓存的数据
*/
private List<Map<Integer,LayerMessage>> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
//导入失败的错误提示集合
@Setter
private List<String> res;
public LayerMessageListener(){
this.res = new ArrayList<>();
}
//一行一行去读取excel内容并封装到LayerMessageDto中
//默认从第二行读取数据,因为第一行一般都是表头
@Override
public void invoke(LayerMessage layerMessage, AnalysisContext analysisContext) {
//获取行号
int index=analysisContext.readRowHolder().getRowIndex();
log.info("解析到第{}行的数据:{}",analysisContext.readRowHolder().getRowIndex(),layerMessage);
count++;
//缓存解析的数据
Map<Integer,LayerMessage> map = new HashMap<>();
map.put(index,layerMessage);
cachedDataList.add(map);
//达到批量处理的数据量,进行批量插入数据库
if(cachedDataList.size() >= BATCH_COUNT){
save(cachedDataList);
//插入完之后清空缓存
cachedDataList.clear();
}
}
//解析完成后执行收尾工作
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
log.info("sheet={} 所有数据解析完成!", analysisContext.readSheetHolder().getApproximateTotalRowNumber()-1);
//将缓存中剩余的数据保存到数据库中
save(cachedDataList);
//清空缓存
cachedDataList.clear();
}
//返回错误信息
public R resMess(){
log.info("添加失败{}条数据,count:{}",res.size(),count);
if(res!=null && res.isEmpty()){
return R.ok("全部添加成功");
}else if(res != null && res.size()==count){
return R.failed(res,"全部添加失败");
}else{
return R.failed(res,"部分添加失败");
}
}
//添加数据
void save(List<Map<Integer, LayerMessage>> layerMessagelist){
//此处为了将excel中的行号与内容对应起来,我使用了map的结构
for(Map<Integer,LayerMessage> layerMessagemap:layerMessagelist){
for(Map.Entry<Integer,LayerMessage> entry:layerMessagemap.entrySet()){
int rowindex=entry.getKey();
LayerMessage layerMessage=entry.getValue();
//此处可以写对excel中导入的内容的校验逻辑
//检查“markerDataId”是否已经存在于数据库中
List<String> list = layerMessageMapper.markerDataIdAll();
List<String> list1 = layerMessageMapper.selectCodeList(layerMessage.getAreaCode());
if (list1.contains(layerMessage.getAreaCode())){
res.add("第"+rowindex+"行错误");
continue;
}
//将新层消息插入数据库
layerMessageMapper.insertLayerMessage(layerMessageDto);
}
}
}
}