Flowable 监听器的使用
需求背景:
1、发起人发起流程,可以实现发起人自动审核
2、上一节点的审核人,与当前节点审核人相同时,自动审核
3、整个流程实例中,存在已审核的审核人,当前节点自动审核
流程图如下所示:
针对于自动审核设置,其实是由前端内置bpnm.xml 去设置的,与前端达成协议,例如不启用时,就不要置入监听器,启用时,就植入监听器,在配置不同的字段,表示不同的审核方式。
发起人自动审核
自定义监听器,实现TaskListener,并配置需要的字段,该字段与前端的需要达成一致
bpmn.xml 如下:
这样在监听器下就可以接受到这两个字段的值,根据这两个字段的值,去完成自动审核功能。
值得注意的是,在监听器中,spring的自动注入并不能通过注解 @Autowired 去实现,而且通过构造函数加spring的上下文去实现注入。
例如:
重写TaskListener 的 notify 方法,该方法的形参是DelegateTask,这个参数可以获取到bpnm.xml 中 任务节点的属性,例如监听器的字段,任务id,流程实例id,流程定义等等。基于这个现有条件,我们即可完成发起人自动审核。
@Overridepublic void notify(DelegateTask delegateTask) {// 从 FixedValue 中获取值String autoApprovalEnabledStr = (String) autoApprovalEnabled.getValue(delegateTask);String autoApprovalRuleStr = (String) autoApprovalRule.getValue(delegateTask);String processDefinitionId = delegateTask.getProcessDefinitionId();String taskDefinitionKey = delegateTask.getTaskDefinitionKey();BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);String eventName = delegateTask.getEventName();logger.info("触发监听器,当前监听器级别:{}",eventName);logger.info("触发监听器,当前任务:{}",delegateTask.getName());UserTask userTask = (UserTask) bpmnModel.getFlowElement(taskDefinitionKey);createLevelAutoTask(userTask,delegateTask,autoApprovalRuleStr,autoApprovalEnabledStr);}
在 createLevelAutoTask 方法中,需要完成以下步骤,判断当前的任务节点是不是会签节点,针对与会签节点,我们不去实现自动审核,直接停止当前监听器即可,还需要考虑,发起人如果是角色,或者是部门的情况下,我们应该怎么去实现,同样的,发起人是单个用户的话怎么实现,针对单个用户非常简单。
private void createLevelAutoTask(UserTask userTask, DelegateTask delegateTask, String autoApprovalRuleStr, String autoApprovalEnabledStr) {// 检查会签任务Integer nrOfInstances = (Integer) delegateTask.getVariable("nrOfInstances");Integer nrOfCompletedInstances = (Integer) delegateTask.getVariable("nrOfCompletedInstances");if (nrOfInstances != null && nrOfCompletedInstances != null) {// 这是一个多实例任务return;}if (userTask !=null){// 获取 当前任务节点的 类型,部门 DEPTS 、角色 ROLESString dataType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_DATA_TYPE);// 获取组的ID,角色ID集合或部门ID集合List<Long> groups = userTask.getCandidateGroups().stream().map(item -> Long.parseLong(item.substring(4))).collect(Collectors.toList());List<Long> userIds = new ArrayList<>();// 分别处理发起人是角色,部门,和user的场景if ("ROLES".equals(dataType) && !groups.isEmpty()){UserGroupRoleBO userGroupRoleBO = new UserGroupRoleBO();userGroupRoleBO.setRoleIdList(groups);userGroupRoleBO.setOrgIdList(null);userIds = userRemote.findUserByOrgIdsOrByRoleIds(userGroupRoleBO);// 表示启用自动审核if (AutoProcessType.AUTO_RULE_ENABLE.getCode().equals(autoApprovalEnabledStr)) {handleAutoApproval1(delegateTask, autoApprovalRuleStr,userIds);}}else if("DEPTS".equals(dataType) && !groups.isEmpty()){UserGroupRoleBO userGroupRoleBO = new UserGroupRoleBO();userGroupRoleBO.setRoleIdList(null);userGroupRoleBO.setOrgIdList(groups);userIds = userRemote.findUserByOrgIdsOrByRoleIds(userGroupRoleBO);// 表示启用自动审核if (AutoProcessType.AUTO_RULE_ENABLE.getCode().equals(autoApprovalEnabledStr)) {handleAutoApproval1(delegateTask, autoApprovalRuleStr,userIds);}}else {if (AutoProcessType.AUTO_RULE_ENABLE.getCode().equals(autoApprovalEnabledStr)){handleAutoApproval(delegateTask, autoApprovalRuleStr);}}}}
直接从单个用户来说吧,对于部门和角色相差不差,只需要获取到部门的id或者角色id,通过服务调用的方式去拿到用户的id,判断当前的登录用户是否在这个用户id集合中,存在即自动审核就好。
以下是针对单个用户的实现代码
@Transactionalpublic void handleAutoApproval(DelegateTask delegateTask, String autoApprovalRule) {String processInstanceId = delegateTask.getProcessInstanceId();Map<String, Object> variables = delegateTask.getVariables();String taskId = delegateTask.getId();String assignee = delegateTask.getAssignee();String currentAssignee = (String) variables.get(ProcessConstants.CURRENT_ASSIGNEE);// 每一次任务审核,存储审核人的idList<String> assigneeList = (ArrayList) variables.get(ProcessConstants.ASSIGNEE_LIST) == null?new ArrayList<>():(ArrayList) variables.get("assigneeList") ;String userIdStr = (String) variables.get(ProcessConstants.PROCESS_INITIATOR);UserToken userToken = AuthorizationContext.getAdminUser();String userId = userToken.getUserId().toString();NodeUserVO uservo = userRemote.findUserById(Long.parseLong(assignee));String nickname = uservo.getNickname();String msg = AutoProcessType.AUTO_INITIATOR_ENABLE.getCode().equals(autoApprovalRule)?nickname + "发起流程申请":nickname+"通过";// 发起人自动审核if (AutoProcessType.AUTO_INITIATOR_ENABLE.getCode().equals(autoApprovalRule)) {if (userId.equals(userIdStr)) {assigneeList.add(userIdStr);variables.put(ProcessConstants.CURRENT_ASSIGNEE,userId);variables.put(ProcessConstants.ASSIGNEE_LIST,assigneeList);commentTask(userId, taskId, processInstanceId, FlowComment.NORMAL.getType(), msg, variables, delegateTask);}} else if (AutoProcessType.AUTO_ADJACENT_ENABLE.getCode().equals(autoApprovalRule)) {
// if (checkPreviousAssignee(assignee, delegateTask)) {
// variables.put("currentAssignee",String.valueOf(userId));
// variables.put(ProcessConstants.FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
// commentTask(userId, taskId, processInstanceId, FlowComment.SKIP.getType(), msg, variables, delegateTask);
// }// 判断 上一节点 审批人 与当前节点审批人是否一致if (StringUtils.isNotBlank(currentAssignee) && currentAssignee.equals(assignee)) {variables.put(ProcessConstants.CURRENT_ASSIGNEE,userId);assigneeList.add(userIdStr);variables.put(ProcessConstants.ASSIGNEE_LIST,assigneeList);variables.put(ProcessConstants.FLOWABLE_SKIP_EXPRESSION_ENABLED, true);commentTask(userId, taskId, processInstanceId, FlowComment.SKIP.getType(), msg, variables, delegateTask);}} // 表示 当前流程实例中,存在已审核过的审核人,自动审核else if (AutoProcessType.AUTO_APPROVED.getCode().equals(autoApprovalRule)){// 相同表示 已存在审核人了if (assigneeList.contains(userId)){msg = nickname + "通过";variables.put(ProcessConstants.CURRENT_ASSIGNEE,userId);assigneeList.add(userIdStr);variables.put(ProcessConstants.ASSIGNEE_LIST,assigneeList);variables.put(ProcessConstants.FLOWABLE_SKIP_EXPRESSION_ENABLED, true);commentTask(userId, taskId, processInstanceId, FlowComment.SKIP.getType(), msg, variables, delegateTask);}}}private void commentTask(String userId,String taskId,String processInId,String commentType,String message, Map<String, Object> variables ,DelegateTask delegateTask){identityService.setAuthenticatedUserId(userId);taskService.addComment(taskId, processInId, commentType, message);logger.info("已完成任务:{}",delegateTask.getName());taskService.complete(taskId, variables);}
主要的实现方式,通过设置流程变量的方式,在流程发起的时候,去判断当前登录用户与任务节点受理用户的id是否一致,如果一致就自动审核即可,对于上一节点和当前节点审核人相同自动审核的,在用户审核时,添加流程变量,那么这个流程实例就存储了当前的审核人信息,在下一个任务时,判断以下是否一致即可。就不写那么详细了。