BPMN2.0,flowable工作流指向多节点,并且只能选择其中一个节点的处理方式

目录

1、环境

2、流程信息

3、需求

4、思路

5、代码实现

6、流程xml文件


1、环境

前端:BPMN2.0.js

后端:flowable:6.8.0

2、流程信息

流程图(6、流程xml文件在文章最后):

各节点信息:

节点名称 节点id
开始 ks
登记 dj
员工 yg
领导审批 ldsp
结束 js

3、需求

【领导审批】节点要根据实际情况,选择【提交】到【结束】,还是【退回】到【员工】

4、思路

【排他网关】:

如果要达到这种指向单一节点的,可以使用【排他网关】,我这边理解【排他网关】往往是用于特定的业务逻辑的时候使用的,但是我这里可能会有很多节点会有退回到上一节点的指向,为了可以做得更加通用,这里先否掉【排他网关】。

【条件顺序流】(最后确定使用):

在两个几点连线上使用【条件顺序流】。前端获取当前节点所有的指向,由用户进行下一节点的单选选择,他节点id传到指定变量中(我这里定义了变量nextNodeId),条件顺序流的表示式为:${nextNodeId=="yg"}(yg为【员工】节点的id值),通过这种方式来确定需要走到哪个节点。

5、代码实现

代码由开源项目做二次修改:https://gitee.com/nbacheng/ruoyi-nbcio/tree/master/

以下代码可能需要对flowable工作流有一些基础的才比较好理解

获取下一节点的所有节点接口:

controller:

java 复制代码
    /**
     * 获取下一步骤的节点
     **/
    @PostMapping(value = "/nextNodeList")
    public R<NextUserTaskVo> nextUserTaskList(@RequestBody WfTaskBo taskBo) {
        NextUserTaskVo nextUserTaskVo = flowTaskService.nextUserTaskList(taskBo);
        return R.ok(nextUserTaskVo);
    }

nextUserTaskList:

java 复制代码
public NextUserTaskVo nextUserTaskList(WfTaskBo taskBo) {
        NextUserTaskVo nextUserTaskVo = new NextUserTaskVo();
        Task task = taskService.createTaskQuery().taskId(taskBo.getTaskId()).singleResult();
        List<UserTask> taskList = FindNextNodeUtil.getNextUserTasks(repositoryService, task, taskBo.getVariables());
        nextUserTaskVo.setUserTaskList(taskList);
        nextUserTaskVo.setTaskDefinitionKey(task.getTaskDefinitionKey());
        return nextUserTaskVo;
    }
复制代码
getNextUserTasks:
java 复制代码
    public static List<UserTask> getNextUserTasks(RepositoryService repositoryService, org.flowable.task.api.Task task, Map<String, Object> map) {
        List<UserTask> data = new ArrayList<>();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        Process mainProcess = bpmnModel.getMainProcess();
        Collection<FlowElement> flowElements = mainProcess.getFlowElements();
        String key = task.getTaskDefinitionKey();
        FlowElement flowElement = bpmnModel.getFlowElement(key);
        next(flowElements, flowElement, map, data);
        return data;
    }
