工作流实战_22_flowable 驳回/回退 并行网关驳回 多实例驳回 子流程驳回

2023-10-22 19:30

本文主要是介绍工作流实战_22_flowable 驳回/回退 并行网关驳回 多实例驳回 子流程驳回,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

项目地址https://gitee.com/lwj/flowable.git
代码分支flowable-base
视频讲解地址https://www.bilibili.com/video/av78779999/
用户名密码
0000001test
0000002test
0000003test
0000004test

文章目录

      • 1. 场景
      • 2. 演示
      • 3. 代码分享
        • 3.1. 获取可驳回节点
        • 3.2. 驳回代码分享

1. 场景

驳回:当前处理人可以驳回历史走过的任何一个节点
1、驳回任意普通节点
2、驳回多实例节点
3、驳回并行网关节点
4、驳回子流程节点
5、子流程节点驳回主流程节点

实际情况中,为了获取可驳回的节点列表,我们做了一些规定,比方说并行网关节点,要求必须成对出现,也只能驳回到并行网关节点的 fork节点

2. 演示

由于情况很多,截图反而不能重点讲述驳回的事情,这里只截一张图,如果想看详情请查看视频里面的讲解
在这里插入图片描述

3. 代码分享

3.1. 获取可驳回节点
public List<FlowNodeVo> getBackNodesByProcessInstanceId(String taskId,String processInstanceId) {List<FlowNodeVo> backNods = new ArrayList<>();TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();String currActId = taskEntity.getTaskDefinitionKey();//获取运行节点表中usertaskString sql = "select t.* from act_ru_actinst t where t.ACT_TYPE_ = 'userTask' " +" and t.PROC_INST_ID_=#{processInstanceId} and t.END_TIME_ is not null ";List<ActivityInstance> activityInstances = runtimeService.createNativeActivityInstanceQuery().sql(sql).parameter("processInstanceId", processInstanceId).list();//获取运行节点表的parallelGateway节点并出重sql = "SELECT t.ID_, t.REV_,t.PROC_DEF_ID_,t.PROC_INST_ID_,t.EXECUTION_ID_,t.ACT_ID_, t.TASK_ID_, t.CALL_PROC_INST_ID_, t.ACT_NAME_, t.ACT_TYPE_, " +" t.ASSIGNEE_, t.START_TIME_, max(t.END_TIME_) as END_TIME_, t.DURATION_, t.DELETE_REASON_, t.TENANT_ID_" +" FROM  act_ru_actinst t WHERE t.ACT_TYPE_ = 'parallelGateway' AND t.PROC_INST_ID_ = #{processInstanceId} and t.END_TIME_ is not null" +" and t.ACT_ID_ <> #{actId} GROUP BY t.act_id_";List<ActivityInstance> parallelGatewaies = runtimeService.createNativeActivityInstanceQuery().sql(sql).parameter("processInstanceId", processInstanceId).parameter("actId", currActId).list();//排序if (CollectionUtils.isNotEmpty(parallelGatewaies)) {activityInstances.addAll(parallelGatewaies);activityInstances.sort(Comparator.comparing(ActivityInstance::getEndTime));}//分组节点int count = 0;Map<ActivityInstance, List<ActivityInstance>> parallelGatewayUserTasks = new HashMap<>();List<ActivityInstance> userTasks = new ArrayList<>();ActivityInstance currActivityInstance = null;for (ActivityInstance activityInstance : activityInstances) {if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(activityInstance.getActivityType())) {count++;if (count % 2 != 0) {List<ActivityInstance> datas = new ArrayList<>();currActivityInstance = activityInstance;parallelGatewayUserTasks.put(currActivityInstance, datas);}}if (BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType())) {if (count % 2 == 0) {userTasks.add(activityInstance);} else {if (parallelGatewayUserTasks.containsKey(currActivityInstance)) {parallelGatewayUserTasks.get(currActivityInstance).add(activityInstance);}}}}//组装人员名称List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).finished().list();Map<String, List<HistoricTaskInstance>> taskInstanceMap = new HashMap<>();List<String> userCodes = new ArrayList<>();historicTaskInstances.forEach(historicTaskInstance -> {userCodes.add(historicTaskInstance.getAssignee());String taskDefinitionKey = historicTaskInstance.getTaskDefinitionKey();if (taskInstanceMap.containsKey(historicTaskInstance.getTaskDefinitionKey())) {taskInstanceMap.get(taskDefinitionKey).add(historicTaskInstance);} else {List<HistoricTaskInstance> tasks = new ArrayList<>();tasks.add(historicTaskInstance);taskInstanceMap.put(taskDefinitionKey, tasks);}});//组装usertask的数据List<User> userList = identityService.createUserQuery().userIds(userCodes).list();Map<String, String> activityIdUserNames = this.getApplyers(processInstanceId, userList, taskInstanceMap);if (CollectionUtils.isNotEmpty(userTasks)) {userTasks.forEach(activityInstance -> {FlowNodeVo node = new FlowNodeVo();node.setNodeId(activityInstance.getActivityId());node.setNodeName(activityInstance.getActivityName());node.setEndTime(activityInstance.getEndTime());node.setUserName(activityIdUserNames.get(activityInstance.getActivityId()));backNods.add(node);});}//组装会签节点数据if (MapUtils.isNotEmpty(taskInstanceMap)) {parallelGatewayUserTasks.forEach((activity, activities) -> {FlowNodeVo node = new FlowNodeVo();node.setNodeId(activity.getActivityId());node.setEndTime(activity.getEndTime());StringBuffer nodeNames = new StringBuffer("会签:");StringBuffer userNames = new StringBuffer("审批人员:");if (CollectionUtils.isNotEmpty(activities)){activities.forEach(activityInstance -> {nodeNames.append(activityInstance.getActivityName()).append(",");userNames.append(activityIdUserNames.get(activityInstance.getActivityId())).append(",");});node.setNodeName(nodeNames.toString());node.setUserName(userNames.toString());backNods.add(node);}});}//去重合并List<FlowNodeVo> datas = backNods.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->new TreeSet<>(Comparator.comparing(nodeVo -> nodeVo.getNodeId()))), ArrayList::new));//排序datas.sort(Comparator.comparing(FlowNodeVo::getEndTime));return datas;}
3.2. 驳回代码分享
public ReturnVo<String> backToStepTask(BackTaskVo backTaskVo) {ReturnVo<String> returnVo = null;TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(backTaskVo.getTaskId()).singleResult();//1.把当前的节点设置为空if (taskEntity != null) {//2.设置审批人taskEntity.setAssignee(backTaskVo.getUserCode());taskService.saveTask(taskEntity);//3.添加驳回意见this.addComment(backTaskVo.getTaskId(), backTaskVo.getUserCode(), backTaskVo.getProcessInstanceId(),CommentTypeEnum.BH.toString(), backTaskVo.getMessage());//4.处理提交人节点FlowNode distActivity = flowableBpmnModelService.findFlowNodeByActivityId(taskEntity.getProcessDefinitionId(), backTaskVo.getDistFlowElementId());if (distActivity != null) {if (FlowConstant.FLOW_SUBMITTER.equals(distActivity.getName())) {ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(taskEntity.getProcessInstanceId()).singleResult();runtimeService.setVariable(backTaskVo.getProcessInstanceId(), FlowConstant.FLOW_SUBMITTER_VAR, processInstance.getStartUserId());}}//5.删除节点this.deleteActivity(backTaskVo.getDistFlowElementId(), taskEntity.getProcessInstanceId());List<String> executionIds = new ArrayList<>();//6.判断节点是不是子流程内部的节点if (flowableBpmnModelService.checkActivitySubprocessByActivityId(taskEntity.getProcessDefinitionId(),backTaskVo.getDistFlowElementId())&& flowableBpmnModelService.checkActivitySubprocessByActivityId(taskEntity.getProcessDefinitionId(),taskEntity.getTaskDefinitionKey())){//6.1 子流程内部驳回Execution executionTask = runtimeService.createExecutionQuery().executionId(taskEntity.getExecutionId()).singleResult();String parentId = executionTask.getParentId();List<Execution> executions = runtimeService.createExecutionQuery().parentId(parentId).list();executions.forEach(execution -> executionIds.add(execution.getId()));this.moveExecutionsToSingleActivityId(executionIds,backTaskVo.getDistFlowElementId());}else {//6.2 普通驳回List<Execution> executions = runtimeService.createExecutionQuery().parentId(taskEntity.getProcessInstanceId()).list();executions.forEach(execution -> executionIds.add(execution.getId()));this.moveExecutionsToSingleActivityId(executionIds,backTaskVo.getDistFlowElementId());}returnVo = new ReturnVo<>(ReturnCode.SUCCESS, "驳回成功!");} else {returnVo = new ReturnVo<>(ReturnCode.FAIL, "不存在任务实例,请确认!");}return returnVo;}

这篇关于工作流实战_22_flowable 驳回/回退 并行网关驳回 多实例驳回 子流程驳回的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/263172

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

工作常用指令与快捷键

Git提交代码 git fetch  git add .  git commit -m “desc”  git pull  git push Git查看当前分支 git symbolic-ref --short -q HEAD Git创建新的分支并切换 git checkout -b XXXXXXXXXXXXXX git push origin XXXXXXXXXXXXXX