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.mzph.cn/news/145398.shtml

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

相关文章

(论文阅读32/100)Flowing convnets for human pose estimation in videos

32.文献阅读笔记 简介 题目 Flowing convnets for human pose estimation in videos 作者 Tomas Pfister, James Charles, and Andrew Zisserman, ICCV, 2015. 原文链接 https://arxiv.org/pdf/1506.02897.pdf 关键词 Human Pose Estimation in Videos 研究问题 视频…

leetcode刷题日志-58最后一个单词的长度

给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 示例 1&#xff1a; 输入&#xff1a;s “Hello World” 输出&#xff1a;5 解释&a…

11.16 知识总结(模型层更多内容)

一、 多表查询&#xff08;跨表查询&#xff09; <br class"Apple-interchange-newline"><div></div> 子查询&#xff1a;分步查询 链表查询&#xff1a;把多个有关系的表拼接成一个大表(虚拟表) inner join left join right join 1.1 基于双下划…

【2016年数据结构真题】

已知由n&#xff08;M>2&#xff09;个正整数构成的集合A{a<k<n},将其划分为两个不相交的子集A1 和A2&#xff0c;元素个数分别是n1和n2&#xff0c;A1和A2中的元素之和分别为S1和S2。设计一个尽可能高效的划分算法&#xff0c;满足|n1-n2|最小且|s1-s2|最大。要求…

Ubuntu16.04上安装Docker

Ubuntu16.04上安装Docker 更新 apt 包索引: sudo apt-get update安装依赖包,以便使用 HTTPS 仓库 sudo apt-get install apt-transport-https ca-certificates curl software-properties-common添加 Docker GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu…

JVM——运行时数据区(堆+方法区+直接内存)

目录 1.Java堆2.方法区**方法区&#xff08;Method Area&#xff09;溢出**方法区&#xff08;Method Area&#xff09;字符串常量池静态变量的存储 3.直接内存(Direct Memory) 1.Java堆 ⚫ 一般Java程序中堆内存是空间最大的一块内存区域。创建出来的对象都存在于堆上。 ⚫ 栈…

matlab二维曲面散点图插值方法

在 MATLAB 中&#xff0c;你可以使用以下函数进行二维曲面散点插值&#xff1a; griddata: 该函数可以在散点数据上进行二维插值&#xff0c;生成平滑的曲面。它支持多种插值方法&#xff0c;包括三次样条插值、最近邻插值、线性插值和自然邻近法插值。 scatteredInterpolant:…

Centos7.9用rancher来快速部署K8S

什么是 Rancher&#xff1f; Rancher 是一个 Kubernetes 管理工具&#xff0c;让你能在任何地方和任何提供商上部署和运行集群。 Rancher 可以创建来自 Kubernetes 托管服务提供商的集群&#xff0c;创建节点并安装 Kubernetes&#xff0c;或者导入在任何地方运行的现有 Kube…

OpenCV入门5——OpenCV的算术与位运算

文章目录 图像的加法运算图像的减法运算图像的乘除运算图像的融合OpenCV位运算-非操作OpenCV位操作-与运算OpenCV位操作-或与异或为图像添加水印 图像的加法运算 # -*- coding: utf-8 -*- import cv2 import numpy as npimg cv2.imread(E://pic//4.jpg)# 图的加法运算就是矩阵…

EasyCVR视频监控+AI智能分析网关如何助力木材厂安全生产?

旭帆科技有很多工厂的视频监管方案&#xff0c;小编也经常分享出来供大家参考。近期&#xff0c;又有伙伴后台私信我们想要关于木材厂的方案。针对木材厂的生产过程与特性以及安全风险等&#xff0c;我们来分享一下相关的监管方案&#xff1a; 1&#xff09;温湿度监测&#xf…

技巧篇:Mac 环境PyCharm 配置 python Anaconda

Mac 中 PyCharm 配置 python Anaconda环境 在 python 开发中我们最常用的IDE就是PyCharm&#xff0c;有关PyCharm的优点这里就不在赘述。在项目开发中我们经常用到许多第三方库&#xff0c;用的最多的命令就是pip install 第三方库名 进行安装。现在你可以使用一个工具来帮你解…

前端开发学习 (一) 搭建Vue基础环境

一、环境搭建 1、安装nodejs #下载地址 https://nodejs.org/dist/v20.9.0/node-v20.9.0-x64.msi 2、配置环境变量 上面下载完安装包后自行安装&#xff0c;安装完成后安装下图操作添加环境变量 #查看版本 node --version v20.9.0# npm --version 10.1.03、配置npm加速源 np…

2.c++基础语法

文章目录 1.c 程序结构关键字标识符、操作符、标点预处理指令注释main 主函数命名空间 2.c 变量和常量变量 3.c 数组和容器4.c 程序流程5.c字符和字符串 1.c 程序结构 关键字 关键字事程序保留的&#xff0c;程序员不能使用&#xff0c;c的常见关键字如下图&#xff1a; 标识…

机器人导航+OPENCV透视变换示例代码

透视变换又称四点变换&#xff0c;所以不能用于5边形这样的图形变换&#xff0c;不是真正的透视变换&#xff0c;但是这个方法可以把机器人看到的图像转换为俯视图&#xff0c;这样就可以建立地图&#xff0c;要不然怎么建立地图呢。 void CrelaxMyFriendDlg::OnBnClickedOk()…

Ubuntu 18.04无网络连接的n种可能办法

文章目录 网络图标消失&#xff0c;Ubuntu无网络连接VMware上Ubuntu18.04&#xff0c;桥接了多个网卡&#xff0c;其中一个用来上网&#xff0c;均设置为静态ip网络桥接链路没有接对路由不对 网络图标消失&#xff0c;Ubuntu无网络连接 sudo service network-manager stop sud…

增删改查mysql

查询 -- 查询表结果-- 查看 当前数据库下的表show tables;-- 查看指定的表desc tb_emp; -- td_emp 是表名-- 查看 数据库的见表语句show create table tb_emp; 修改 -- 修改表结构 -- 修改 为表 tb_emp 添加字段 qq varchar(11) alter table tb_emp add qq varchar(11) …

【LeetCode刷题-滑动窗口】--340.至多包含K个不同字符的最长子串

340.至多包含K个不同字符的最长子串 class Solution {public int lengthOfLongestSubstringKDistinct(String s, int k) {int len s.length();if(len < k){return len;}//滑动窗口的左右指针int left 0,right 0;//定义一个哈希映射HashMap<Character,Integer> hash…

使用Postman进行压力测试

1.打开Postman新建测试接口 2.点击右边保存&#xff0c;选择一个文件集合&#xff0c;如果没有就创建&#xff0c;然后保存 就是这个东西&#xff0c;这里不便展示出来&#xff0c;压力测试需要在文件夹里面进行 3.选择要测试的接口&#xff0c;iterations 表示请求发起次数&a…

基于Vue+SpringBoot的大学计算机课程管理平台 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 实验课程档案模块2.2 实验资源模块2.3 学生实验模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 实验课程档案表3.2.2 实验资源表3.2.3 学生实验表 四、系统展示五、核心代码5.1 一键生成实验5.2 提交实验5.3 批阅实…

金蝶云星空签出元数据提示“数据中心业务对象版本高于应用版本”

文章目录 数据中心业务对象版本高于应用版本签出元数据提示建议 数据中心业务对象版本高于应用版本 签出元数据提示 建议 每次签出元数据前&#xff0c;先获取最新的代码后再签出&#xff0c;如果还是提示&#xff0c;那就根据你的情况选择版本。