复制代码
next:
java 复制代码
    public static void next(Collection<FlowElement> flowElements, FlowElement flowElement, Map<String, Object> map, List<UserTask> nextUser) {
        //如果是结束节点
        if (flowElement instanceof EndEvent) {
            //如果是子任务的结束节点
            if (getSubProcess(flowElements, flowElement) != null) {
                flowElement = getSubProcess(flowElements, flowElement);
            }
        }
        //获取Task的出线信息--可以拥有多个
        List<SequenceFlow> outGoingFlows = null;
        if (flowElement instanceof Task) {
            outGoingFlows = ((Task) flowElement).getOutgoingFlows();
        } else if (flowElement instanceof Gateway) {
            outGoingFlows = ((Gateway) flowElement).getOutgoingFlows();
        } else if (flowElement instanceof StartEvent) {
            outGoingFlows = ((StartEvent) flowElement).getOutgoingFlows();
        } else if (flowElement instanceof SubProcess) {
            outGoingFlows = ((SubProcess) flowElement).getOutgoingFlows();
        } else if (flowElement instanceof CallActivity) {
            outGoingFlows = ((CallActivity) flowElement).getOutgoingFlows();
        }
        if (outGoingFlows != null && outGoingFlows.size() > 0) {
            //遍历所有的出线--找到可以正确执行的那一条
            for (SequenceFlow sequenceFlow : outGoingFlows) {
                //1.有表达式,且为true
                //2.无表达式
                // 不做表达式的判断
//                String expression = sequenceFlow.getConditionExpression();
//                if (expression == null || expressionResult(map, expression.substring(expression.lastIndexOf("{") + 1, expression.lastIndexOf("}")))) {
                    //出线的下一节点
                    String nextFlowElementID = sequenceFlow.getTargetRef();
                    if (checkSubProcess(nextFlowElementID, flowElements, nextUser)) {
                        continue;
                    }

                    //查询下一节点的信息
                    FlowElement nextFlowElement = getFlowElementById(nextFlowElementID, flowElements);
                    //调用流程
                    if (nextFlowElement instanceof CallActivity) {
                        CallActivity ca = (CallActivity) nextFlowElement;
                        if (ca.getLoopCharacteristics() != null) {
                            UserTask userTask = new UserTask();
                            userTask.setId(ca.getId());

                            userTask.setId(ca.getId());
                            userTask.setLoopCharacteristics(ca.getLoopCharacteristics());
                            userTask.setName(ca.getName());
                            nextUser.add(userTask);
                        }
                        next(flowElements, nextFlowElement, map, nextUser);
                    }
                    //用户任务
                    if (nextFlowElement instanceof UserTask) {
                        nextUser.add((UserTask) nextFlowElement);
                    }
                    //排他网关
                    else if (nextFlowElement instanceof ExclusiveGateway) {
                        next(flowElements, nextFlowElement, map, nextUser);
                    }
                    //并行网关
                    else if (nextFlowElement instanceof ParallelGateway) {
                        next(flowElements, nextFlowElement, map, nextUser);
                    }
                    //接收任务
                    else if (nextFlowElement instanceof ReceiveTask) {
                        next(flowElements, nextFlowElement, map, nextUser);
                    }
                    //服务任务
                    else if (nextFlowElement instanceof ServiceTask) {
                        next(flowElements, nextFlowElement, map, nextUser);
                    }
                    //子任务的起点
                    else if (nextFlowElement instanceof StartEvent) {
                        next(flowElements, nextFlowElement, map, nextUser);
                    }
                    //结束节点
                    else if (nextFlowElement instanceof EndEvent) {
                        nextUser.add(BeanCopyUtils.copy((EndEvent) nextFlowElement, UserTask.class));
                        next(flowElements, nextFlowElement, map, nextUser);
                    }
                    //信号抛出
                    else if(nextFlowElement instanceof ThrowEvent){
                        nextUser.add(BeanCopyUtils.copy((ThrowEvent) nextFlowElement, UserTask.class));
                    }
//                }
            }
        }
    }

前端调用接口后拼接成单选:(选择后提交时,把id值赋值到变量nextNodeId中)

html 复制代码
<el-form-item label="选择节点:" prop="jumpType" :rules="[{ required: true, message: '请选择节点', trigger: 'blur' }]">
              <el-radio-group v-model="selectedRouteNodeRows" class="ml-4">
                <template v-for="nodeData in routeNodeData.userTaskList" :key="nodeData.id">
                  <el-radio
                    v-if="(nodeData.incomingFlows && nodeData.incomingFlows.length > 0 && nodeData.incomingFlows.filter(item => item.targetRef == nodeData.id && item.sourceRef == routeNodeData.taskDefinitionKey)[0]) || (nodeData.incomingFlows && nodeData.incomingFlows.length == 0 && nodeData.loopCharacteristics)"
                    :label="nodeData.id"
                  >{{ 
                  `${(nodeData.incomingFlows && nodeData.incomingFlows.length > 0 && nodeData.incomingFlows.filter(item => item.targetRef == nodeData.id && item.sourceRef == routeNodeData.taskDefinitionKey)[0]?.name) || ''} -> ${nodeData.name}`
                  }}
                  </el-radio>
                  </template>
              </el-radio-group>
              
            </el-form-item>

6、流程xml文件

