当前位置: 首页 > news >正文

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;}
}

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

相关文章:

excel导入 Easy Excel

依旧是框架感觉有东西&#xff0c;但是确实是模拟不出来&#xff0c;各种零零散散的件太多了 controller层 ApiOperation(value "导入Excel", notes "导入Excel", httpMethod "POST", response ExcelResponseDTO.class)ApiImplicitParams({…...

html实现图片裁剪处理(附源码)

文章目录 1.设计来源1.1 主界面1.2 裁剪界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134455169 html实现图片裁剪处理(附源码)&#xff0c;支持图片放大缩小&#…...

前端语言报错

1. 语法错误&#xff08;Syntax Errors&#xff09; 这是由于代码不符合语法规则而引起的错误&#xff0c;通常在代码编译阶段发生。示例&#xff1a; javascriptCopy code if (x 10 { // 缺少了右括号 // 代码逻辑 } 2. 类型错误&#xff08;Type Errors&#xff09; 这…...

详细讲解什么是观察者模式

观察者模式&#xff08;Observer Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象&#xff0c;当主题对象状态发生变化时&#xff0c;所有依赖于它的观察者都会得到通知并自动更新。 该模…...

镭速,克服UDP传输缺点的百倍提速传输软件工具

在网络传输中&#xff0c;我们经常会面临这样的困难&#xff1a;文件太大&#xff0c;传输速度太慢&#xff0c;浪费时间和流量&#xff1b;文件太小&#xff0c;传输速度太快&#xff0c;容易出现丢包和乱序&#xff0c;损害数据的完整性和正确性。这些困难的根本在于传输层协…...

Semi-Supervised Multi-Modal Learning with Balanced Spectral Decomposition

Y是所有模态的表征矩阵&#xff0c; ∑ i 1 d h ( λ i ) \sum_{i1}^dh(\lambda_i) ∑i1d​h(λi​) is the proposed eigenvalue-based objective function,the final similarity matrix W for the multimodal data as a block matrix 辅助信息 作者未提供代码...

3296:【例50.2】 计算书费《信息学奥赛一本通编程启蒙(C++版)》

3296&#xff1a;【例50.2】 计算书费《信息学奥赛一本通编程启蒙&#xff08;C版&#xff09;》 【题目描述】 下面是一个图书的单价表&#xff1a; 1、计算概论 28.9 元/本 2、数据结构与算法 32.7 元/本 3、数字逻辑 45.6 元/本 4、C程序设计教程 78 元/本 5、人工智能…...

统一身份认证平台之SSO建设

前言 上篇说道Passwordless无密码技术&#xff0c;也提到了数字时代密码管理的难度&#xff0c;其实在日常的生活中&#xff0c;很多用户也会因为忘记某些网站的登录密码而烦恼。为了方便记忆&#xff0c;很多人都在不同的站点使用相同的用户名和密码&#xff0c;虽然也可以减少…...

【开题报告】基于SpringBoot的膳食营养健康网站的设计与实现

1.选题背景与意义 基于SpringBoot的膳食营养健康网站的设计与实现是一个具有重要意义的选题。背景和意义主要包括以下几点&#xff1a; &#xff08;1&#xff09;社会健康意识的提升&#xff1a;随着人们健康意识的提高&#xff0c;越来越多的人开始关注自己的饮食营养问题。…...

超五类网线和六类网线的相同点和区别

本文对超五类网线和六类网线的相同点和区别进行了简单介绍&#xff0c;帮助大家区分和建立相应的概念。 相同点&#xff1a; &#xff08;1&#xff09;都是网络跳线&#xff0c;用于连接网络设备。 &#xff08;2&#xff09;网线内部由8根不同颜色的线组成。 区别&#xf…...

Linux--初识和基本的指令(1)

目录 前言 0.什么是操作系统 0.1 搭建 Linux 环境 0.2搭建 Linux 环境小结 1.使用 XShell 远程登录 Linux 1.1关于 Linux 桌面 1.2下载安装 XShell 1.3查看 Linux 主机 ip 1.4XShell 下的复制粘贴 2.Linux下基本指令 2.1 pwd命令 2.2 ls命令 2.3 mkdir指令 2.4 cd…...

