工作流实战_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

相关文章

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

Spring Security中用户名和密码的验证完整流程

《SpringSecurity中用户名和密码的验证完整流程》本文给大家介绍SpringSecurity中用户名和密码的验证完整流程,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 首先创建了一个UsernamePasswordAuthenticationTChina编程oken对象,这是S

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2

SpringBoot集成LiteFlow工作流引擎的完整指南

《SpringBoot集成LiteFlow工作流引擎的完整指南》LiteFlow作为一款国产轻量级规则引擎/流程引擎,以其零学习成本、高可扩展性和极致性能成为微服务架构下的理想选择,本文将详细讲解Sp... 目录一、LiteFlow核心优势二、SpringBoot集成实战三、高级特性应用1. 异步并行执行2