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);}@Overridepublic 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);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {if (excelImportContext.getInvalid()) {// 验证不成功,进度:50excelResponseService.importFailure(excelResponseDTO, dataList, excelImportContext.getImportClass(),excelImportContext.getParamMap());} else {// 否则成功excelResponseService.importSuccess(excelResponseDTO);}dataBeanMapList.clear();dataList.clear();}@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {log.error("验证异常", exception);String msg = "该行导入出错,请联系管理员;";// 这里捕获异常,包含 ImportObjectMapEventListener 抛出的异常if (exception instanceof ServiceException) {// 处理 ServiceExceptionmsg = ((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);}@Overridepublic 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);}}@Overridepublic boolean skip(BeanMap dataBeanMap, List<BeanMap> dataBeanMapList, Map<String, Object> objectMap) {return false;}
}

其他的都是一样的实现方法,我觉得这个框架真的很有趣,但是我真的没有办法拿出来,想要抽离真的代价太大了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/200374.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何有效的禁止Google Chrome自动更新?

禁止Chrome自动更新 1、背景2、操作步骤 1、背景 众所周知&#xff0c;当我们在使用Selenium进行Web自动化操作&#xff08;如爬虫&#xff09;时&#xff0c;一般会用到ChromeDriver。然而Driver的更新速度明显跟不上Chrome的自动更新。导致我们在使用Selenium进行一些操作时就…

华为ac+fit无线2层漫游配置案例

ap的管理dhcp在ac上&#xff0c;业务dhcp在汇聚交换机上、并且带2层漫游 R1: interface GigabitEthernet0/0/0 ip address 11.1.1.1 255.255.255.0 ip route-static 12.2.2.0 255.255.255.0 11.1.1.2 ip route-static 192.168.0.0 255.255.0.0 11.1.1.2 lsw1: vlan batch 100…

鸿蒙系统扫盲(二):再谈鸿蒙是不是安卓套壳?

最近小米发布了澎湃OS&#xff0c;vivo发布了蓝OS&#xff0c;好像自从华为回归后&#xff0c;大伙都开始写自己的OS了&#xff0c;小米官方承认是套壳安卓&#xff0c;然后被大家喷了&#xff0c;于是鸿蒙是不是安卓套壳的话题又回到了大众的视野&#xff0c;今天在讨论下这个…

React函数组件状态Hook—useState《进阶-对象数组》

React函数组件状态-state 对象 state state 中可以保存任意类型的 JavaScript 值&#xff0c;包括对象。但是&#xff0c;你不应该直接修改存放在 React state 中的对象。相反&#xff0c;当你想要更新⼀个对象时&#xff0c;你需要创建⼀个新的对象&#xff08;或者将其拷⻉⼀…

VS+Qt+C++ Yolov8物体识别窗体程序onnx模型

程序示例精选 VSQtC Yolov8物体识别窗体程序onnx模型 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《VSQtC Yolov8物体识别窗体程序onnx模型》编写代码&#xff0c;代码整洁&#xff0c;规…

Spring接入Metric+Graphite+Grafana搭建监控系统

环境搭建 Metric 主要是记录操作记录&#xff0c;把数据传给Graphite&#xff0c;这个只需要引入依赖就可以了 日志收集系统&#xff0c;可以支持很多的监控系统一般在Spring项目中用其收集数据&#xff0c;可以发送到Graphite等监控系统中一般使用Merter和Timer分别记录成功…

多目标应用:基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度(MATLAB)

一、微网系统运行优化模型 微电网优化模型介绍&#xff1a; 微电网多目标优化调度模型简介_IT猿手的博客-CSDN博客 二、基于非支配排序的蜣螂优化算法NSDBO 基于非支配排序的蜣螂优化算法NSDBO简介&#xff1a; https://blog.csdn.net/weixin46204734/article/details/128…

HTTPS流量抓包分析中出现无法加载key

HTTPS流量抓包分析(TLSv1.2)&#xff0c;这篇文章分析的比较透彻&#xff0c;就不班门弄斧了 https://zhuanlan.zhihu.com/p/635420027 写个小问题&#xff1a;RSA密钥对话框加载rsa key文件的时候注意不要在中文目录下&#xff0c;否则会提示&#xff1a;“Enter the passwor…

IDEA自动注解设置(中文版)

IDEA自动注解设置 1、添加类自动注释 文件 - 设置 - 编辑器 - 文件和代码模板 - Include - File Header /** *description&#xff1a;TODO *author&#xff1a; ${USER} *create&#xff1a; ${DATE} ${TIME} */2、添加类方法自动注释 文件 - 设置 - 编辑器 - 实时模版 - …

米哈游大数据云原生实践

云布道师 近年来&#xff0c;容器、微服务、Kubernetes 等各项云原生技术的日渐成熟&#xff0c;越来越多的公司开始选择拥抱云原生&#xff0c;并将企业应用部署运行在云原生之上。随着米哈游业务的高速发展&#xff0c;大数据离线数据存储量和计算任务量增长迅速&#xff0c…

【剑指offer|图解|链表】链表的中间结点 + 链表中倒数第k个结点

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、算法模板 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. ⛳️链表的中间结点二. ⛳️链表中倒数第k个结点&#x1f4dd;结语 &#x1f4c…

数据结构及八种常用数据结构简介

data-structure 数据结构是一种存在某种关系的元素的集合。“数据” 是指元素&#xff1b;“结构” 是指元素之间存在的关系&#xff0c;分为 “逻辑结构” 和 “物理结构&#xff08;又称存储结构&#xff09;”。 常用的数据结构有 数组&#xff08;array&#xff09;、栈&…

C语言童年生活二三事(ZZULIOJ1091:童年生活二三事(多实例测试))

题目描述 Redraiment小时候走路喜欢蹦蹦跳跳&#xff0c;他最喜欢在楼梯上跳来跳去。 但年幼的他一次只能走上一阶或者一下子蹦上两阶。 现在一共有N阶台阶&#xff0c;请你计算一下Redraiment从第0阶到第N阶共有几种走法。 输入&#xff1a;输入包括多组数据。 每组数据包括一…

selenium下载安装对应的chromedriver并执行

文章目录 selenium对应版本chrome驱动下载114以及之前的chrome版本119/120/121的chrome版本 chromedriver安装执行selenium代码 selenium Selenium是广泛使用的模拟浏览器运行的库&#xff0c;它是一个用于Web应用程序测试的工具。 Selenium测试直接运行在浏览器中&#xff0c…

图片降噪软件 Topaz DeNoise AI mac中文版功能

Topaz DeNoise AI for Mac是一款专业的Mac图片降噪软件。如果你有噪点的相片&#xff0c;可以通过AI智能的方式来处理掉噪点&#xff0c;让照片的噪点降到最 低。有了Topaz DeNoise AI mac版处理图片更方便&#xff0c;更简单。 Topaz DeNoise AI mac软件功能 无任何预约即可在…

Linux进程通信——消息队列

概念 消息队列&#xff0c;是消息的链接表&#xff0c;存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。 特点 1.消息队列是面向记录的&#xff0c;其中的消息具有特定的格式以及特定的优先级。&#xff08;消息队列是结构体&#xff09; 2.消息队列独立于发送与接…

【数据结构】栈详解

目录 1. 前言2. 栈2.1 栈的概念及结构2.2 如何实现栈2.3 数组栈实现2.3.1 top怎么确定2.3.2 栈顶插入2.3.2.1 栈顶插入分析2.3.2.2 栈顶插入代码实现 2.3.3 栈顶删除2.3.4 判空2.3.4.1 分析2.3.4.2 代码实现 2.3.5 栈的元素个数2.3.6 栈销毁2.3.7 栈访问数据 3. 源代码3.1 Stac…

从零开始的C++(十八)

avl树中insert的模拟实现 avl树特点&#xff1a; 1.是搜索二叉树 2.每个结点的左右子树高度差的绝对值不超过2 inser模拟实现&#xff1a; // 右单旋void RotateR(Node* pParent){Node* parent pParent;Node* pr parent->_pRight;Node* prl pr->_pLeft;//记录父节点…

【设计模式】结构型设计模式

结构型设计模式 文章目录 结构型设计模式一、概述二、适配器模式&#xff08;Adapter Pattern&#xff09;2.1 类适配器模式2.2 对象适配器模式2.3 接口适配器模式2.4 小结 三、桥接模式&#xff08;Bridge Pattern&#xff09;四、装饰器模式&#xff08;Decorator Pattern&am…

2 Redis的高级数据结构

1、Bitmaps 首先&#xff0c;最经典的应用场景就是用户日活的统计&#xff0c;比如说签到等。 字段串&#xff1a;“dbydc”&#xff0c;根据对应的ASCII表&#xff0c;最后可以得到对应的二进制&#xff0c;如图所示 一个字符占8位&#xff08;bit&#xff09;&#xff0c;…