1、pom.xml文件引入easyExcel
<!--阿里开源easyExcel依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.10</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
2、导入监听类
package com.tool.pc.utils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.tool.pc.service.UsersService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Data
@Slf4j
public class ExcelImoprtListener extends AnalysisEventListener<Map<Integer, String>> {
//定义每多少条数据进行数据库保存
private static final int BATCH_COUNT = 128;
//自己实现service层,我这里用的用户表来演示
private UsersService usersService;
//用list集合保存解析到的结果
private List<Map<Integer, String>> list;
//部门id,需要传入的参数可以自己定义
private Integer deptId;
//重构,把传来的值赋给对应的属性
public ExcelImoprtListener(UsersService usersService, Integer deptId) {
this.usersService = usersService;
this.deptId = deptId;
list = new ArrayList<>();
}
/**
* 重写invokeHeadMap方法,获去表头,如果有需要获取第一行表头就重写这个方法,不需要则不需要重写
*
* @param headMap Excel每行解析的数据为Map<Integer, String>类型,Integer是Excel的列索引,String为Excel的单元格值
* @param context context能获取一些东西,比如context.readRowHolder().getRowIndex()为Excel的行索引,表头的行索引为0,0之后的都解析成数据
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
log.info("解析到一条头数据:{}, currentRowHolder: {}", headMap.toString(), context.readRowHolder().getRowIndex());
list.add(headMap);
}
/**
* 重写invoke方法获得除Excel第一行表头之后的数据,
* 如果Excel第二行也是表头,那么也会解析到这里,如果不需要就通过判断context.readRowHolder().getRowIndex()跳过
*
* @param data 除了第一行表头外,数据都会解析到这个方法
* @param context 和上面解释一样
*/
@Override
public void invoke(Map<Integer, String> data, AnalysisContext context) {
log.info("解析到一条数据:{}, currentRowIndex: {}----", data.toString(), context.readRowHolder().getRowIndex());
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 解析到最后会进入这个方法,需要重写这个doAfterAllAnalysed方法,然后里面调用自己定义好保存方法
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", list.size());
//这里自行实现service层方法存储数据库
usersService.saveList(list,deptId);
}
}
3、Controller方法
/**
* 导入
* @param file
* @param deptId 部门id
* @author
* @date
* @return
*/
@PostMapping("/limitImport")
public void limitImport(@RequestParam("file") MultipartFile file,
@RequestParam("deptId") Integer deptId) throws IOException {
//初始化监听器
ExcelImoprtListener excelImoprtListener = new ExcelImoprtListener(usersService,deptId);
//解析数据
EasyExcel.read(file.getInputStream(), excelImoprtListener).sheet(0).doReadSync();
}