excel导入 Easy Excel
依旧是框架感觉有东西,但是确实是模拟不出来,各种零零散散的件太多了
controller层
@ApiOperation(value = "导入Excel", notes = "导入Excel", httpMethod = "POST", response = ExcelResponseDTO.class)
@ApiImplicitParams({
@ApiImplicitParam(name = "X-Person-Id", value = "登录人ID", paramType = "header", dataType = "long", required = true),
@ApiImplicitParam(name = "X-Person-Name", value = "登录人姓名", paramType = "header", dataType = "string", required = true),
@ApiImplicitParam(name = "X-Data-Permission", value = "数据安全性", paramType = "header", dataType = "String", required = true),
@ApiImplicitParam(name = "X-Business-Group-Id", value = "用户所属业务组编号", paramType = "header", dataType = "long", required = true, defaultValue = "1001"),
@ApiImplicitParam(name = "multipartFile", value = "附件", dataType = "__file", required = true),
@ApiImplicitParam(name = "modelType", value = "导入模块标示,严格大小写,例如:BaseInfo", dataType = "string", required = true)
})
@ApiResponses({
@ApiResponse(code = 204, message = "导入失败"),
@ApiResponse(code = 200, message = "导入成功")
})
@PostMapping("/excel/{modelType}")
public ResponseEntity<Object> excel(
@RequestHeader("X-Person-Id") Long xPersonId,
@RequestHeader("X-Person-Name") String xPersonName,
@RequestHeader("X-Data-Permission") String dataPermission,
@RequestHeader("X-Business-Group-Id") Long xBusinessGroupId,
@RequestPart("multipartFile") MultipartFile multipartFile,
@PathVariable("modelType") String modelType,
@RequestParam(value = IMPORT_PARAM_MAP_K1, required = false) String param1,
@RequestParam(value = IMPORT_PARAM_MAP_K2, required = false) String param2,
@RequestParam(value = IMPORT_PARAM_MAP_K3, required = false) String param3,
@RequestParam(value = IMPORT_PARAM_MAP_K4, required = false) String param4,
@RequestParam(value = IMPORT_PARAM_MAP_K5, required = false) String param5) {
if (!multipartFile.getOriginalFilename().endsWith(EXCEL_SUFFIX_XLSX) &&
!multipartFile.getOriginalFilename().endsWith(EXCEL_SUFFIX_XLS)) {
return new ResponseEntity<>(new MessageResponse("导入暂时只支持[" + EXCEL_SUFFIX_XLSX + "]或[" + EXCEL_SUFFIX_XLS + "]格式的文件!"), HttpStatus.NOT_FOUND);
}
Map<String, String> paramMap = fillParamMap(dataPermission,param1, param2, param3, param4, param5);
/**
* 导入逻辑
* 1.上传文件到aws
* 2.存储上传记录到redis
* 3.异步请求获取导入记录
* 4.从记录中获取需要执行的记录
* 5.执行记录并把进度放入redis
*/
try {
Class<?> iClass = this.foundClass(modelType);
ExcelResponseDTO excelResponseDTO = excelResponseService.buildExcelResponse(xPersonId, xPersonName, xBusinessGroupId, multipartFile,this.getRequestHeaderContext());
importService.importExcel(excelResponseDTO, iClass, paramMap);
return ResponseEntity.ok(excelResponseDTO);
} catch (ClassNotFoundException e) {
log.error("com.chinaunicom.ihr.coreperson.web.ImportController.excel", e);
return new ResponseEntity<>(new MessageResponse("导入模块未找到!"), HttpStatus.NOT_FOUND);
} catch (Exception e) {
log.error("com.chinaunicom.ihr.coreperson.web.ImportController.excel", e);
return new ResponseEntity<>(new MessageResponse("系统暂时不支持上传,请联系管理员!"), HttpStatus.NOT_FOUND);
}
}
我们一块一块的分析。
首先开始时对于excel不同的版本的一个处理
if (!multipartFile.getOriginalFilename().endsWith(EXCEL_SUFFIX_XLSX) &&
!multipartFile.getOriginalFilename().endsWith(EXCEL_SUFFIX_XLS)) {
return new ResponseEntity<>(new MessageResponse("导入暂时只支持[" + EXCEL_SUFFIX_XLSX + "]或[" + EXCEL_SUFFIX_XLS + "]格式的文件!"), HttpStatus.NOT_FOUND);
}
然后是将接口传入的参数储存进map中便于后续调用
Map<String, String> paramMap = fillParamMap(dataPermission,param1, param2, param3, param4, param5);
因为这个导入是一个通用方法,传入不同的实体类名称,去读取制定的类
Class<?> iClass = this.foundClass(modelType);
private Class foundClass(String modelType) throws ClassNotFoundException {
// 获取模块 加载 com.chinaunicom.ihr.coreperson.dao.excel.domain. 下的导入类
return Class.forName(IMPORT_DOMAIN_PACKAGE_NAME + "." + modelType + "Import");
}
这是所有的导入的类,
@Getter
@Setter
@ToString
@ExcelImportServiceTag(PersonBaseInfoImportService.class)
@CloseImportOperateStatus(closeDelete = true, closeUpdate = true, closeRenew = false, closeModify = false)
public class PersonBaseInfoNewImport {
@IdVerify(PersonBaseInfoService.class)
@ExcelProperty(value = "数据唯一标识", index = 0)
protected String id;
@OperateStatusVerify
@ExcelProperty(value = "操作状态[创建,更正,更新]", index = 1)
protected String operateStatus;
/**
* 使用操作日期作为生效日期
* 生效日期就是加入本企业日期
*/
@NotEmptyVerify
@ExcelProperty(value = "生效日期(*)(日期格式:1990/1/1)" + YELLOW_CELL_SUFFIX, index = 2)
protected String operateDate;
/**
* 证件类型
*/
@GlobalLookupCodeInfoVerify(value = "证件类型有误;", lookupType = LookupType.PERSON_ID_CARD_TYPE)
@ExcelProperty(value = "证件类型(*)" + YELLOW_CELL_SUFFIX, index = 3)
private String idCardType;
/**
* 证件编号
*/
@IdCardNumberVerify
@ExcelProperty(value = "证件编号(*)" + YELLOW_CELL_SUFFIX, index = 4)
private String idCardNumber;
/**
* 是否残疾人
*/
@BooleanVerify("是否残疾人有误;")
@ExcelProperty(value = "是否残疾人(*)(是/否)" + YELLOW_CELL_SUFFIX, index = 5)
private String handicapped;
/**
* 是否外籍人员
*/
@BooleanVerify("是否外籍人员有误;")
@ExcelProperty(value = "是否外籍人员(*)(是/否)" + YELLOW_CELL_SUFFIX, index = 6)
private String foreigner;
/**
* 员工编号
*/
@CreateCanEmptyVerify("员工编号不能为空;")
@PersonNoUniqueVerify
@ExcelProperty(value = "员工编号(*)" + YELLOW_CELL_SUFFIX, index = 7)
private String employeeNumber;
/**
* 姓名
*/
@NotEmptyVerify
@ExcelProperty(value = "姓名(*)" + YELLOW_CELL_SUFFIX, index = 8)
private String chineseName;
/**
* 英文名
*/
@ExcelProperty(value = "英文名", index = 9)
private String englishName;
/**
* 用工性质
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "用工性质有误;", lookupType = LookupType.PERSON_EMPLOYMENT_NATURE)
@EmploymentNatureVerify
@ExcelProperty(value = "用工性质(*)" + YELLOW_CELL_SUFFIX, index = 10)
private String employmentNature;
/**
* 性别:1 男 0 女
*/
@SexVerify("性别有误;")
@ExcelProperty(value = "性别(*)(1/男 0/女)" + YELLOW_CELL_SUFFIX, index = 11)
private String sex;
/**
* 婚姻状况
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "婚姻状况有误;", lookupType = LookupType.PERSON_MARITAL_STATUS)
@ExcelProperty(value = "婚姻状况(*)" + YELLOW_CELL_SUFFIX, index = 12)
private String maritalStatus;
/**
* 出生日期
*/
@NotEmptyVerify
@DateVerify("出生日期有误;")
@ExcelProperty(value = "出生日期(*)(日期格式:1990/1/1)" + YELLOW_CELL_SUFFIX, index = 13)
private String dateOfBirth;
/**
* 国籍
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "国籍有误;", lookupType = LookupType.PERSON_NATIONALITY)
@ExcelProperty(value = "国籍(*)" + YELLOW_CELL_SUFFIX, index = 14)
private String nationality;
/**
* 民族
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "民族有误;", lookupType = LookupType.PERSON_ETHNICITY)
@ExcelProperty(value = "民族(*)" + YELLOW_CELL_SUFFIX, index = 15)
private String ethnicity;
/**
* 籍贯
*/
@NotEmptyVerify
@ExcelProperty(value = "籍贯(*)" + YELLOW_CELL_SUFFIX, index = 16)
private String nativePlace;
/**
* 出生地
*/
@ExcelProperty(value = "出生地", index = 17)
private String townOfBirth;
/**
* 户籍所在地
*/
@ExcelProperty(value = "户籍所在地", index = 18)
private String domicile;
/**
* 政治面貌
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "政治面貌;", lookupType = LookupType.PERSON_POLITICAL)
@ExcelProperty(value = "政治面貌(*)" + YELLOW_CELL_SUFFIX, index = 19)
private String political;
/**
* 公司邮箱
*/
@ExcelProperty(value = "公司邮箱", index = 20)
private String officeEmail;
/**
* 手机号码
*/
@NotEmptyVerify
@MobilePhoneNoVerify
@ExcelProperty(value = "手机号码(*)" + YELLOW_CELL_SUFFIX, index = 21)
private String phoneNumber;
/**
* 个人邮箱
*/
@ExcelProperty(value = "个人邮箱", index = 22)
private String personEmail;
/**
* 最高学历
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "最高学历有误;", lookupType = LookupType.PERSON_HIGHEST_EDUCATION)
@ExcelProperty(value = "最高学历(*)" + YELLOW_CELL_SUFFIX, index = 23)
private String highestEducation;
/**
* 是否职业经理人 (1 是 0 否)
*/
@NotEmptyVerify
@ProfessionalManageVerify("是否职业经理人有误;")
@ExcelProperty(value = "是否职业经理人(*)" + YELLOW_CELL_SUFFIX, index = 24)
private String professionalManager;
/**
* 学历类型
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "学历类型有误;", lookupType = LookupType.EDUCATION_TYPE)
@ExcelProperty(value = "学历类型(*)" + YELLOW_CELL_SUFFIX, index = 25)
private String educationType;
/**
* 最高学位
*/
@GlobalLookupCodeInfoVerify(value = "最高学位有误;", lookupType = LookupType.PERSON_HIGHEST_DEGREE)
@ExcelProperty(value = "最高学位", index = 26)
private String highestDegree;
/**
* 参加工作日期
*/
@NotEmptyVerify
@DateVerify("参加工作日期有误;")
@ExcelProperty(value = "参加工作日期(日期格式:1990/1/1)(*)" + YELLOW_CELL_SUFFIX, index = 27)
private String dateOfWork;
/**
* 社会工龄调整值(月)
*/
@IntegerVerify("社会工龄调整值有误;")
@ExcelProperty(value = "社会工龄调整值(月)", index = 28)
private String dateOfWorkAdj;
/**
* 企业工龄调整值(月)
*/
@IntegerVerify("企业工龄调整值有误;")
@ExcelProperty(value = "企业工龄调整值(月)", index = 29)
private String dateOfJoinAdj;
/**
* 加入本企业途径
*/
@GlobalLookupCodeInfoVerify(value = "加入本企业途径有误;", lookupType = LookupType.PERSON_WAY_TO_JOIN)
@ExcelProperty(value = "加入本企业途径", index = 30)
private String wayToJoin;
/**
* 劳务派遣入本企业日期
*/
@DateVerify("劳务派遣入本企业日期有误;")
@ExcelProperty(value = "劳务派遣入本企业日期(日期格式:1990/1/1)", index = 31)
private String dateOfLaborDispatch;
/**
* 劳务派遣工龄调整值(月)
*/
@IntegerVerify("劳务派遣工龄调整值有误;")
@ExcelProperty(value = "劳务派遣工龄调整值(月)", index = 32)
private String dateOfLaborDispatchAdj;
/**
* 部门
*/
@NotEmptyVerify
@OrgCodeVerify
@ExcelProperty(value = "部门编码(*)" + YELLOW_CELL_SUFFIX, index = 33)
private String orgCode;
@ExcelProperty(value = "部门名称", index = 34)
private String orgName;
/**
* 职位
*/
@NotEmptyVerify
@PositionCodeVerify
@ExcelProperty(value = "职位编码(*)" + YELLOW_CELL_SUFFIX, index = 35)
private String positionCode;
@ExcelProperty(value = "职位名称", index = 36)
private String positionName;
/**
* 职务
*/
@JobCodeVerify
@ExcelProperty(value = "职务编码", index = 37)
private String jobCode;
@ExcelProperty(value = "职务名称", index = 38)
private String jobName;
/**
* 在岗类别
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "在岗类别有误;", lookupType = LookupType.PERSON_ON_DUTY_CATEGORY)
@ExcelProperty(value = "在岗类别(*)" + YELLOW_CELL_SUFFIX, index = 39)
private String onDutyCategory;
/**
* 人员类别
*/
@GlobalLookupCodeInfoVerify(value = "人员类别有误;", lookupType = LookupType.PERSON_EMPLOYEE_CATEGORY)
@ExcelProperty(value = "人员类别", index = 40)
private String employeeCategory;
/**
* 上级主管
*/
@SeniorRoleVerify
@ExcelProperty(value = "上级主管员工编号", index = 41)
private String seniorRoleNo;
@ExcelProperty(value = "上级主管姓名", index = 42)
private String seniorRoleName;
/**
* 岗级
*/
@NotEmptyVerify
@GlobalLookupCodeInfoVerify(value = "职位级别有误;", lookupType = LookupType.PERSON_GRADE)
@ExcelProperty(value = "职位级别(*)" + YELLOW_CELL_SUFFIX, index = 43)
private String grade;
/**
* 退伍时间
*/
@DateVerify("退伍时间有误;")
@ExcelProperty(value = "退伍时间", index = 44)
private String dateOfDisbandment;
/**
* 党内职务
*/
@GlobalLookupCodeInfoVerify(value = "党内职务有误;", lookupType = LookupType.PARTY_JOB)
@ExcelProperty(value = "党内职务", index = 45)
private String jobOnParty;
/**
* 工龄
*/
@ExcelProperty(value = "工龄", index = 46)
private String workYear;
/**
* 职位备注
*/
@ExcelProperty(value = "职位备注", index = 47)
private String positionRemark;
@ExcelProperty(value = "报错提示", index = 48)
protected String message;
}
这个实体类大有文章,我们先按照顺序看代码后续再回来看。
ExcelResponseDTO excelResponseDTO = excelResponseService.buildExcelResponse(xPersonId, xPersonName, xBusinessGroupId, multipartFile,this.getRequestHeaderContext());
/**
* 构建一个 ExcelResponse
*
* @param xPersonId
* @param xPersonName
* @param xBusinessGroupId
* @param multipartFile
* @return
*/
public ExcelResponseDTO buildExcelResponse(Long xPersonId, String xPersonName, Long xBusinessGroupId, MultipartFile multipartFile, RequestHeaderContext requestHeaderContext) {
String url = uploadService.uploadFile(xPersonId, multipartFile);
ExcelResponseDTO excelResponseDTO = new ExcelResponseDTO(xPersonId, xPersonName, xBusinessGroupId,
url, multipartFile.getOriginalFilename(),requestHeaderContext);
manageable.putExcelResponse(excelResponseDTO);
return excelResponseDTO;
}
实话说从开始一直没有看懂为啥要把导入的文件存起来,会占用空间吧,我能够理解的想法就是,这样可以不用将文件存储在内容中,然后再讲对象读取出来用于后续的导入以及校验,
importService.importExcel(excelResponseDTO, iClass, paramMap);
public void importExcel(ExcelResponseDTO excelResponseDTO, Class<?> iClass, Map<String, String> paramMap) {
// 导入上下文
ExcelImportContext excelImportContext = new ExcelImportContext(iClass, excelResponseDTO.getPersonId(),
excelResponseDTO.getPersonName(), excelResponseDTO.getBusinessGroupId(), paramMap);
String url = uploadService.getRealPath(excelResponseDTO.getAddress());
try (InputStream inputStream = new BufferedInputStream(new URL(url).openConnection().getInputStream())) {
boolean bo = false;
List<Class<?>> queue = Collections.singletonList(iClass);
// 如果是多个,获取多个的导入类
ExcelMultipleImportClassTag multipleImportClassTag = iClass.getAnnotation(ExcelMultipleImportClassTag.class);
if (Objects.nonNull(multipleImportClassTag)) {
queue = Arrays.asList(multipleImportClassTag.value());
// 是否多sheet页对应同一个导入模板
bo = multipleImportClassTag.mulSheet();
}
// 队列执行
for (Class<?> ic : queue) {
EasyExcel
.read(inputStream)
.head(ic)
.password(EasyExcelUtils.getPassword(ic))
.headRowNumber(EasyExcelUtils.getHeadRowNumber(ic))
.registerReadListener(new ImportVerifyEventListener(excelImportContext, excelResponseDTO))
.registerReadListener(new ImportObjectMapEventListener(excelImportContext))
.sheet(EasyExcelUtils.getSheetIndex(ic))
.doRead();
}
// 如果多sheet页对应同一导入类
if (bo) {
// 获取sheet页数量
Workbook workbook = Workbook.getWorkbook(inputStream);
Sheet[] sheets = workbook.getSheets();
//
for (int i = multipleImportClassTag.index(); i < sheets.length; i++) {
EasyExcel
.read(inputStream)
.head(multipleImportClassTag.mulSheetToTemplate())
.password(EasyExcelUtils.getPassword(multipleImportClassTag.mulSheetToTemplate()))
.headRowNumber(EasyExcelUtils.getHeadRowNumber(multipleImportClassTag.mulSheetToTemplate()))
.registerReadListener(new ImportVerifyEventListener(excelImportContext, excelResponseDTO))
.registerReadListener(new ImportObjectMapEventListener(excelImportContext))
.sheet(i-1)
.doRead();
}
}
} catch (Exception e) {
excelResponseDTO.setResult("导入出错,请检查与标准模板的差异或联系管理员");
excelResponseService.importFailure(excelResponseDTO);
log.error("com.chinaunicom.ihr.coreperson.service.BaseImportService.importExcel Exception:", e);
}
}
其实这一块才是主要去实现导入以及导入的字段的校验的地方,我也是用过easyexcel但是我感觉这个项目中是用的高级用法,包括easyexcel在官网的demo真的好简单
主要是这一块的两个类,去实现的具体的校验以及具体的导入
public class ImportVerifyEventListener extends AnalysisEventListener {
/**
* 处理 信息dto
*/
private final ExcelResponseService excelResponseService;
/**
* 类验证字段之前处理器
*/
private final List<VerifyProcess> classVerifyFieldBeforeList = new ArrayList<>();
/**
* 类验证字段之后处理器
*/
private final List<VerifyProcess> classVerifyFieldAfterList = new ArrayList<>();
/**
* 字段验证处理器
*/
private final Map<Integer, List<VerifyProcess>> fieldVerifyMap = new TreeMap<>();
/**
* 导入类 index 与 字段集合
*/
private Map<Integer, Field> fieldMap = new TreeMap<>();
/**
* 导入上下文
*/
private ExcelImportContext excelImportContext;
/**
* 导入 信息dto
*/
private ExcelResponseDTO excelResponseDTO;
/**
* 当前的数据Map
*/
private BeanMap currentDataBeanMap;
/**
* 所有已经读取出来的数据BeanMap(包含当前)
*/
private List<BeanMap> dataBeanMapList = new ArrayList<>();
/**
* 所有的数据 Object 如果最后验证完无效,那么导出的就是这个List
*/
private List<Object> dataList = new ArrayList<>();
public ImportVerifyEventListener(ExcelImportContext excelImportContext, ExcelResponseDTO excelResponseDTO) {
this.excelImportContext = excelImportContext;
this.excelResponseDTO = excelResponseDTO;
this.excelResponseService = SpringContextUtils.getApplicationContext().getBean(ExcelResponseService.class);
this.initClassVerifyMap();
this.initFieldMap();
this.initFieldVerifyMap();
}
/**
* 初始化类验证处理器
*/
private void initClassVerifyMap() {
for (Annotation annotation : excelImportContext.getImportClass().getAnnotations()) {
VerifyProcessTag processTag = annotation.annotationType().getAnnotation(VerifyProcessTag.class);
if (Objects.nonNull(processTag)) {
if (processTag.fieldBefore()) {
classVerifyFieldBeforeList.add(buildClassVerifyProcess(processTag.processClass(), annotation, processTag.order()));
}
if (processTag.fieldAfter()) {
classVerifyFieldAfterList.add(buildClassVerifyProcess(processTag.processClass(), annotation, processTag.order()));
}
}
}
classVerifyFieldBeforeList.sort(Comparator.comparingInt(VerifyProcess::getOrder));
classVerifyFieldAfterList.sort(Comparator.comparingInt(VerifyProcess::getOrder));
}
/**
* 初始化字段Map
*
* @return
*/
public void initFieldMap() {
List<Field> fieldList = new ArrayList<>();
// 当为空时即还没有初始化
Class<?> tempClass = excelImportContext.getImportClass();
while (tempClass != null) {
Collections.addAll(fieldList, tempClass.getDeclaredFields());
tempClass = tempClass.getSuperclass();
}
for (Field field : fieldList) {
ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class);
if (excelIgnore != null) {
continue;
}
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
if (excelProperty != null && excelProperty.index() >= 0) {
fieldMap.put(excelProperty.index(), field);
}
}
}
/**
* 初始化字段验证处理器
*/
private void initFieldVerifyMap() {
for (Map.Entry<Integer, Field> fieldEntry : fieldMap.entrySet()) {
Field field = fieldEntry.getValue();
List<VerifyProcess> processList = new ArrayList<>();
for (Annotation annotation : field.getAnnotations()) {
FieldVerifyProcessTag processTag = annotation.annotationType().getAnnotation(FieldVerifyProcessTag.class);
if (Objects.nonNull(processTag)) {
processList.add(buildFieldVerifyProcess(processTag.processClass(), annotation, processTag.order(), field));
}
}
processList.sort(Comparator.comparingInt(VerifyProcess::getOrder));
fieldVerifyMap.put(fieldEntry.getKey(), processList);
}
}
/**
* 构造处理器
*
* @param processClass
* @return
*/
private AbstractVerifyProcess buildClassVerifyProcess(Class<? extends AbstractVerifyProcess> processClass, Annotation annotation, int order) {
return ReflectUtil.newInstance(processClass, excelImportContext, annotation, order);
}
/**
* 构造处理器
*
* @param processClass
* @return
*/
private AbstractFieldVerifyProcess buildFieldVerifyProcess(Class<? extends AbstractFieldVerifyProcess> processClass, Annotation annotation, int order, Field field) {
return ReflectUtil.newInstance(processClass, excelImportContext, annotation, order, field);
}
@Override
public void invoke(Object data, AnalysisContext context) {
dataList.add(data);
currentDataBeanMap = BeanMap.create(data);
// 把代入的 message 去掉
currentDataBeanMap.put(IMPORT_MESSAGE_FIELD_NAME, null);
dataBeanMapList.add(currentDataBeanMap);
// 把 data 转换为 Map 并且去掉 null 值
Map<String, Object> objectMap = BeanUtil.beanToMap(data, false, true);
// 字段之前验证的类验证
eachVerifyMap(objectMap, classVerifyFieldBeforeList);
// 字段验证
// 根据字段顺序处理
for (Map.Entry<Integer, List<VerifyProcess>> verifyEntry : fieldVerifyMap.entrySet()) {
// 根据处理器顺序处理
eachVerifyMap(objectMap, verifyEntry.getValue());
}
// 字段之后验证的类验证
eachVerifyMap(objectMap, classVerifyFieldAfterList);
Object message = objectMap.get(IMPORT_MESSAGE_FIELD_NAME);
if (Objects.nonNull(message) && CollectionUtils.isNotEmpty((List) message)) {
currentDataBeanMap.put(IMPORT_MESSAGE_FIELD_NAME, String.join("", (List) message));
excelImportContext.setInvalid(Boolean.TRUE);
}
context.readRowHolder().setCurrentRowAnalysisResult(objectMap);
}
/**
* 循环验证
*
* @param objectMap
* @param verifyList
*/
private void eachVerifyMap(Map<String, Object> objectMap, List<VerifyProcess> verifyList) {
// 字段之后验证的类验证
for (VerifyProcess verifyProcess : verifyList) {
// 只要有一个跳过那么就都跳过
if (verifyProcess.skip(currentDataBeanMap, dataBeanMapList, objectMap)) {
return;
}
verifyProcess.execute(currentDataBeanMap, dataBeanMapList, objectMap);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
if (excelImportContext.getInvalid()) {
// 验证不成功,进度:50
excelResponseService.importFailure(excelResponseDTO, dataList, excelImportContext.getImportClass(),excelImportContext.getParamMap());
} else {
// 否则成功
excelResponseService.importSuccess(excelResponseDTO);
}
dataBeanMapList.clear();
dataList.clear();
}
@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
log.error("验证异常", exception);
String msg = "该行导入出错,请联系管理员;";
// 这里捕获异常,包含 ImportObjectMapEventListener 抛出的异常
if (exception instanceof ServiceException) {
// 处理 ServiceException
msg = ((ServiceException) exception).getMessageResponse().getMsg();
}
String message = (String) currentDataBeanMap.get(IMPORT_MESSAGE_FIELD_NAME);
currentDataBeanMap.put(IMPORT_MESSAGE_FIELD_NAME,
StringUtils.isEmpty(message) ? msg : (message + ";" + msg));
excelImportContext.setInvalid(Boolean.TRUE);
}
}
具体的操作在invoke
里面
这一块我真的踩了好多坑,其实这一块是去读实体类上面的注解,
我们以id为例将几种类型
@IdVerify(PersonBaseInfoService.class)
@ExcelProperty(value = "数据唯一标识", index = 0)
protected String id;
ExcelProperty这是生成excel中的字段名,IdVerify专门写的id的注解,用来验证id字段的
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@FieldVerifyProcessTag(processClass = IdVerifyProcess.class)
public @interface IdVerify {
/**
* 调用查询的 service 类型
*
* @return
*/
Class<? extends ServiceImpl> value();
}
FieldVerifyProcessTag这个注解就是专门用来去实现的类
public class IdVerifyProcess extends AbstractFieldVerifyProcess {
public IdVerifyProcess(ExcelImportContext context, Annotation annotation, int order, Field field) {
super(context, annotation, order, field);
}
@Override
public void execute(BeanMap dataBeanMap, List<BeanMap> dataBeanMapList, Map<String, Object> objectMap) {
if (this.isUpdateOperateStatus(dataBeanMap)
|| this.isDeleteOperateStatus(dataBeanMap)) {
String fieldValue = this.getFieldValue(dataBeanMap);
if (StringUtils.isEmpty(fieldValue)) {
this.setMessage(objectMap, "未找到要操作的数据,操作状态为【更新或更正或更改】时,唯一标识不能为空;");
} else {
try {
fieldValue = ExcelImportUtils.decode(fieldValue, StringUtils.UTF8);
} catch (UnsupportedEncodingException e) {
this.setMessage(objectMap, "ID解码失败;");
}
IdVerify annotation = (IdVerify) this.annotation;
// 如果是带时间戳的类
if (HistoryServiceImpl.class.isAssignableFrom(annotation.value())) {
String operateDate = this.getFieldValue(dataBeanMap, String.class, IMPORT_OPERATE_DATE_FIELD_NAME);
if (StringUtils.isNotEmpty(operateDate)) {
LocalDate localDate = ExcelImportUtils.convertDate(operateDate);
if (Objects.nonNull(localDate)) {
objectMap.put(IMPORT_OPERATE_DATE_FIELD_NAME, localDate);
dataBeanMap.put(IMPORT_OPERATE_DATE_FIELD_NAME, localDate.toString());
// 把日期传入
idVerify(objectMap, fieldValue,
((HistoryServiceImpl) this.getBean(annotation.value())).selectById(fieldValue, localDate));
} else {
this.setMessage(objectMap, "操作日期有误;");
}
} else {
this.setMessage(objectMap, "操作日期不能为空;");
}
} else {
idVerify(objectMap, fieldValue, (this.getBean(annotation.value())).selectById(fieldValue));
}
}
}
}
/**
* 验证 Id
*
* @param objectMap
* @param fieldValue
* @param selectById
*/
private void idVerify(Map<String, Object> objectMap, String fieldValue, Object selectById) {
if (Objects.isNull(selectById)) {
this.setMessage(objectMap, "当前行数据唯一标识的数据在系统中未找到;");
} else {
objectMap.put(field.getName(), fieldValue);
}
}
@Override
public boolean skip(BeanMap dataBeanMap, List<BeanMap> dataBeanMapList, Map<String, Object> objectMap) {
return false;
}
}
其他的都是一样的实现方法,我觉得这个框架真的很有趣,但是我真的没有办法拿出来,想要抽离真的代价太大了