Java与MySQL的绝妙结合:打造高效审批流程

是流程思路等分析🐱‍👤

审批流程🐱‍💻

1️⃣.串行流程

当前节点审批完成后,下一次节点才能进行操作,例如经理通过之后,总监才能审批;


2️⃣.并行流程

一个审批节点需要多人联审。一般有两种方式:会签、或签

  • 会签:

        注意:别跟串行审批混淆。会签的多个角色是平行的,没有上下级关系、前后顺序。

        例如:在某项文件、合同、决策或其他重要事项上,需要多个相关人员进行确认、批准或签署的情况下,参与该过程的人员同时批准,这时会签就能很大程度上提高效率,顺便也能解决人情世故的问题~~。

        会签支持并签:

         业务模式支持:"全部投票"、"按投票比例"、"按投票通过比例"、支持设置 "百分比" 和 "分数" 两种方式。

  • 或签(也有叫"竞签"、"串签"):指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,只要其中任意一人审批即可到下一审批节点;

3️⃣.条件流程

根据不同规则,走不同流程

例如报销5000以下直属领导审批就行,5000~10000需要总监审批。

4️⃣.混合流程

就是上述的流程混合运用;

例如请假的正常流程是到直属领导审批,3天以上需要总监审批。5天以上需要总裁审批。


审批动作🙋‍♀️

1. 通过:通过申请,流转到下一人。原因选填。

2. 驳回:驳回到发起人、驳回到上一环节、驳回到之前的某一环节

3. 保存:保存当前填写的信息。

4. 转交:转交给某人审批

5. 加签:处理者可以在审批时临时增加审核人员

6. 抄送:抄送人会知晓审核过程,但不进行操作


执行动作👩‍🎓

申请:针对当前业务表单信息发起申请,开始审批流程的传递。分为2部分:由申请提交人手动发起申请、由程序自动判断满足触发规则的数据自动发起申请;另外还要注意的2点:是否允许提交人撤销(是、否)、记录编辑(不可编辑、管理员可编辑、管理员和审批人都可编辑 );

通过:当前步骤处理通过,进入下一步骤,若为末步骤,则流程处理完成;

退回:将步骤退回至上一步骤,即返回至上一处理人处,若为首步骤,则不进行退回;

否决:将步骤直接结束,执行结束动作拒绝活动,不再进行操作,或者回退至第一步骤;

撤回:若当前步骤已处理,下一处理人未处理的情况下可进行撤回操作。


节点状态🕵️‍♀️

提交人: 未提交、已提交、处理中、已结束。

处理人: 待处理、已处理。

创建业务工单:提交人登录系统之后,选择想要发起的业务工单,填写业务工单。填写完成可以选择提交或者保存;

未提交:列表中显示所有保存但未提交的业务工单,未提交列表中的业务工单都没有业务工单编号(唯一),状态为“未提交”。提交人可以选择某个业务工单后能方便对其进行修改、删除和提交;

已提交:列表显示所有已经提交的业务工单,有业务工单编号,并显示(未处理)。提交后的业务工单进入处理流程,提交人无法进行修改和删除;

处理中:列表显示所有提交并已经有节点处理的业务工单,提交人可以查询某个业务工单的处理进度;

已结束:列表显示所有已经处理完成的业务工单;

待处理:列表显示所有待处理业务工单;

已处理:列表显示所有当前处理人已处理的业务工单,既被当前处理人流转到下一个流程节点的业务工单;


UI预览🛹


表设计🚧

流程配置表🚗