flowable.xml:

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
    xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
    xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
    xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
    xmlns:flowable="http://flowable.org/bpmn" id="diagram_Process_1761616908502" targetNamespace="http://flowable.org/bpmn" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
    <bpmn2:process id="Process_1761616908502" name="审批流程" isExecutable="true">
        <bpmn2:startEvent id="ks" name="开始">
            <bpmn2:outgoing>Flow_0zttbj2</bpmn2:outgoing>
        </bpmn2:startEvent>
        <bpmn2:userTask id="yg" name="员工" flowable:dataType="INITIATOR" flowable:assignee="${initiator}" flowable:text="流程发起人">
            <bpmn2:incoming>fq</bpmn2:incoming>
            <bpmn2:incoming>th</bpmn2:incoming>
            <bpmn2:outgoing>sq</bpmn2:outgoing>
        </bpmn2:userTask>
        <bpmn2:userTask id="ldsp" name="领导审批" flowable:dataType="ROLES" flowable:candidateGroups="ROLE123456" flowable:text="领导">
            <bpmn2:incoming>sq</bpmn2:incoming>
            <bpmn2:outgoing>Flow_13elc6g</bpmn2:outgoing>
            <bpmn2:outgoing>th</bpmn2:outgoing>
        </bpmn2:userTask>
        <bpmn2:endEvent id="js" name="结束">
            <bpmn2:incoming>Flow_13elc6g</bpmn2:incoming>
        </bpmn2:endEvent>
        <bpmn2:sequenceFlow id="Flow_13elc6g" name="提交" sourceRef="ldsp" targetRef="js">
            <bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">${nextNodeId=="js"}</bpmn2:conditionExpression>
        </bpmn2:sequenceFlow>
        <bpmn2:sequenceFlow id="fq" name="发起" sourceRef="dj" targetRef="yg" />
        <bpmn2:sequenceFlow id="sq" name="申请" sourceRef="yg" targetRef="ldsp" />
        <bpmn2:sequenceFlow id="th" name="退回" sourceRef="ldsp" targetRef="yg">
            <bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">${nextNodeId=="yg"}</bpmn2:conditionExpression>
        </bpmn2:sequenceFlow>
        <bpmn2:userTask id="dj" name="登记" flowable:dataType="INITIATOR" flowable:assignee="${initiator}" flowable:text="流程发起人">
            <bpmn2:incoming>Flow_0zttbj2</bpmn2:incoming>
            <bpmn2:outgoing>fq</bpmn2:outgoing>
        </bpmn2:userTask>
        <bpmn2:sequenceFlow id="Flow_0zttbj2" sourceRef="ks" targetRef="dj" />
    </bpmn2:process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_1">
        <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1761616908502">
            <bpmndi:BPMNEdge id="Flow_0zttbj2_di" bpmnElement="Flow_0zttbj2">
                <di:waypoint x="38" y="239" />
                <di:waypoint x="110" y="239" />
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="th_di" bpmnElement="th">
                <di:waypoint x="550" y="199" />
                <di:waypoint x="550" y="170" />
                <di:waypoint x="336" y="170" />
                <di:waypoint x="336" y="199" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="432" y="152" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="sq_di" bpmnElement="sq">
                <di:waypoint x="386" y="239" />
                <di:waypoint x="500" y="239" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="432" y="221" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="fq_di" bpmnElement="fq">
                <di:waypoint x="210" y="239" />
                <di:waypoint x="286" y="239" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="235" y="221" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="Flow_13elc6g_di" bpmnElement="Flow_13elc6g">
                <di:waypoint x="600" y="239" />
                <di:waypoint x="682" y="239" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="635" y="217" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNShape id="ks_di" bpmnElement="ks">
                <dc:Bounds x="2" y="221" width="36" height="36" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="10" y="264" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="yg_di" bpmnElement="yg">
                <dc:Bounds x="286" y="199" width="100" height="80" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="ldsp_di" bpmnElement="ldsp">
                <dc:Bounds x="500" y="199" width="100" height="80" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="dj_di" bpmnElement="dj">
                <dc:Bounds x="110" y="199" width="100" height="80" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="js_di" bpmnElement="js">
                <dc:Bounds x="682" y="221" width="36" height="36" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="691" y="264" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNShape>
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</bpmn2:definitions>