万宾科技智能井盖传感器,提升市政井盖健康

市政井盖就是城市里不可或缺的基础设施之一&#xff0c;关于它的监测工作可马虎不得。它承载着保护市民的交通安全以及城市正常运转的重要使命。虽然现在城市化的速度很快&#xff0c;但是传统的市政井盖管理方式变得有些力不从心了。井盖的覆盖范围很广&#xff0c;如果单单依…...

transformer学习资料

一、NLP 自然语言处理 NLP 是机器学习在语言学领域的研究&#xff0c;专注于理解与人类语言相关的一切。NLP 的目标不仅是要理解每个单独的单词含义&#xff0c;而且也要理解这些单词与之相关联的上下文之间的意思。 常见的NLP 任务列表&#xff1a; 对整句的分类&#xff1…...

一起学docker系列之四docker的常用命令--系统操作docker命令及镜像命令

目录 前言1 操作 Docker 的命令1.1 启动 Docker1.2 停止 Docker1.3 重启 Docker1.4 查看 Docker 状态1.5 查看 Docker 所有命令的信息1.6 查看某个命令的帮助信息 2 操作镜像的命令2.1 查看所有镜像2.2 搜索某个镜像2.3 下载某个镜像2.4 查看镜像所占空间2.5 删除镜像2.6 强制删…...

MySQL 的执行原理(三)

5.4. InnoDB 中的统计数据 我们前边唠叨查询成本的时候经常用到一些统计数据&#xff0c;比如通过 SHOW TABLE STATUS 可以看到关于表的统计数据&#xff0c;通过 SHOW INDEX 可以看到关于索引 的统计数据&#xff0c;那么这些统计数据是怎么来的呢&#xff1f;它们是以什么方…...

一道好题——分治

一道好题应该有一个简洁的题面。 有一个长度为 n&#xff0c;初始全为 0 的序列 a&#xff0c;另有一个长度为 n 的序列 b&#xff0c;你希望将 a 变成 b&#xff0c;你可以执行如下两种操作&#xff1a; 1 x&#xff1a;将 a 中所有值为 x 的数 11。 2 x&#xff1a;将 a 中下…...

庖丁解牛:NIO核心概念与机制详解 02 _ 缓冲区的细节实现

文章目录 PreOverview状态变量概述PositionLimitCapacity演示&#xff1a; 观察变量 访问方法get() 方法put()方法类型化的 get() 和 put() 方法 缓冲区的使用&#xff1a;一个内部循环 Pre 庖丁解牛&#xff1a;NIO核心概念与机制详解 01 接下来我们来看下缓冲区内部细节 Ov…...

Python itertools模块中的combinations() 函数用法

Python itertools模块中的combinations 函数用法 调用方法示例1示例2 调用方法 itertools.combinations(iterable, r)各个参数意义&#xff1a; iterable&#xff1a;输入数据&#xff0c;数据应该是可迭代的。 r&#xff1a;子序列的长度 返回值&#xff1a;从输入的可迭代数…...

在线预览excel,luckysheet在vue项目中的使用

一. 需求 需要在内网项目中在线预览excel文档&#xff0c;并可以下载 二.在项目中下载并引入luckysheet 1.打开项目根目录&#xff0c;npm i luckyexcel 安装 npm i luckyexcel2.在项目的index.html文件中引入依赖 外网项目中的引入&#xff08;CDN引入&#xff09;&#…...

【python】OpenCV—Image Pyramid(8)

文章目录 1 图像金字塔2 拉普拉斯金字塔 1 图像金字塔 高斯金字塔 在 OpenCV 中使用函数 cv2.pyrDown()&#xff0c;实现图像高斯金字塔操作中的向下采样&#xff0c;使用函数 cv2.pyrUp() 实现图像金字塔操作中的向上采样 import cv2img cv2.imread(C://Users/Administrat…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...