阿里巴巴的EasyExcel是一种Java语言编写的开源库,用于简化Excel文件的导入和导出操作。在Java中解析Excel,比有名的框架有Apache POI和jxl,但是他们都有个严重的问题就是非常耗内存。相比EasyExcel在处理大型Excel文件时,EasyExcel能够有效地管理内存,避免出现内存溢出等问题,而且也比较简单。
com.alibaba
easyexcel
3.3.2
1.准备ExcelModel实体类对应Excel表格
@Data
public class ExcelModel {
@ExcelProperty("ID")
private Long id;
@ExcelProperty("姓名")
private String name;
@ExcelProperty("性别")
private String sex;
@ExcelProperty("年龄")
private Integer age;
@ExcelProperty()注解里面的值对应Excel表格里面的第一行的内容,循序无所谓
2.准备 文件读取监听器
1.创建一个DataListener监听器类,然后直接implements实现ReadListener接口,接口里面放写好的Excel实体类,只需要重写invoke()方法和doAfterAllAnalysed()方法
invoke()方法的参数是你对应的Excel实体类 (ExcelModel) 和(AnalysisContext context)
咱们直接看代码
@Component
public class DataListener implements ReadListener {
//日志
private static final Logger LOGGER = LoggerFactory.getLogger(DataListener.class);
//每次最多导入条数
private static final int BATCH_COUNT = 2000;
//执行批量添加的service
@Resource
private SysUserService sysUserService;
//数据集合
List poList = new ArrayList<>();
//读取失败的Excel文件索引行数集合
List failedRowIndexList = new ArrayList<>();
//无参构造方法
public MailDataListener() {
}
//使用这个构造方法,Listener是不被spring所管理的
//所以我们自己在外面new Listener的时候把service传进来
public MailDataListener(SysUserService sysUserService) {
this.sysUserService = sysUserService;
}
//这个是按照Excel表格来进行每行读取的 一行一行读取
@Override
public void invoke(ExcelModel excelModel, AnalysisContext context) {
ReadRowHolder readRowHolder = context.readRowHolder();
//Excel的行索引
Integer rowIndex = readRowHolder.getRowIndex() + 1;
try {
//对应数据库的实体类
SysUser sysUser = new SysUser();
//通过get获取Excel中的数据
//可以在这做一些数据处理,看自己需求
Long id = excelModel.getId();
String name = excelModel.getName();
....
sysUser.setId(id);
sysUser.setName(name);
....
//把实体类存到集合中
poList.add(sysUser);
//读取数超过2000进行一次数据写入
//防止一次读取的数据量过大做的一个限制
//因为在doAfterAllAnalysed()方法里面执行批量导入,这个方法是在读取完Excel才会执行
if (poList.size() >= BATCH_COUNT) {
sysUserService.insertByPoListCheck(poList);
poList.clear();//清除list中的数据
}
LOGGER.info("行索引数: [%s] -> Excel数据: [%s]", rowIndex,
JsonUtil.toJsonString(excelModel));
//try catch 用的Exception这样不管什么异常都捕获得到出错的Excel行数
} catch (Exception e) {
LOGGER.error("行索引数: [%s] -> 失败的Excel数据: [%s]", rowIndex,
JsonUtil.toJsonString(excelModel));
//收集失败的Excel行索引 通过getFailedRows()返回
failedRowIndexList.add(rowIndex);
}
}
//最后执行,读取完整个Excel执行
//先打印下日志,然后直接批量导入操作
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
LOGGER.info("所有数据读取完毕!");
try {
if (!poList.isEmpty()) {
sysUserService.insertByPoListCheck(poList);
}
} catch (ResDBEffectCheckException e) {
throw new RuntimeException("Insert User Check Error!");
}
}
//获取读取失败的Excel行索引数集合
public List getFailedRows() {
return failedRowIndexList;
}
}
JsonUtil的方法就是自己封装的ObjectMapper的writeValueAsString方法
public class JsonUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtil.class);
private static final ObjectMapper objectMapper = new ObjectMapper();
public static String toJsonString(T obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
LOGGER.error("Failed to convert object to JSON string", e);
return null;
}
}
}
剩下的就比较简单了
3.service层和mapper层代码
service 对应 controller
public class SendService {
@Resource
private SysUserService sysUserService;
public List batchSending(MultipartFile file) {
if (file == null) {
throw new NullInvokeParamRuntimeException();
}
try {
//文件转成流的形式
InputStream inputStream = file.getInputStream();
//new一个监听器 把service传进去
DataListener dataListener = new DataListener(sysUserService);
//使用这个的.read方法 参数为 文件 对应excel的实体类 new好的监听器
EasyExcelFactory.read(inputStream, ExcelModelBo.class, dataListener)
.sheet(0) //指定读取第一个工作表
.headRowNumber(1) //指定标题行在第一行
.doRead(); //执行实际的读取操作
//最后返回监听器里写好的获取读取失败行数的方法
return dataListener.getFailedRows();
} catch (IOException e) {
throw new RuntimeException();
}
}
}
service 对应mapper
public class SysUserService {
@Resource
private SysUserMapper sysUserMapper;
public int insertByPoList(List poList) {
return sysUserMapper.insertByPoList(poList);
}
public void insertByPoListCheck(List poList) throws ResDBEffectCheckException {
int i = insertByPoList(poList);
if (i == 0) {
throw new ResDBEffectCheckException("Insert Mail DB Effect Check Error! Source [%s]",
poList);
}
}
}
mapper
@Insert("""
""")
int insertByPoList(@Param("list") List list);
4.controller层代码
@Resource
SendService sendService
@PostMapping("/batch")
public ResponseEntity
有用的话大家可以点个赞啊 蟹蟹!!!