CREATE TABLE `approval_config` (`approval_config_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '雪花算法',`corp_id` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '企业ID',`node_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '节点名称',`form_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '表单ID 属于那个表单的流程',`approval_auto_pass` tinyint(1) DEFAULT '0' COMMENT '审批节点人员相同时自动通过[1:true;0:false]',`current_node_approver_type` tinyint DEFAULT NULL COMMENT '审批人类型[1:发起人自己;2:指定角色;3:指定人员;4:表单内人员];注:1/3/4存userid、2存roleId',`current_node_approver` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '待审批人如果是角色就是角色ID,如果是其他则是userId格式:[xxx,xxx]',`care_of` tinyint(1) DEFAULT NULL COMMENT '允许审批人转交[1:true;2:false]',`approval_type` tinyint DEFAULT NULL COMMENT '审批类型[1:会签:2:或签]',`approval_node` int DEFAULT NULL COMMENT '审批节点[取值:1~N 从小到大;0:发起节点 、1:是第一个节点、 2:第二个节点 N:是第N个节点;最大的是结束节点]',`carbon_copy_recipients_type` tinyint DEFAULT '1' COMMENT '抄送人类型[1:发起人自己;2:指定角色;3:指定人员;4:表单内人员]',`carbon_copy_recipients` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '抄送人userId 数组格式',`create_time` datetime DEFAULT NULL COMMENT '规则创建时间;默认拿最新的',`group_id` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '分组[标识那些节点是同一个组的]',`visible_fields` json DEFAULT NULL COMMENT '可见字段:[{"bt": false, "kj": true, "kx": true, "field": "create_time", "children": "purchase_requisition_details"}];\r\nkj:可见;kx:可写;kb:必填。如果是最后一个节点就需要单独拉一个配置',PRIMARY KEY (`approval_config_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='审批流程节点规则配置表';

 审批流程发起表🚓

CREATE TABLE `approval_info` (`approval_info_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '雪花算法',`corp_id` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '企业ID',`approval_config_group_id` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则表的groupID',`form_id` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '表单ID 属于那个表单',`founder` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '发起人',`launch_time` datetime NOT NULL COMMENT '发起时间',`end_state` tinyint(1) DEFAULT '0' COMMENT '是否结束流程[1是]',`end_time` datetime DEFAULT NULL COMMENT '流程结束时间',`object_id` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '关联某条数据',`process_progress` int DEFAULT '0' COMMENT '用来记录整个流程进行到那个节点',`record_node_history` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '记录历史经历节点,英文逗号分隔0,1,2,1,2,3 最后一个值和当前节点同步',PRIMARY KEY (`approval_info_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='审批流程发起表';

审批记录表🚕

CREATE TABLE `approval_record` (`approval_record_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '雪花算法',`corp_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '企业ID',`approval_info_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '审批发起表approval_info',`form_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '表单ID 属于那个表单的流程',`approver_user_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '审批人or 转交人 userId',`approver_time` datetime NOT NULL COMMENT '审批时间',`approver_opinions` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '审批意见',`approver_result` tinyint NOT NULL COMMENT '审批结果[1:同意;2:拒绝:3:转交]',`transferee` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '被转交人userId;approver_result=3时必填',`transferee_text` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '转交备注(此字段暂时无用)',`accessory_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '附件数组',`approver_node` tinyint NOT NULL COMMENT '属于个节点的审批记录',`approver_count` tinyint DEFAULT '1' COMMENT '审批次数默认1; 例:当节点B是会签,且有人同意,有人拒绝,当拒绝后会返回上一个节点A。当再次进入节点B时,用来区分,此审批记录是第一次记录还是第二次审批记录或者第N次',PRIMARY KEY (`approval_record_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='审批记录表';

 抄送记录表🛺

CREATE TABLE `approval_carbon_copy` (`carbon_copy_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '雪花',`corp_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '企业ID',`form_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '属于那个表单',`approval_info_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '推送那条审批的ID',`user_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '接收抄送人',`create_time` datetime NOT NULL COMMENT '抄送时间',`read` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已读[1:已读;0:未读]',`approval_node` tinyint NOT NULL COMMENT '那个节点抄送的',PRIMARY KEY (`carbon_copy_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='审批抄送记录表';

思路👩‍🎓👩‍🎓

流程配置

1.通过流程节点规则配置表,配置每个节点的审批人、抄送人、审批规则、可见、可写、必填字段的规则等(可以给不同的表单配置不同的审批规则)。

2.配置完毕即可,每次新增数据,读取流程规则配置表,生成一条审批流程发起记录,记录发起人,发起时间,关联某条流程规则(旧数据还是使用旧流程),流程当前节点等。

3.每个节点的审批人、抄送人、可见、可写、必填字段都是根据流程规则配置表中动态配置。


代码🥇

审批按钮

  @Transactional(rollbackFor = Exception.class)public ResultUtils approval(String token, ApprovalDTO param) {String corpId = TokenUtils.getCorpId(token);String userId = TokenUtils.getUserId(token);LocalDateTime time = LocalDateTime.now();// 找到当前数据待审批节点,是否需要自己审批,或者已经审批过ApprovalInfo info = approvalInfoMapper.selectOne(new QueryWrapper<ApprovalInfo>().eq("corp_id", corpId).eq("object_id", param.getObjectId()).eq("form_id", param.getFormId()).select("approval_info_id", "process_progress", "record_node_history", "end_state","approval_config_group_id","founder"));Assert.isFalse(info.getEndState(), ErrorMsg.msg18);Integer currentNode = info.getProcessProgress();// 当前节点// 每个节点的审批设置List<ApprovalConfig> approvalConfigs = approvalConfigMapper.selectList(new QueryWrapper<ApprovalConfig>().eq("corp_id", corpId).eq("group_id", info.getApprovalConfigGroupId()).eq("form_id", param.getFormId()).select("approval_auto_pass", "current_node_approver_type", "visible_fields","current_node_approver", "care_of", "approval_type", "approval_node", "carbon_copy_recipients_type", "carbon_copy_recipients"));Map<Integer, ApprovalConfig> configMap = approvalConfigs.stream().collect(Collectors.toMap(ApprovalConfig::getApprovalNode, ApprovalConfig -> ApprovalConfig));ApprovalConfig config = configMap.get(info.getProcessProgress());List<String> historyNode = Lists.newArrayList(info.getRecordNodeHistory().split(","));// 历史节点需要剔除最后一个historyNode.remove(historyNode.size() - 1);Bag bag = new HashBag(historyNode);int count = bag.getCount(currentNode.toString());// 这个节点历史是否出现过count = count == 0 ? 1 : (count + 1); // 用于标注这个节点是否多次审批if (param.getType() == 3) {// 转交ApprovalRecord record = new ApprovalRecord();record.setApprovalRecordId(SnowFlakeUtil.getDefaultSnowFlakeId() + "");record.setCorpId(corpId);record.setApprovalInfoId(info.getApprovalInfoId());record.setFormId(param.getFormId());record.setApproverUserId(userId);record.setApproverTime(time);record.setApproverOpinions(param.getMessage());record.setApproverResult(param.getType());record.setTransferee(param.getTransfereeUserId());if (ObjectUtil.isNotEmpty(param.getAccessoryUrl())) {record.setAccessoryUrl(JSONUtil.toJsonStr(param.getAccessoryUrl()));}record.setApproverNode(info.getProcessProgress().byteValue());record.setApproverCount(new Byte(count + ""));approvalRecordMapper.insertSelective(record);return ResultUtils.success();}ApprovalRecord records = approvalRecordMapper.selectOne(new QueryWrapper<ApprovalRecord>().eq("corp_id", corpId).eq("form_id", param.getFormId()).eq("approver_user_id", userId).eq("approval_info_id", info.getApprovalInfoId()).eq("approver_node", currentNode).eq("approver_count", count));Assert.isFalse(ObjectUtil.isNotEmpty(records) && StrUtil.isNotBlank(records.getTransferee()), ErrorMsg.msg29);Assert.isFalse(ObjectUtil.isNotEmpty(records), ErrorMsg.msg16);// 查询是否是被转交人List<String> transferees = approvalRecordMapper.findTransferee(corpId, param.getFormId(), info.getApprovalInfoId(), currentNode, count);if (CollUtil.isEmpty(transferees)) {// 1.是否需要自己审批if (config.getCurrentNodeApproverType() == 2) {// 指定角色// 查询自己拥有那些角色List<UserRole> userRoles = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("user_id", userId).eq("corp_id", corpId).select("role_id"));List<String> roleIds = userRoles.stream().map(key -> key.getRoleId()).collect(Collectors.toList());List<Integer> currentNodeApproverRoleId = JSONUtil.toList(config.getCurrentNodeApprover().toString(), Integer.class);ArrayList<String> integers = new ArrayList<>(roleIds);boolean b = integers.retainAll(currentNodeApproverRoleId);// 存在交集则返回trueAssert.isFalse(!b, ErrorMsg.msg17);} else if (config.getCurrentNodeApproverType()==3){// 指定人员 用户IDList<String> currentNodeApproverUserId = JSONUtil.toList(config.getCurrentNodeApprover().toString(), String.class);boolean contains = currentNodeApproverUserId.contains(userId);Assert.isFalse(!contains, ErrorMsg.msg17);} else if (config.getCurrentNodeApproverType() == 1) {// 发起人自己Assert.isFalse(!info.getFounder().equals(userId), ErrorMsg.msg17);}}if (param.getType() == 2) {// 拒绝approvalRefuse(info, approvalConfigs, param, userId, corpId, count, time);return ResultUtils.success();}// 判断了需要自己审批之后,先编辑数据,然后在进行审批操作JSONObject paramData = param.getMainData();approvalEditData(corpId, paramData, time, userId, param.getFormId());// 进行审批操作if (param.getType() == 1) {// 同意approvalAgreeing(currentNode, info, configMap, param, userId, corpId, time, param.getObjectId());}return ResultUtils.success();}

 审批按钮-拒绝

    /*** 审批按钮-拒绝** @param info            当前数据的审批详情* @param approvalConfigs 审批规则* @param param           参数* @param userId          当前审批人id* @param corpId          企业id* @param count           审批次数*/private void approvalRefuse(ApprovalInfo info, List<ApprovalConfig> approvalConfigs, ApprovalDTO param, String userId, String corpId, int count, LocalDateTime time) {// 生成审批记录ApprovalRecord record = new ApprovalRecord();record.setApprovalRecordId(SnowFlakeUtil.getDefaultSnowFlakeId() + "");record.setCorpId(corpId);record.setApprovalInfoId(info.getApprovalInfoId());record.setFormId(param.getFormId());record.setApproverUserId(userId);record.setApproverTime(time);record.setApproverOpinions(param.getMessage());record.setApproverResult(param.getType());if (ObjectUtil.isNotEmpty(param.getAccessoryUrl())) {record.setAccessoryUrl(JSONUtil.toJsonStr(param.getAccessoryUrl()));}record.setApproverNode(info.getProcessProgress().byteValue());record.setApproverCount(new Byte(count + ""));approvalRecordMapper.insertSelective(record);// 回滚上一个节点info.setProcessProgress(info.getProcessProgress() - 1);info.setRecordNodeHistory(info.getRecordNodeHistory() + "," + info.getProcessProgress());// info.setCurrentState(1);approvalInfoMapper.updateByPrimaryKeySelective(info);if (info.getProcessProgress() == 0) {// 如果回到第一个节点,数据状态则变成初始String formCode = fromConfigMapper.findFormCode(corpId, param.getFormId());commonMapper.updateDataState(formCode, 0, param.getObjectId(), corpId);}}

 审批按钮-同意

    /*** 审批按钮-同意** @param currentNode 处理的当前节点* @param info        流程详情* @param configMap   配置集合 key=节点;val=配置* @param param       参数* @param userId      当前审批人userId* @param corpId      企业ID* @param time        当前时间*/private void approvalAgreeing(Integer currentNode, ApprovalInfo info, Map<Integer, ApprovalConfig> configMap,ApprovalDTO param, String userId, String corpId, LocalDateTime time, String objectId) {// 查询这个节点以前是否审批过List<String> historyNode = Lists.newArrayList(info.getRecordNodeHistory().split(","));// 历史节点需要剔除最后一个historyNode.remove(historyNode.size() - 1);Bag bag = new HashBag(historyNode);int count = bag.getCount(currentNode.toString());// 这个节点历史是否出现过count = count == 0 ? 1 : count + 1; // 用于标注这个节点是否多次审批// 生成审批记录ApprovalRecord record2 = new ApprovalRecord();record2.setApprovalRecordId(SnowFlakeUtil.getDefaultSnowFlakeId() + "");record2.setCorpId(corpId);record2.setApprovalInfoId(info.getApprovalInfoId());record2.setFormId(param.getFormId());record2.setApproverUserId(userId);record2.setApproverTime(time);record2.setApproverOpinions(param.getMessage());record2.setApproverResult(param.getType());if (ObjectUtil.isNotEmpty(param.getAccessoryUrl())) {record2.setAccessoryUrl(JSONUtil.toJsonStr(param.getAccessoryUrl()));}record2.setApproverNode(currentNode.byteValue());record2.setApproverCount(new Byte(count + ""));approvalRecordMapper.insertSelective(record2);// 获取当前节点配置ApprovalConfig currentConfig = configMap.get(currentNode);if (currentConfig.getApprovalType() == 1) {// 1会签// 判断是否是最后一个审批的,如果不是return出去List<String> userIds = null;if (currentConfig.getCurrentNodeApproverType() == 2) {// 角色id// 查询自己拥有那些角色List<UserRole> userRoles = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("user_id", userId).eq("corp_id", corpId).select("user_id"));userIds = userRoles.stream().map(key -> key.getUserId()).collect(Collectors.toList());} else if (currentConfig.getCurrentNodeApproverType()==3){// 用户IDuserIds = JSONUtil.toList(currentConfig.getCurrentNodeApprover().toString(), String.class);} else if (currentConfig.getCurrentNodeApproverType() == 1) {// 发起人自己userIds = Arrays.asList(info.getFounder());}// 查询已经审批的人!=待审批人数则不是最后一个人// 1.查询已经审批的人数Integer count1 = approvalRecordMapper.selectCount(new QueryWrapper<ApprovalRecord>().eq("corp_id", corpId).eq("approval_info_id", info.getApprovalInfoId()).eq("form_id", param.getFormId()).eq("approver_node", currentNode).eq("approver_count", count));if (userIds.size() != count1) {return;// 不是最后一个可以退出}}Integer nextNode = currentNode + 1;// 更新流程信息info.setProcessProgress(nextNode);info.setRecordNodeHistory(info.getRecordNodeHistory() + "," + info.getProcessProgress());// info.setCurrentState(2);// 到这里如果不是或签,就是会签是最后一个人同意可以判断进入下一个节点//  判断下一个节点是不是最后一个节点,如果是可以结束节点了,不是则继续往下递归if ((configMap.keySet().size() - 1) == nextNode) {info.setEndTime(time);info.setEndState(true);//  结束流程approvalInfoMapper.updateByPrimaryKeySelective(info);// 数据状态变成生效String formCode = fromConfigMapper.findFormCode(corpId, param.getFormId());commonMapper.updateDataState(formCode, 2, objectId, corpId);return;}approvalInfoMapper.updateByPrimaryKeySelective(info);// 校验下一个配置是否需要审批ApprovalConfig nextConfig = configMap.get(nextNode);// 下一个节点的配置List<RuleVO> rule = JSONUtil.toList(JSONUtil.parseArray(nextConfig.getVisibleFields()), RuleVO.class);for (RuleVO ruleVO : rule) {if (ruleVO.getKx()) {return;// 判断是否开了可写,如果开了可写,不管有没有开相同审批人自动通过,都不能往下走}}if (nextConfig.getApprovalAutoPass()) {// 开了 审批人员相同自动通过// 1.是否需要自己审批if (nextConfig.getCurrentNodeApproverType() == 2) {// 角色id// 查询自己拥有那些角色List<UserRole> userRoles = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("user_id", userId).eq("corp_id", corpId).select("role_id"));List<String> roleIds = userRoles.stream().map(key -> key.getRoleId()).collect(Collectors.toList());List<Integer> currentNodeApproverRoleId = JSONUtil.toList(nextConfig.getCurrentNodeApprover().toString(), Integer.class);ArrayList<String> integers = new ArrayList<>(roleIds);boolean b = integers.retainAll(currentNodeApproverRoleId);// 存在交集返回trueif (!b) return;} else {// 用户IDList<String> currentNodeApproverUserId = JSONUtil.toList(nextConfig.getCurrentNodeApprover().toString(), String.class);boolean contains = currentNodeApproverUserId.contains(userId);if (!contains) return;}// 需要自己审批approvalAgreeing(nextNode, info, configMap, param, userId, corpId, time, objectId);}// approvalRecordMapper.insertSelective(record2);}

 合并权限(如果最后一个节点存在多个自定义权限组,就需要合并)

/*** 合并权限组** @param roleIds      当前用户拥有的角色* @param dbPowerGroup 自定义权限组*/private List<RuleVO> mergePowerGroup(List<String> roleIds, List<PowerGroup> dbPowerGroup) {List<RuleVO> result = new ArrayList<>();// 判断当前自定义权限组是否包含 当前用户的角色for (PowerGroup power : dbPowerGroup) {List<Integer> dbRoleIds = JSONUtil.toList(power.getRoleId().toString(), Integer.class);List<String> retainAll = new ArrayList<>(roleIds);retainAll.retainAll(dbRoleIds);if (retainAll.size() != 0) {// 存在交集,证明这个自定义权限组有当前操作用户List<RuleVO> rule = JSONUtil.toList(JSONUtil.parseArray(power.getVisibleFields()), RuleVO.class);Map<String, RuleVO> tempMapDB = rule.stream().collect(Collectors.toMap(ruleVo -> ruleVo.getChildren() + ruleVo.getField(), RuleVO -> RuleVO));if (CollUtil.isEmpty(result)) {result = rule;} else {Map<String, RuleVO> tempListMap = result.stream().collect(Collectors.toMap(ruleVo -> ruleVo.getChildren() + ruleVo.getField(), RuleVO -> RuleVO));if (tempMapDB.keySet().size() > result.size()) {// 如果B权限组字段比A权限组多,就拿多的一方进行循环for (RuleVO item : rule) {RuleVO ruleVO = tempListMap.get(item.getChildren() + item.getField());if (ruleVO.getBt()) {item.setBt(ruleVO.getBt());}if (ruleVO.getKj()) {item.setKj(ruleVO.getKj());}if (ruleVO.getKx()) {item.setKx(ruleVO.getKx());}}result = rule;} else {// 否则就拿A权限组遍历for (RuleVO item : result) {// 合并组成新的规则,如果A规则为true,B规则为false,则取true的一方RuleVO ruleDB = tempMapDB.get(item.getChildren() + item.getField());if (ruleDB.getBt()) {item.setBt(ruleDB.getBt());}if (ruleDB.getKj()) {item.setKj(ruleDB.getKj());}if (ruleDB.getKx()) {item.setKx(ruleDB.getKx());}}}}}}return result;}

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

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

相关文章

为什么Python赢了,别的语言都干嘛去了?

人工智能时代&#xff0c;为什么Python大放异彩&#xff0c;别的语言都干嘛去了&#xff1f; 为什么不是使用者众多的Java&#xff1f;也许是Java啰里啰唆&#xff0c;不如Python那么简洁&#xff1f; 为什么不是Ruby&#xff1f; 和Python一样简洁&#xff0c;但是更加优雅。…

【谢希尔 计算机网络】第1章 计算机网络概述

目录 1.1.1计算机网络概念&#xff0c;功能&#xff0c;组成&#xff0c;分类 计算机网络的概念 计算机网络的功能 计算机网络的组成 计算机网络的分类 1.1.2标准化工作 1.1.3速率相关的性能指标 速率 带宽 吞吐量 时延 时延带宽积​编辑 往返时延RTT 利用率 1.…

Python:函数和代码复用

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&#xff0c;尽在下方&#xff0c;赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备好了&#xff0c;直接在文末名片自取就可 1、关于递归函…

深度学习:cross-attention介绍以及与self-attention的区别

1.Cross-attention vs Self-attention Cross-attention的输入来自不同的序列&#xff0c;Self-attention的输入来自同序列&#xff0c;也就是所谓的输入不同&#xff0c;但是除此之外&#xff0c;基本一致。 具体而言&#xff0c; self-attention输入则是一个单一的嵌入序列。 …

Open3D 点云配准——可视化匹配点对之间的连线

点云配准 一、算法原理1、概述2、主要函数二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、概述 可视化源点云和目标点云中匹配点对之间的连线,这对于点云配准,尤…

MySQL基础终端命令与Python简单操作MySQL

文章目录 MySQL终端命令1. 进入mysql2. 创建数据库3. 选择数据库4. 创建数据表1. 主键约束2. 外键约束3. 非空约束4. 唯一约束5. 使用默认约束6. 设置id为自增列 5. 查看数据表6. 修改数据表1. 修改表名2. 修改表的字段类型3. 修改表的字段名4. 为表添加字段5. 删除字段6. 调整…

驱动开发,stm32mp157a开发板的led灯控制实验

1.实验目的 编写LED灯的驱动&#xff0c;在应用程序中编写控制LED灯亮灭的代码逻辑实现LED灯功能的控制&#xff1b; 2.LED灯相关寄存器分析 LED1->PE10 LED1亮灭&#xff1a; RCC寄存器[4]->1 0X50000A28 GPIOE_MODER[21:20]->01 (输出) 0X50006000 GPIOE_ODR[10]-&g…

SSL Windows环境诊断修复工具,保持shell连接活跃

SangforHelperToolInstaller.exe 接入内网遇到网络故障&#xff0c;修复网络问题&#xff0c;可以使用这个软件&#xff0c;修复网络问题非常强大。

二叉树的具体原理及实现

文章目录 一.树的专业术语二.二叉树的原理三.常见的二叉树分类1.完全二叉树2.平衡二叉树3.二叉搜索树 四.二叉搜索树算法具体实现五.二叉搜索树具体实现代码 一.树的专业术语 首先先介绍树的专业术语 二.二叉树的原理 二叉搜索树&#xff08;Binary Search Tree&#xff0c…

【rar密码】WinRAR整理密码,如何使用?

之前给大家介绍过WinRAR自动加密的设置方法&#xff0c;今天再介绍一种RAR压缩包加密方法&#xff1a;整理密码。 什么是整理密码&#xff1a; 在加密rar文件的时候&#xff0c;点击下拉框选择密码&#xff0c;不用输入密码 设置方法&#xff1a; 前面的操作步骤和设置自动…

在ExoPlayer中使用协程:构建强大的Android媒体播放器

在ExoPlayer中使用协程&#xff1a;构建强大的Android媒体播放器 现今的移动应用世界中&#xff0c;媒体消费是用户体验的核心部分。无论是流媒体视频、音乐播放还是处理自适应媒体格式&#xff0c;强大的媒体播放器对于提供无缝和愉悦的用户体验至关重要。而在安卓平台上&…

Python(PySpark案例实战)

为什么要学习PySpark&#xff1f; Spark对Python语言的支持&#xff0c;重点体现在&#xff0c;Python第三方库&#xff1a;PySpark之上。 PySpark是由Spark官方开发的Python语言第三方库。 Python开发者可以使用pip程序快速的安装PySpark并像其它三方库那样直接使用。 PySp…