activiti网关
网关是用来控制流程的走向的。
1. 排他网关–ExclusiveGateway
1.1 什么是排他网关
排他网关,用来在流程中实现决策。当执行到这个网关时,会根据判断条件去选择执行某一条分支。
注意:排他网关只会选择一个为true的分支执行。如果有两个分支条件都为true,排他网关会选择id值较小的一条分支去执行
为什么用排他网关?
![img](https://img-blog.csdnimg.cn/img_convert/a0ef25c20b38551cf41b26f60c2b5ebc.jpeg)
不用排他网关也可以实现分支,比如之前通过流程变量,在连线的condition条件上设置分支条件,但设置condition条件有个缺点:如果条件都不满足,流程就结束了(并且是异常结束)。
而从网关出去的条件都不满足是直接抛出异常。
1.2 流程定义
排他网关流程图:这里的为了测试网关,任务负责人直接在设计流程的时候设置assignee
属性了,不通过流程变量设置了
![image-20211208145357643](https://img-blog.csdnimg.cn/img_convert/5955f4899a66c8b5f305967f6f4ad000.png)
1.3 测试
部署排他网关流程,启动流程实例:
/**
* 部署流程
*/
@Test
public void deployment() {
//流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//部署
Deployment deploy = repositoryService
.createDeployment()
.name("排他网关流程")
.addClasspathResource("bpmn/exclusivegateway.bpmn20.xml")
.addClasspathResource("bpmn/exclusivegateway.png")
.deploy();
//部署信息
System.out.println("流程id:" + deploy.getId());
System.out.println("流程名:" + deploy.getName());
}
/**
* 启动流程实例
*/
@Test
public void startProcessInstance() {
//流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//通过runtimeService启动流程
RuntimeService runtimeService = processEngine.getRuntimeService();
runtimeService.startProcessInstanceByKey("exclusivegateway");
}
完成个人任务:
/**
* 张三完成个人任务
*/
@Test
public void completeTask() {
//流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取taskService调用api完成任务
TaskService taskService = processEngine.getTaskService();
//测试直接从数据库act_ru_task表查看任务id,然后根据taskId完成任务
//按设计流程,需要完成两次才会走到排他网关条件
taskService.complete("2505");
}
/**
* 经理完成个人任务
*/
@Test
public void completeTask() {
//流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取taskService调用api完成任务
TaskService taskService = processEngine.getTaskService();
//测试直接从数据库act_ru_task表查看任务id,然后根据taskId完成任务
//按设计流程,需要完成两次才会走到排他网关条件
/**
* 网关条件在执行网关前的任务中设置网关中的流程变量值,或者启动流程实例的时候设置
*/
//设置排他网关条件,出差天数num
Map<String, Object> map = new HashMap<>();
//设置4天,所以经理任务完成后,流程走到总经理
map.put("num", 4);
taskService.complete("5002", map);
}
查询act_ru_task
表:流程任务走到了总经理审批,因为设置的出差天数num=4,在排他网关中我们设置了出差天数>3需要由总经理审批。
![image-20211208214155742](https://img-blog.csdnimg.cn/img_convert/a5a254b7f80d9dec5c06d91f11da0d61.png)
注意:如果网关中的条件都不满足的话,会报异常
2. 并行网关–ParallelGateway
2.1 什么是并行网关
并行网关是将流程分成多条分支,和将多条分支再次汇聚到一起,并行网关是基于进入和外出顺序流的:
fork分支:
流程分成多条顺序流分支执行
join汇聚:
多条分支到达并行网关,先到的分支需要等待别的分支,直到所有的顺序流分支都到达以后,流程就会通过汇聚网关通向下一个任务节点。
如果同一个并行网关具有多个进入和多个外出顺序流,它就同时具有分支和汇聚功能。此时该网关需要先汇聚所有进入的顺序流,然后再切分成多个并行分支。
注意:并行网关不会解析条件,即时顺序流中定义了条件也会忽略。
2.2 流程定义
并行网关流程图:负责人已提前在流程设计中写死了,后面代码直接用,不再通过流程变量设置
![image-20211208224344262](https://img-blog.csdnimg.cn/img_convert/20f80e4e4efe7358d03a57f3bd88c43e.png)
2.3 测试
部署并行网关流程,启动流程实例:
/**
* 部署并行网关
*/
@Test
public void deployment() {
//流程引起
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//通过RepositoryService部署
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("bpmn/parallelway.bpmn20.xml")
.addClasspathResource("bpmn/parallelway.png")
.name("并行网关流程")
.deploy();
//输出信息
System.out.println("流程id:" + deploy.getId());
System.out.println("流程名称:" + deploy.getName());
}
/**
* 启动流程实例
*/
@Test
public void startProcessInstance() {
//流程引起
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//通过RuntimeService启动流程实例
RuntimeService runtimeService = processEngine.getRuntimeService();
//设置流程变量出差天数num
Map<String, Object> map = new HashMap<>();
map.put("num", 4);
//启动流程实例的时候,同时设置流程变量,也可以在完成任务的时候设置,但必须在使用流程变量之前
ProcessInstance instance = runtimeService.startProcessInstanceByKey("parallelway", map);
//输出内容
System.out.println("流程定义id:" + instance.getProcessDefinitionId());
System.out.println("流程实例id:" + instance.getId());
System.out.println("当前活动id:" + instance.getActivityId());
}
完成个人任务:
/**
* 完成个人任务
*/
@Test
public void completeTask() {
//流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//TaskService完成任务
TaskService taskService = processEngine.getTaskService();
//任务id
String taskId = "2506";
//完成任务,出差天数流程变量已经在启动流程实例的时候设置过了,这里可以不用设置了,重复设置会覆盖之前的
taskService.complete(taskId);
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/3d161d479a56327a5b08a94067e531e9.png#pic_center)
当完成启动流程实例后的第一个任务后,查询act_ru_task
表会有两条数据:
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/9e1ffcf3936792cd4a70560a122c7444.png#pic_center)
即使我们并行网关设置了条件,且代码中设置的流程变量只满足了一个条件,但依旧产生了两条任务,也就是并行网关并不会去解析我们设置的条件的,并行网关分支之后,必须要等多个分支任务都完成后汇聚到一起,再流转到下一节点任务。
按当前流程来看:完成申请出差任务后,需要等到项目经理和技术经理都审批后,才会由总经理或者结束任务。
接下来,继续通过个人任务代码,需要完成项目经理和技术经理的任务,如果只完成一个任务,那么任务表中还是停留在并行网关的一个分支任务,并没有通向下一个节点
![image-20211208224811156](https://img-blog.csdnimg.cn/img_convert/01f96d7c22ed591f96b2473a897a881d.png)
分支任务都完成后,走到总经理审批,因为这里有个排他网关,我们的出差天数是4天,所以根据条件走到总经理审批节点。
![image-20211208224921977](https://img-blog.csdnimg.cn/img_convert/81d2f7578be4002392d46bd79ccbe289.png)
总结:只有所有分支达到汇聚点,并行网关才会执行完成;并行的分支任务执行不分前后,由任务的负责人去完成即可
3. 包含网关–InclusiveGateway
3.1 什么是包含网关
包含网关可以看做排他网关和并行网关的结合体,和排他网关一样,可以在外出顺序流上定义条件,包含网关会解析他们,但排他网关只会选择其中一条执行,但包含网关可以选择多条顺序流,同并行网关一样。
包含网关的功能是基于进入和外出顺序流的:
分支:
所有外出顺序流的条件都会被解析,满足条件的顺序流会以并行任务的方式继续执行。
汇聚:
所有并行分支到达包含网关,会进入等待状态,直到所有满足条件的分支都到达后,流程会穿过包含网关继续执行。
3.2 流程定义
出差天数大于3天由项目经理审批,出差天数小于等于3天由技术经理审批,且必须经过人事经理审批。
所以在包含网关通向项目经理和技术经理审批任务的分支连线上需要设置condition条件
![image-20211209215528234](https://img-blog.csdnimg.cn/img_convert/d0381305fc3ab18974d0c29f4f2c9848.png)
3.3 测试
部署包含网关,启动流程实例:
/**
* 部署流程
*/
@Test
public void deployment() {
//流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//创建RepositoryService进行部署
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.name("包含网关流程")
.addClasspathResource("bpmn/inclusivegateway.bpmn20.xml")
.addClasspathResource("bpmn/inclusivegateway.png")
.deploy();
//输出信息
System.out.println("流程key:" + deployment.getKey());
System.out.println("流程名称:" + deployment.getName());
}
/**
* 启动流程实例
*/
@Test
public void startProcessInstance() {
//流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//创建RuntimeService,通过其启动流程实例
RuntimeService runtimeService = processEngine.getRuntimeService();
//设置流程变量--出差天数
Map<String, Object> map = new HashMap<>();
map.put("num", 5);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("inclusivegateway", map);
//输出流程实例信息
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程定义key:" + processInstance.getProcessDefinitionKey());
}
启动流程实例之后,查询act_ru_task
任务表,会有一条创建出差单任务
![image-20211209222129564](https://img-blog.csdnimg.cn/img_convert/1174bf29befc0b8e787e56261f79c43b.png)
完成上面的任务,任务id为2506
/**
* 完成个人任务
*/
@Test
public void completeTask() {
//流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//创建TaskService
TaskService taskService = processEngine.getTaskService();
String taskId = "2506";
taskService.complete(taskId);
}
查询act_ru_execution
流程实例执行表:
第一条记录:包含网关分支
后两条记录代表要执行的分支,分别为人事经理审批和项目经理审批。可通过主键id关联act_ru_task
任务表查询具体任务信息。只有两条要执行的分支,是因为我们设置的出差天数5天,只满足了项目经理审批的条件,技术经理的并不满足,而人事经理在流程设计中是必须要经过的
注意这里2503记录的ACT_ID_值 Task_0dpxs8x
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/b18a2a2415279cbaf91692cbc14df208.png#pic_center)
查询act_ru_task
任务表:同样有两个待执行的任务
![image-20211209223032400](https://img-blog.csdnimg.cn/img_convert/ab5ce95381da087bb134562acd827813.png)
通过完成个人任务代码,先执行项目经理审批,然后查询任务表:act_ru_task
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/f4387748b2f0736b2ed6e0ff034a4d68.png#pic_center)
此时,act_ru_task
表只有人事经理审批任务。
查询流程实例执行表:act_ru_execution
:刷新后,项目经理的那条记录的ACT_ID_
值已经更新,人事经理的那条记录并未更新,因为我们只完成了项目经理的任务,项目经理实例执行的ACT_ID_
变成了第二个包含网关节点的ID,人事经理的依旧停留在当前的状态中
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/2dc780c890b6c74baca63eb876886bb7.png#pic_center)
所以,我们需要接着执行人事经理的任务
通过完成个人任务代码,先执行人事经理审批,然后查询任务表:act_ru_task
![image-20211209224418881](https://img-blog.csdnimg.cn/img_convert/dda965f67868ea775fcc0984ecda37f3.png)
此时,根据设置的条件,任务走到了总经理审批,说明我们后面设置的排他网关也生效了。
接着查询流程实例执行表:包含网关的分支记录已经没有了,包含网关执行完成,分支和汇聚就从act_ru_execution
中删除。
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/5e37ef09fb4bda81b5b5038be1489ccf.png#pic_center)
总结:在包含网关分支时,符合条件的分支将会执行,符合条件的分支也将需要汇聚后才可通向下一个节点。
4. 事件网关–EventGateway
4.1 什么是事件网关
事件网关允许根据事件判断流向。网关的每个外出顺序流都需要连接到一个中间捕获事件,当流程到达一个基于事件网关,网关会进入等待状态:暂停执行。与此同时,会为每个外出顺序流创建相对的事件订阅。流程的走向完全是由中间事件的选择,而由哪个事件来决定则是由最先触发的事件来决定的。
事件网关的外出顺序流和普通的顺序流不同,这些顺序流不会真正的"执行",相反,他们让流程引擎去决定,当执行到达一个基于事件的网关时,需要订阅什么事件。需要考虑以下条件:
- 事件网关必须要有两条或以上的外出顺序流
- 事件网关后,只能使用
intermediateCatchEvent
类型(activiti不支持基于事件网关后连接receiveTask)
- 连接到事件网关的中间捕获事件必须只有一个入口顺序流
4.2 流程定义
设计一个有三个走向的事件网关。后面紧接着定时器事件、信号事件和消息事件,然后在后面分别跟着三个task任务,task任务可以告知我们流程是怎么走的。通过设置task任务的监听器可以更详细的知道整个流程的执行过程。