文章目录
- 前言
- 网关介绍
- 代码案例测试各项网关
- 排他网关 ExclusiveGateway
- 1、绘制流程图
- 2、编写测试代码
- 并行网关ParallelGateway
- 1、绘制流程图
- 2、编写测试代码
- 包含网关InclusiveGateway
- 1、绘制流程图
- 2、编写测试代码
前言
在activiti
工作流中,还有一个组件也很重要,那就是网关,并在许多的流程设计中都会进行使用操作。
网关介绍
常见的网关有以下4种,分别如下所示。
-
排他网关 ExclusiveGateway
多条分支线路,执行满足条件的一条流程。
当流程执行到这个网关,所有分支都会判断条件是否为true,如果为true则执行该分支。按照对应的条件执行,选择满足条件true的分支。如果多条分支都不会满足条件,流程会被异常结束。
请假天数大于等于3天时,需要总经理审批后,再进行财务审批。
请假天数小于 3 天时,财务直接审批即可,无需 总经理进行审批。 -
并行网关 ParallelGateway
并行流允许为一个流程设置多条链路同步执行。
并行网关需要前后两个配置
,当所有的分支流程都执行完成后,才会通过当前聚合网关,流程向下执行。
财务系统中涉及到贷审会
的配置点,一般使用该网关实现。
fork分支:并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。
join汇聚: 所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。如果并行网关中配置了条件,条件会被忽略!
并行网关条件会忽略。
请假流程需要 项目经理 和 技术经理 都审批,才能将流程向下执行。 -
包含网关InclusiveGateway
包含网关也和 并行网关类似,需要前后两个网关节点配置,分为分支网关和汇聚网关。
与并行网关的最大区别:
并行网关需要所有的分支都执行完成后,才能继续进行下面的其他节点任务流程操作。其次并行网关不会考虑分支条件。
包含网关在开始时,会根据每个连线设置的条件,执行满足条件的分支。当所有满足条件的分支均执行完成后,才会进入汇聚网关中继续向下执行流程。
请假流程一定需要人事经理审批。
如果请假天数等于或超过3天,需要项目经理审批,方便管理项目事项安排。
如果请假天数小于3天,只需要技术经理审批。
-
事件网关EventGateway (只做了解)
事件网关允许根据事件判断流向。网关的每个外出顺序流都要连接到一个中间捕获事件。 当流程到达一个基于事件网关,网关会进入等待状态:会暂停执行。与此同时,会为每个外出顺序流创建相对的事件订阅。
事件网关的外出顺序流和普通顺序流不同,这些顺序流不会真的"执行", 相反它们让流程引擎去决定执行到事件网关的流程需要订阅哪些事件。 要考虑以下条件:- 事件网关必须有两条或以上外出顺序流;
- 事件网关后,只能使用intermediateCatchEvent类型(activiti不支持基于事件网关后连接ReceiveTask)
- 连接到事件网关的中间捕获事件必须只有一个入口顺序流。
与事件网关配合使用的intermediateCatchEvent:
这个事件支持多种事件类型:
Message Event:消息事件
Singal Event: 信号事件
Timer Event: 定时事件
使用事件网关定义流程:
代码案例测试各项网关
以对象方式传递参数信息。
package cn.bugs.vo;
import lombok.Data;
import java.io.Serializable;
// 必须实现 Serializable ,否则 实例化流程对象时,会报错
@Data
public class Evection implements Serializable {
// 请假天数
private Integer num;
}
排他网关 ExclusiveGateway
1、绘制流程图
模板代码如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" 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:tns="http://www.activiti.org/testm1715603344601" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1715603344601" name="" targetNamespace="http://www.activiti.org/testm1715603344601" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="exclusive" isClosed="false" isExecutable="true" name="排他网关" processType="None">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:assignee="worker1" activiti:exclusive="true" id="_3" name="出差申请"/>
<userTask activiti:assignee="worker2" activiti:exclusive="true" id="_4" name="部门经理审批"/>
<exclusiveGateway gatewayDirection="Unspecified" id="_5" name="ExclusiveGateway"/>
<userTask activiti:assignee="worker3" activiti:exclusive="true" id="_6" name="总经理审批"/>
<userTask activiti:assignee="worker4" activiti:exclusive="true" id="_7" name="财务审批"/>
<endEvent id="_8" name="EndEvent"/>
<sequenceFlow id="_9" sourceRef="_2" targetRef="_3"/>
<sequenceFlow id="_10" sourceRef="_3" targetRef="_4"/>
<sequenceFlow id="_11" sourceRef="_4" targetRef="_5"/>
<sequenceFlow id="_12" name="请假大于等于3天" sourceRef="_5" targetRef="_6">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${evection.num >= 3}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="_13" name="请假小于3天" sourceRef="_5" targetRef="_7">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${evection.num < 3}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="_14" sourceRef="_6" targetRef="_7"/>
<sequenceFlow id="_15" sourceRef="_7" targetRef="_8"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="exclusive">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<dc:Bounds height="32.0" width="32.0" x="85.0" y="315.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<dc:Bounds height="55.0" width="85.0" x="185.0" y="305.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<dc:Bounds height="55.0" width="85.0" x="350.0" y="305.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5" isMarkerVisible="false">
<dc:Bounds height="32.0" width="32.0" x="375.0" y="460.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
<dc:Bounds height="55.0" width="85.0" x="555.0" y="405.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7">
<dc:Bounds height="55.0" width="85.0" x="555.0" y="520.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_8" id="Shape-_8">
<dc:Bounds height="32.0" width="32.0" x="740.0" y="530.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="_5" targetElement="_7">
<di:waypoint x="407.0" y="476.0"/>
<di:waypoint x="555.0" y="547.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_5" targetElement="_6">
<di:waypoint x="407.0" y="476.0"/>
<di:waypoint x="555.0" y="432.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_7" targetElement="_8">
<di:waypoint x="640.0" y="547.5"/>
<di:waypoint x="740.0" y="546.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_14" id="BPMNEdge__14" sourceElement="_6" targetElement="_7">
<di:waypoint x="597.5" y="460.0"/>
<di:waypoint x="597.5" y="520.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_2" targetElement="_3">
<di:waypoint x="117.0" y="331.0"/>
<di:waypoint x="185.0" y="332.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_4" targetElement="_5">
<di:waypoint x="391.0" y="360.0"/>
<di:waypoint x="391.0" y="460.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_3" targetElement="_4">
<di:waypoint x="270.0" y="332.5"/>
<di:waypoint x="350.0" y="332.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
2、编写测试代码
案例代码包含部署
、创造流程实例(2个)
、审批验证查询
。
addTable()
–>startProcess()
–>completTask()
–>queryTask()
–>completTask()
–>queryTask()
package com.bugs.activity;
import cn.bugs.vo.Evection;
import cn.hutool.core.collection.CollectionUtil;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
@SpringBootTest
public class GateWayExclusive {
/**
* 部署
*/
@Test
public void addTable(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
Deployment demo1 = repositoryService.createDeployment()
.addClasspathResource("bpmn/gateway-exclusive.bpmn") // 添加流程图
//.addClasspathResource("bpmn/gateway-exclusive.png") // 对应的流程图片 支持 png|jpg|gif|svg
.name("排他网关流程部署测试")
.deploy();
System.out.println("流程部署id===》"+demo1.getId());
System.out.println("流程部署name===》"+demo1.getName());
}
/**
* 启动实例 全局系统参数 设置
* 这里针对条件 分别启动两个流程实例
*/
@Test
public void startProcess(){
// 获取流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 获取 runtime 服务
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
// 指定哪个模板
String tempKey = "exclusive";
// 流程变量 可以是对象 也可以是单个的类型变量 比如 字符串
HashMap<String, Object> paramMap = new HashMap<>();
Evection evection = new Evection();
//evection.setNum(2); // 流程1
evection.setNum(4); // 流程2
paramMap.put("evection",evection);
// 启动流程实例
runtimeService.startProcessInstanceByKey(tempKey,paramMap);
}
/**
* 查询流程实例信息
*/
@Test
public void queryTask(){
// 执行已部署的流程模板名称
String tempKey = "exclusive";
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(tempKey) // 指定哪个流程图模板
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(x->{
System.out.println("流程实例 id "+x.getProcessInstanceId());
System.out.println("任务 id "+x.getId());
System.out.println("任务负责人 "+x.getAssignee());
System.out.println("任务名称 "+x.getName());
System.out.println("===========================================");
});
}
}
/**
* 工作流的节点与状态的扭转
* 这里有2个流程 分别对对应的任务 id 进行流程的推进
*
* 执行两次,将节点推送到 排他网关
*/
@Test
public void completTask(){
String tempKey = "exclusive";
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery().processDefinitionKey(tempKey).list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(task->{
taskService.complete(task.getId());
});
}
}
}
最终执行后,排他网关所在节点信息如下所示:
并行网关ParallelGateway
1、绘制流程图
流程图文件如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" 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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1715604997659" name="" targetNamespace="http://www.activiti.org/testm1715604997659" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="parallel" isClosed="false" isExecutable="true" name="并行网关流程测试" processType="None">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:assignee="worker1" activiti:exclusive="true" id="_3" name="出差申请"/>
<userTask activiti:assignee="worker2" activiti:exclusive="true" id="_4" name="技术经理"/>
<parallelGateway gatewayDirection="Unspecified" id="_5" name="ParallelGateway"/>
<userTask activiti:assignee="worker3" activiti:exclusive="true" id="_6" name="总经理"/>
<parallelGateway gatewayDirection="Unspecified" id="_7" name="ParallelGateway"/>
<sequenceFlow id="_8" sourceRef="_2" targetRef="_3"/>
<sequenceFlow id="_9" sourceRef="_3" targetRef="_5"/>
<sequenceFlow id="_10" sourceRef="_5" targetRef="_4"/>
<sequenceFlow id="_11" sourceRef="_5" targetRef="_6"/>
<sequenceFlow id="_12" sourceRef="_4" targetRef="_7"/>
<sequenceFlow id="_13" sourceRef="_6" targetRef="_7"/>
<endEvent id="_14" name="EndEvent"/>
<sequenceFlow id="_15" sourceRef="_7" targetRef="_14"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="parallel">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<dc:Bounds height="32.0" width="32.0" x="40.0" y="275.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<dc:Bounds height="55.0" width="85.0" x="150.0" y="265.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<dc:Bounds height="55.0" width="85.0" x="430.0" y="200.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
<dc:Bounds height="32.0" width="32.0" x="330.0" y="275.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
<dc:Bounds height="55.0" width="85.0" x="430.0" y="355.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7">
<dc:Bounds height="32.0" width="32.0" x="600.0" y="295.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_14" id="Shape-_14">
<dc:Bounds height="32.0" width="32.0" x="710.0" y="295.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="_6" targetElement="_7">
<di:waypoint x="515.0" y="382.5"/>
<di:waypoint x="600.0" y="311.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_4" targetElement="_7">
<di:waypoint x="515.0" y="227.5"/>
<di:waypoint x="600.0" y="311.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_7" targetElement="_14">
<di:waypoint x="632.0" y="311.0"/>
<di:waypoint x="710.0" y="311.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_2" targetElement="_3">
<di:waypoint x="72.0" y="291.0"/>
<di:waypoint x="150.0" y="292.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_3" targetElement="_5">
<di:waypoint x="235.0" y="292.5"/>
<di:waypoint x="330.0" y="291.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_5" targetElement="_6">
<di:waypoint x="362.0" y="291.0"/>
<di:waypoint x="430.0" y="382.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_5" targetElement="_4">
<di:waypoint x="362.0" y="291.0"/>
<di:waypoint x="430.0" y="227.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
2、编写测试代码
编写测试代码,执行观察控制台日志信息。
addTable()
–>startProcess()
–>completTask()
–>queryTask()
package com.bugs.activity;
import cn.bugs.vo.Evection;
import cn.hutool.core.collection.CollectionUtil;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
@SpringBootTest
public class GatewayParallel {
/**
* 部署
*/
@Test
public void addTable(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
Deployment demo1 = repositoryService.createDeployment()
.addClasspathResource("bpmn/gateway-parallel.bpmn") // 添加流程图
//.addClasspathResource("bpmn/gateway-parallel.png") // 对应的流程图片 支持 png|jpg|gif|svg
.name("排他网关流程部署测试")
.deploy();
System.out.println("流程部署id===》"+demo1.getId());
System.out.println("流程部署name===》"+demo1.getName());
}
/**
* 启动实例
*/
@Test
public void startProcess(){
// 获取流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 获取 runtime 服务
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
// 指定哪个模板
String tempKey = "parallel";
// 启动流程实例
runtimeService.startProcessInstanceByKey(tempKey);
}
/**
* 工作流的节点与状态的扭转
* 这里有2个流程 分别对对应的任务 id 进行流程的推进
*
* 执行两次,将节点推送到 排他网关
*/
@Test
public void completTask(){
String tempKey = "parallel";
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery().processDefinitionKey(tempKey).list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(task->{
taskService.complete(task.getId());
});
}
}
/**
* 查询流程实例信息
*/
@Test
public void queryTask(){
// 执行已部署的流程模板名称
String tempKey = "parallel";
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(tempKey) // 指定哪个流程图模板
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(x->{
System.out.println("流程实例 id "+x.getProcessInstanceId());
System.out.println("任务 id "+x.getId());
System.out.println("任务负责人 "+x.getAssignee());
System.out.println("任务名称 "+x.getName());
System.out.println("===========================================");
});
}
}
}
当进入并行网关后,此时的任务节点变成了2个,分别指向了 技术经理 和 总经理 审批节点。
再将其中某个节点进行审批操作,观察多个节点某个执行后整体流程的进度信息。
/**
* 仅执行 worker2 技术经理 的审批任务
*/
@Test
public void completWork2Task(){
String tempKey = "parallel";
String assign = "worker2";
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(tempKey)
.taskAssignee(assign)
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(task->{
taskService.complete(task.getId());
});
}
}
/**
* 查询流程实例信息
*/
@Test
public void queryTask(){
// 执行已部署的流程模板名称
String tempKey = "parallel";
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(tempKey) // 指定哪个流程图模板
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(x->{
System.out.println("流程实例 id "+x.getProcessInstanceId());
System.out.println("任务 id "+x.getId());
System.out.println("任务负责人 "+x.getAssignee());
System.out.println("任务名称 "+x.getName());
System.out.println("===========================================");
});
}
}
还需要继续等待另一个节点的审批通过,才会彻底执行完成并行网关流程。
包含网关InclusiveGateway
包含网关就是 排他网关与并行网关的结合体。
1、绘制流程图
上图对应的bpmn文件xml代码如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" 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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1715674484799" name="" targetNamespace="http://www.activiti.org/testm1715674484799" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="inclusive" isClosed="false" isExecutable="true" processType="None">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:assignee="worker1" activiti:exclusive="true" id="_3" name="流程提交"/>
<inclusiveGateway gatewayDirection="Unspecified" id="_4" name="InclusiveGateway"/>
<userTask activiti:assignee="worker2" activiti:exclusive="true" id="_5" name="项目经理审批"/>
<userTask activiti:assignee="worker3" activiti:exclusive="true" id="_6" name="人事审批"/>
<userTask activiti:assignee="worker4" activiti:exclusive="true" id="_7" name="技术经理审批"/>
<inclusiveGateway gatewayDirection="Unspecified" id="_8" name="InclusiveGateway"/>
<endEvent id="_9" name="EndEvent"/>
<sequenceFlow id="_10" sourceRef="_2" targetRef="_3"/>
<sequenceFlow id="_11" sourceRef="_3" targetRef="_4"/>
<sequenceFlow id="_12" name="请假天数超过或等于3天" sourceRef="_4" targetRef="_5">
<documentation id="_12_D_1"/>
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${evection.num>=3}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="_13" sourceRef="_4" targetRef="_6"/>
<sequenceFlow id="_14" name="请假天数小于3天" sourceRef="_4" targetRef="_7">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${evection.num<3}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="_15" sourceRef="_5" targetRef="_8"/>
<sequenceFlow id="_16" sourceRef="_6" targetRef="_8"/>
<sequenceFlow id="_17" sourceRef="_7" targetRef="_8"/>
<sequenceFlow id="_18" sourceRef="_8" targetRef="_9"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="inclusive">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<dc:Bounds height="32.0" width="32.0" x="65.0" y="265.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<dc:Bounds height="55.0" width="85.0" x="180.0" y="255.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<dc:Bounds height="32.0" width="32.0" x="365.0" y="265.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
<dc:Bounds height="55.0" width="85.0" x="510.0" y="125.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
<dc:Bounds height="55.0" width="85.0" x="510.0" y="255.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7">
<dc:Bounds height="55.0" width="85.0" x="510.0" y="390.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_8" id="Shape-_8">
<dc:Bounds height="32.0" width="32.0" x="725.0" y="270.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_9" id="Shape-_9">
<dc:Bounds height="32.0" width="32.0" x="875.0" y="270.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="_4" targetElement="_6">
<di:waypoint x="397.0" y="281.0"/>
<di:waypoint x="510.0" y="282.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_4" targetElement="_5">
<di:waypoint x="397.0" y="281.0"/>
<di:waypoint x="510.0" y="152.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_5" targetElement="_8">
<di:waypoint x="595.0" y="152.5"/>
<di:waypoint x="725.0" y="286.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_14" id="BPMNEdge__14" sourceElement="_4" targetElement="_7">
<di:waypoint x="397.0" y="281.0"/>
<di:waypoint x="510.0" y="417.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_17" id="BPMNEdge__17" sourceElement="_7" targetElement="_8">
<di:waypoint x="595.0" y="417.5"/>
<di:waypoint x="725.0" y="286.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_16" id="BPMNEdge__16" sourceElement="_6" targetElement="_8">
<di:waypoint x="595.0" y="282.5"/>
<di:waypoint x="725.0" y="286.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_18" id="BPMNEdge__18" sourceElement="_8" targetElement="_9">
<di:waypoint x="757.0" y="286.0"/>
<di:waypoint x="875.0" y="286.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_3" targetElement="_4">
<di:waypoint x="265.0" y="282.5"/>
<di:waypoint x="365.0" y="281.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_2" targetElement="_3">
<di:waypoint x="97.0" y="281.0"/>
<di:waypoint x="180.0" y="282.5"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
2、编写测试代码
将上述的bpmn流程文件部署至activiti中,并将该流程进行启动。
addTable()
–>startProcess()
–>startProcess()
–>completTask()
–>queryTask()
package com.bugs.activity;
import cn.bugs.vo.Evection;
import cn.hutool.core.collection.CollectionUtil;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class GatewayInclusive {
/**
* 单文件上传部署逻辑
*/
@Test
public void addTable(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
Deployment demo1 = repositoryService.createDeployment()
.addClasspathResource("bpmn/gateway-inclusive.bpmn") // 添加流程图
.name("包含网关流程验证")
.deploy();
System.out.println("流程部署id===》"+demo1.getId());
System.out.println("流程部署name===》"+demo1.getName());
}
/**
* 启动实例
* 这里启动2个,一个天数大于3天,一个小于3天
*/
@Test
public void startProcess(){
// 获取流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 获取 runtime 服务
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
// 指定哪个模板
String tempKey = "inclusive";
Map<String, Object> paramMap = new HashMap<>();
Evection evection = new Evection();
//evection.setNum(5); // 流程1
evection.setNum(2); // 流程2
paramMap.put("evection",evection);
// 启动流程实例
runtimeService.startProcessInstanceByKey(tempKey,paramMap);
}
/**
* 将指定流程进行流程提交操作
*/
@Test
public void completTask(){
String tempKey = "inclusive";
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery().processDefinitionKey(tempKey).list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(task->{
taskService.complete(task.getId());
});
}
}
/**
* 查询流程实例信息
*/
@Test
public void queryTask(){
// 执行已部署的流程模板名称
String tempKey = "inclusive";
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(tempKey) // 指定哪个流程图模板
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(x->{
System.out.println("流程实例 id "+x.getProcessInstanceId());
System.out.println("任务 id "+x.getId());
System.out.println("任务负责人 "+x.getAssignee());
System.out.println("任务名称 "+x.getName());
System.out.println("===========================================");
});
}
}
}
启动两个不同请假天数的流程实例后,将提交申请的流程全部进行审批操作。观察两个流程的情况信息。
因为天数的不同,根据流程的分支上的条件判断,由于人事审批并没有条件,则每个流程中都会进入人事审批环节。
配置了条件后,当条件满足,则会进行满足条件分支的审批任务上。