问题描述
在做系统的导入导出模块时需要在导入时判断用户导入的表格是否符合给定的模板,该系统导入导出使用的是EasyExcel,因此在实现该功能时是基于EasyExcel的
解决方案
创建Spring Boot项目,并添加如下依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.7</version>
</dependency>
创建导入时数据对应的实体类,并使用@ExcelProperty注解配置模板表头
public class EasyExcelData {
@ExcelProperty(value = "学号", index = 0)
private String no;
@ExcelProperty(value = "姓名", index = 1)
private String name;
@ExcelProperty(value = "性别", index = 2)
private String gender;
private String errorReason;
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getErrorReason() {
return errorReason;
}
public void setErrorReason(String errorReason) {
this.errorReason = errorReason;
}
@Override
public String toString() {
return "EasyExcelData{" +
"no='" + no + '\'' +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", errorReason='" + errorReason + '\'' +
'}';
}
}
创建监听类并继承AnalysisEventListener类,重写invokeHeadMap方法,在该方法中判断是否符合模板
public class EasyExcelDemoListener extends AnalysisEventListener<EasyExcelData> {
private List<EasyExcelData> correctData = new ArrayList<>();
private List<EasyExcelData> errorData = new ArrayList<>();
/**
* 在这里进行模板的判断
* @param headMap 存放着导入表格的表头,键是索引,值是名称
* @param context
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
/*
count 记录模板表头有几个,用以判断用户导入的表格是否和模板完全一致
如果用户导入表格较模板的表头多,但其余符合模板,这样不影响则不需要
*/
int count = 0;
// 获取数据实体的字段列表
Field[] fields = EasyExcelData.class.getDeclaredFields();
// 遍历字段进行判断
for (Field field : fields) {
// 获取当前字段上的ExcelProperty注解信息
ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
// 判断当前字段上是否存在ExcelProperty注解
if (fieldAnnotation != null) {
++count;
// 存在ExcelProperty注解则根据注解的index索引到表头中获取对应的表头名
String headName = headMap.get(fieldAnnotation.index());
// 判断表头是否为空或是否和当前字段设置的表头名不相同
if (StringUtils.isEmpty(headName) || !headName.equals(fieldAnnotation.value()[0])) {
// 如果为空或不相同,则抛出异常不再往下执行
throw new RuntimeException("模板错误,请检查导入模板");
}
}
}
// 判断用户导入表格的标题头是否完全符合模板
if (count != headMap.size()) {
throw new RuntimeException("模板错误,请检查导入模板");
}
}
/**
* 在这里可以进行数据的解析,每读取一条数据都会执行这个方法
* @param easyExcelData 当前读取的数据
* @param analysisContext
*/
@Override
public void invoke(EasyExcelData easyExcelData, AnalysisContext analysisContext) {
if (StringUtils.isEmpty(easyExcelData.getNo())) {
easyExcelData.setErrorReason("学号为空");
errorData.add(easyExcelData);
} else if (StringUtils.isEmpty(easyExcelData.getName())) {
easyExcelData.setErrorReason("姓名为空");
errorData.add(easyExcelData);
} else if (StringUtils.isEmpty(easyExcelData.getGender())) {
easyExcelData.setErrorReason("性别为空");
errorData.add(easyExcelData);
} else {
correctData.add(easyExcelData);
}
}
/**
* 这里是读取完成后执行的方法
* @param analysisContext
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 打印没有错误的数据
System.out.println(correctData);
// 打印有错误的数据
System.out.println(errorData);
}
}
进行测试,测试用到的表格可到EasyExcel判断导入时是否符合给定模板测试表格获取
@Test
public void testEasyExcelReadError() {
// 读取错误表格
String fileName = "excel" + File.separator + "demo-error.xlsx";
EasyExcel.read(fileName, EasyExcelData.class, new EasyExcelDemoListener()).sheet().doRead();
}
@Test
public void testEasyExcelReadCorrect() {
// 读取正确表格
String fileName = "excel" + File.separator + "demo-correct.xlsx";
EasyExcel.read(fileName, EasyExcelData.class, new EasyExcelDemoListener()).sheet().doRead();
}