一、POM依赖
官网最新版本是3.0.5
我自己项目中的版本
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.7</version>
</dependency>
二、实现
1、controller
@Transactional
@PreAuthorize(value = "system:addCase:excel")
@SysOperationLog(title = "案例导入",businessType = BusinessType.IMPORT)
@ApiOperation(value = "案例导入")
@PostMapping("/excel")
public Result excelWarehousing(List<MultipartFile> files, HttpServletRequest request) {
//批量导入案例
sysCaseService.saveSubject(files, sysCaseService);
return Result.ok();
}
2、SysCaseService
/**
* 批量插入到sql语句中
* @param sysCaseExcelEntity
* @return
*/
Boolean insertListData(List<SysCaseExcelEntity> sysCaseExcelEntity);
3、SysCaseServiceImpl
3-1、RRException是我这边项目的自定义异常
/**
* 案例导入excel
*
* @param fileList
* @param sysCaseService
*/
@Override
public void saveSubject(List<MultipartFile> fileList, SysCaseService sysCaseService) {
if (fileList.isEmpty()) {
throw new RRException("文件异常,请重新选择");
}
for (int i = 0; i < fileList.size(); i++) {
MultipartFile multipartFile = fileList.get(i);
String fileName = multipartFile.getOriginalFilename();
//判断文件类型
if (StringUtils.isNotBlank(fileName)) {
if (!fileName.endsWith(ExcelTypeEnum.XLS.getValue()) && !fileName.endsWith(ExcelTypeEnum.XLSX.getValue())) {
throw new RRException("文件格式错误,请重新选择 xlsx 或 xls 格式文件");
}
try {
//有个很重要的点 UserExcelListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
EasyExcel.read(multipartFile.getInputStream(),
SysCaseExcelEntity.class,
new SysCaseServiceImportExcelListener(sysCaseService)).sheet().doRead();
} catch (Exception e) {
e.printStackTrace();
throw new RRException(e.getMessage());
}
}
}
}
4、接收excel数据的实体类
4-1、@ExcelProperty对应excel的表头的名称
package com.xmtdxt.pc.api.sys.excelListener.excelEntity;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 案例导入 数据实体
* @author LunarYouI
* @create 2022-03-23 11:47
*/
@Data
public class SysCaseExcelEntity implements Serializable {
@ExcelProperty("案例名称")
private String name;
@ExcelProperty("案例报价")
private String startingPrice;
@ExcelProperty("订单报价")
private String orderPrice;
@ExcelProperty("案例类型")
private String caseType;
@ExcelProperty("选择日期")
private String caseDate;
@ExcelProperty("选择场地")
private String site;
@ExcelProperty("选择地址")
private String address;
@ExcelProperty("新郎")
private String protagonistName1;
@ExcelProperty("新娘")
private String protagonistName2;
@ExcelProperty("全部风格(多个逗号分隔)")
private String style;
@ExcelProperty("全部颜色(多个逗号分隔)")
private String color;
@ExcelProperty("案例描述")
private String description;
}
5、SysCaseServiceImportExcelListener,核心代码;
5-1:onException方法进行异常转换;重写了AnalysisEventListener下的方法
5-2:invoke方法下的if条件是我这边用来筛选数据的自定义异常,假设excel中有名字长度大于6,那么代码就终止了。
package com.xmtdxt.pc.api.sys.excelListener.excelListener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.xmtdxt.common.exception.RRException;
import com.xmtdxt.pc.api.sys.excelListener.excelEntity.SysCaseExcelEntity;
import com.xmtdxt.pc.api.sys.service.SysCaseService;
import java.util.ArrayList;
import java.util.List;
/**
* 用户导入excel文件
* 参考代码
* @author LunarYouI
* @create 2022-03-23 11:50
* 每解析一行会回调invoke()方法。
* 整个excel解析结束会执行doAfterAllAnalysed()方法
* 参考:https://www.yuque.com/easyexcel/doc/easyexcel
*/
public class SysCaseServiceImportExcelListener extends AnalysisEventListener<SysCaseExcelEntity> {
SysCaseService sysCaseService;
public SysCaseServiceImportExcelListener(SysCaseService sysCaseService) {
this.sysCaseService = sysCaseService;
}
/**
* 用于暂时存储数据
*/
private List<SysCaseExcelEntity> datas = new ArrayList<>(3000);
/**
* 每隔3000条存储数据库,然后清理list,方便内存回收 具体条数按实际情况确定
*/
private static final int BATCH_COUNT = 3000;
/**
* 记录行数 第一行为表头
*/
int row = 1;
/**
* 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
*
* @param exception
* @param context
* @throws Exception ExcelAnalysisException
*/
@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
System.out.println("解析失败===" + exception.getMessage());
//如果是某一个单元格的转换异常 能获取到具体行号,如果要获取头的信息 配合invokeHeadMap使用
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
throw new RRException("第 " + excelDataConvertException.getRowIndex() + " 行,第 " + excelDataConvertException.getColumnIndex() + " 列解析异常");
}
//若不抛异常 则会继续解析下一行
throw exception;
}
@Override
public void invoke(SysCaseExcelEntity sysCaseExcelEntity, AnalysisContext analysisContext) {
//第一行为表头
row++;
if (sysCaseExcelEntity.getName().length() > 6) {
throw new RRException("第 " + row + " 行:用户名:" + sysCaseExcelEntity.getName() + " 格式错误,字数大于6个");
}
datas.add(sysCaseExcelEntity);
if (datas.size() >= BATCH_COUNT) {
saveData();
datas.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
saveData();
//解析结束销毁不用的资源
datas.clear();
}
/**
* 存储数据库 具体逻辑处理 ================================================================================
*/
private void saveData() {
//循环遍历打印出了数据就证明导入数据成功了!
if (datas != null && datas.size() > 0) {
for (SysCaseExcelEntity data : datas) {
System.out.println("数据-----------------"+data);
}
}
//然后就可以实现将数据存储到数据库中了!
sysCaseService.insertListData(datas);
}
}
假设名字大于 6 了