Easyexcel是通过ReadListener
的invoke方法来进行逐行读取的, 所以我们可自定义listener来重写Invoke方法,将bean校验逻辑放入即可。
1.通用listener
业务中可能存在多种导入需求,我们可以创建一个通用listener,就不用一个导入excel需求就创建一个独立的listener了。
@Getter
@Slf4j
public class CustomExcelListener<T> extends AnalysisEventListener<T> {
List<T> successList = new ArrayList<>();
List<String> errMsgList = new ArrayList<>();
/**
* easyexcel对excel文件进行逐行读取
* @param data
* @param context
*/
@Override
public void invoke(T data, AnalysisContext context) {
String errorMsg = EasyExcelValidateHelper.validate(data);
if (StrUtil.isNotEmpty(errorMsg)) {
errMsgList.add(errorMsg);
} else {
successList.add(data);
}
}
/**
* 解析完sheet后调用
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
log.debug("sheet:{}解析完成", context.readSheetHolder().getSheetName());
}
/**
* covert类进行转换时异常调用
* 这里只保存异常信息,继续读取下一行
* @param exception
* @param context
*/
@Override
public void onException(Exception exception, AnalysisContext context) {
// 如果是某一个单元格的转换异常 能获取到具体行号
// 如果要获取头的信息 配合invokeHeadMap使用
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
String errMsg = StrUtil.format("sheet:[{}], 第{}行,第{}列解析异常;",
context.readSheetHolder().getSheetName(), excelDataConvertException.getRowIndex() + 1, excelDataConvertException.getColumnIndex() + 1);
errMsgList.add(errMsg);
}
}
2.Bean校验工具类
public class EasyExcelValidateHelper {
private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
/**
* easyexcel + hibearnate校验
* @param excelDataObj
* @param <T>
* @return
*/
public static <T> String validate(T excelDataObj) {
StringBuilder result = new StringBuilder();
Set<ConstraintViolation<T>> set = validator.validate(excelDataObj, Default.class);
if (set != null && !set.isEmpty()) {
for (ConstraintViolation<T> cv : set) {
Field declaredField = ReflectUtil.getField(excelDataObj.getClass(), cv.getPropertyPath().toString());
ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);
//拼接错误信息,包含当前出错数据的标题名字+错误信息
result.append(annotation.value()[0] + cv.getMessage()).append(";");
}
}
return result.toString();
}
}