bpmn.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
    xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
    xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
    xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
    xmlns:flowable="http://flowable.org/bpmn" id="diagram_Process_1761616908502" targetNamespace="http://flowable.org/bpmn" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
    <bpmn2:process id="Process_1761616908502" name="审批流程" isExecutable="true">
        <bpmn2:startEvent id="ks" name="开始">
            <bpmn2:outgoing>Flow_0zttbj2</bpmn2:outgoing>
        </bpmn2:startEvent>
        <bpmn2:userTask id="yg" name="员工" flowable:dataType="INITIATOR" flowable:assignee="${initiator}" flowable:text="流程发起人">
            <bpmn2:incoming>fq</bpmn2:incoming>
            <bpmn2:incoming>th</bpmn2:incoming>
            <bpmn2:outgoing>sq</bpmn2:outgoing>
        </bpmn2:userTask>
        <bpmn2:userTask id="ldsp" name="领导审批" flowable:dataType="ROLES" flowable:candidateGroups="ROLE123456" flowable:text="领导">
            <bpmn2:incoming>sq</bpmn2:incoming>
            <bpmn2:outgoing>Flow_13elc6g</bpmn2:outgoing>
            <bpmn2:outgoing>th</bpmn2:outgoing>
        </bpmn2:userTask>
        <bpmn2:endEvent id="js" name="结束">
            <bpmn2:incoming>Flow_13elc6g</bpmn2:incoming>
        </bpmn2:endEvent>
        <bpmn2:sequenceFlow id="Flow_13elc6g" name="提交" sourceRef="ldsp" targetRef="js">
            <bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">${nextNodeId=="js"}</bpmn2:conditionExpression>
        </bpmn2:sequenceFlow>
        <bpmn2:sequenceFlow id="fq" name="发起" sourceRef="dj" targetRef="yg" />
        <bpmn2:sequenceFlow id="sq" name="申请" sourceRef="yg" targetRef="ldsp" />
        <bpmn2:sequenceFlow id="th" name="退回" sourceRef="ldsp" targetRef="yg">
            <bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">${nextNodeId=="yg"}</bpmn2:conditionExpression>
        </bpmn2:sequenceFlow>
        <bpmn2:userTask id="dj" name="登记" flowable:dataType="INITIATOR" flowable:assignee="${initiator}" flowable:text="流程发起人">
            <bpmn2:incoming>Flow_0zttbj2</bpmn2:incoming>
            <bpmn2:outgoing>fq</bpmn2:outgoing>
        </bpmn2:userTask>
        <bpmn2:sequenceFlow id="Flow_0zttbj2" sourceRef="ks" targetRef="dj" />
    </bpmn2:process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_1">
        <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1761616908502">
            <bpmndi:BPMNEdge id="Flow_0zttbj2_di" bpmnElement="Flow_0zttbj2">
                <di:waypoint x="38" y="239" />
                <di:waypoint x="110" y="239" />
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="th_di" bpmnElement="th">
                <di:waypoint x="550" y="199" />
                <di:waypoint x="550" y="170" />
                <di:waypoint x="336" y="170" />
                <di:waypoint x="336" y="199" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="432" y="152" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="sq_di" bpmnElement="sq">
                <di:waypoint x="386" y="239" />
                <di:waypoint x="500" y="239" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="432" y="221" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="fq_di" bpmnElement="fq">
                <di:waypoint x="210" y="239" />
                <di:waypoint x="286" y="239" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="235" y="221" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="Flow_13elc6g_di" bpmnElement="Flow_13elc6g">
                <di:waypoint x="600" y="239" />
                <di:waypoint x="682" y="239" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="635" y="217" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNShape id="ks_di" bpmnElement="ks">
                <dc:Bounds x="2" y="221" width="36" height="36" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="10" y="264" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="yg_di" bpmnElement="yg">
                <dc:Bounds x="286" y="199" width="100" height="80" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="ldsp_di" bpmnElement="ldsp">
                <dc:Bounds x="500" y="199" width="100" height="80" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="dj_di" bpmnElement="dj">
                <dc:Bounds x="110" y="199" width="100" height="80" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="js_di" bpmnElement="js">
                <dc:Bounds x="682" y="221" width="36" height="36" />
                <bpmndi:BPMNLabel>
                    <dc:Bounds x="691" y="264" width="22" height="14" />
                </bpmndi:BPMNLabel>
            </bpmndi:BPMNShape>
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</bpmn2:definitions>
相关推荐
2022.11.7始学前端1 小时前
n8n第四节 表单触发器:让问卷提交自动触发企微消息推送
java·前端·数据库·n8n
Catcharlotte1 小时前
异常(3)
java
岁岁种桃花儿1 小时前
Java应用篇如何基于Redis共享Session实现短信登录
java·开发语言
资深低代码开发平台专家1 小时前
通用编程时代正在向专用化分层演进
java·大数据·c语言·c++·python
开心香辣派小星1 小时前
23种设计模式-17备忘录模式
java·设计模式·备忘录模式
q_19132846951 小时前
基于SpringBoot2+Vue2+uniapp的考研社区论坛网站及小程序
java·vue.js·spring boot·后端·小程序·uni-app·毕业设计
源码技术栈1 小时前
Java智能诊所管理系统源码 SaaS云门诊运维平台源码
java·大数据·运维·人工智能·源码·诊所·门诊
⑩-1 小时前
滚动分页查询实战示例
java·redis
Han.miracle1 小时前
数据库圣经--简单使用索引
java·数据库·sql·索引