一、Activiti相关介绍
1.1 activiti相关数据表
表分类 | 表名 | 解释 |
---|---|---|
一般数据 | ||
[ACT_GE_BYTEARRAY] | 通用的流程定义和流程资源 | |
[ACT_GE_PROPERTY] | 系统相关属性 | |
流程历史记录 | ||
[ACT_HI_ACTINST] | 历史的流程实例 | |
[ACT_HI_ATTACHMENT] | 历史的流程附件 | |
[ACT_HI_COMMENT] | 历史的说明性信息 | |
[ACT_HI_DETAIL] | 历史的流程运行中的细节信息 | |
[ACT_HI_IDENTITYLINK] | 历史的流程运行过程中用户关系 | |
[ACT_HI_PROCINST] | 历史的流程实例 | |
[ACT_HI_TASKINST] | 历史的任务实例 | |
[ACT_HI_VARINST] | 历史的流程运行中的变量信息 | |
流程定义表 | ||
[ACT_RE_DEPLOYMENT] | 部署单元信息 | |
[ACT_RE_MODEL] | 模型信息 | |
[ACT_RE_PROCDEF] | 已部署的流程定义 | |
运行实例表 | ||
[ACT_RU_EVENT_SUBSCR] | 运行时事件 | |
[ACT_RU_EXECUTION] | 运行时流程执行实例 | |
[ACT_RU_IDENTITYLINK] | 运行时用户关系信息,存储任务节点与参与者的相关信息 | |
[ACT_RU_JOB] | 运行时作业 | |
[ACT_RU_TASK] | 运行时任务 | |
[ACT_RU_VARIABLE] | 运行时变量表 |
1.2 Servcie服务接口
service名称 | service作用 |
---|---|
RepositoryService | activiti的资源管理类 |
RuntimeService | activiti的流程运行管理类 |
TaskService | activiti的任务管理类 |
HistoryService | activiti的历史管理类 |
ManagerService | activiti的引擎管理类 |
二、activiti流程图
创建Activiti工作流主要包含以下几步:
1、定义流程,按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来
2、部署流程,把画好的流程定义文件,加载到数据库中,生成表的数据
3、启动流程,使用java代码来操作数据库表中的内容
2.1 绘制流程
使用滑板来绘制流程,通过从右侧把图标拖拽到左侧的画板,最终效果如下:
2.2 指定流程定义Key
流程定义key即流程定义的标识,通过properties视图查看流程的key
2.3 指定任务负责人
在properties视图指定每个任务结点的负责人,如:填写出差申请的负责人为 zhangsan
经理审批负责人为 jerry,总经理审批负责人为 jack,财务审批负责人为 rose
2.4 解决中文乱码
1、打开Settings,找到File Encodings,把encoding的选项都选择UTF-8
2、打开IDEA安装路径,找到如下的安装目录
根据自己所安装的版本来决定,我使用的是64位的idea,所以在idea64.exe.vmoptions文件的最后一行追加一条命令: -Dfile.encoding=UTF-8
如下所示:
一定注意,不要有空格,否则重启IDEA时会打不开,然后 重启IDEA。
如果以上方法已经做完,还出现乱码,就再修改一个文件,并在文件的末尾添加: -Dfile.encoding=UTF-8,然后重启idea,如图:
三、流程操作
3.1 流程定义部署
3.1.1 单个文件部署方式
分别将bpmn文件和png图片文件部署。
package com.itheima.test; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.RepositoryService; import org.activiti.engine.repository.Deployment; import org.junit.Test; public class ActivitiDemo { /** * 部署流程定义 */ @Test public void testDeployment(){ // 1、创建ProcessEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 2、得到RepositoryService实例 RepositoryService repositoryService = processEngine.getRepositoryService(); // 3、使用RepositoryService进行部署 Deployment deployment = repositoryService.createDeployment() .addClasspathResource("bpmn/evection.bpmn") // 添加bpmn资源 .addClasspathResource("bpmn/evection.png") // 添加png资源 .name("出差申请流程") .deploy(); // 4、输出部署信息 System.out.println("流程部署id:" + deployment.getId()); System.out.println("流程部署名称:" + deployment.getName()); } }
执行此操作后activiti会将上边代码中指定的bpm文件和图片文件保存在activiti数据库。
3.1.2 压缩包部署方式
将evection.bpmn和evection.png压缩成zip包。
@Test public void deployProcessByZip() { // 定义zip输入流 InputStream inputStream = this .getClass() .getClassLoader() .getResourceAsStream( "bpmn/evection.zip"); ZipInputStream zipInputStream = new ZipInputStream(inputStream); // 获取repositoryService RepositoryService repositoryService = processEngine .getRepositoryService(); // 流程部署 Deployment deployment = repositoryService.createDeployment() .addZipInputStream(zipInputStream) .deploy(); System.out.println("流程部署id:" + deployment.getId()); System.out.println("流程部署名称:" + deployment.getName()); }
5.2 启动流程实例
流程定义部署在activiti后就可以通过工作流管理业务流程了,也就是说上边部署的出差申请流程可以使用了。
针对该流程,启动一个流程表示发起一个新的出差申请单,这就相当于java类与java对象的关系,类定义好后需要new创建一个对象使用,当然可以new多个对象。对于请出差申请流程,张三发起一个出差申请单需要启动一个流程实例,出差申请单发起一个出差单也需要启动一个流程实例。
代码如下:
/** * 启动流程实例 */ @Test public void testStartProcess(){ // 1、创建ProcessEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 2、获取RunTimeService RuntimeService runtimeService = processEngine.getRuntimeService(); // 3、根据流程定义Id启动流程 ProcessInstance processInstance = runtimeService .startProcessInstanceByKey("myEvection"); // 输出内容 System.out.println("流程定义id:" + processInstance.getProcessDefinitionId()); System.out.println("流程实例id:" + processInstance.getId()); System.out.println("当前活动Id:" + processInstance.getActivityId()); }
输出内容如下:
5.3 任务查询
流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
/** * 查询当前个人待执行的任务 */ @Test public void testFindPersonalTaskList() { // 任务负责人 String assignee = "zhangsan"; ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 创建TaskService TaskService taskService = processEngine.getTaskService(); // 根据流程key 和 任务负责人 查询任务 List<Task> list = taskService.createTaskQuery() .processDefinitionKey("myEvection") //流程Key .taskAssignee(assignee)//只查询该任务负责人的任务 .list(); for (Task task : list) { System.out.println("流程实例id:" + task.getProcessInstanceId()); System.out.println("任务id:" + task.getId()); System.out.println("任务负责人:" + task.getAssignee()); System.out.println("任务名称:" + task.getName()); } }
输出结果如下:
流程实例id:2501 任务id:2505 任务负责人:zhangsan 任务名称:创建出差申请
5.4 流程任务处理
任务负责人查询待办任务,选择任务进行处理,完成任务。
// 完成任务 @Test public void completTask(){ // 获取引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取taskService TaskService taskService = processEngine.getTaskService(); // 根据流程key 和 任务的负责人 查询任务 // 返回一个任务对象 Task task = taskService.createTaskQuery() .processDefinitionKey("myEvection") //流程Key .taskAssignee("zhangsan") //要查询的负责人 .singleResult(); // 完成任务,参数:任务id taskService.complete(task.getId()); }
5.5 流程定义信息查询
查询流程相关信息,包含流程定义,流程部署,流程定义版本
/** * 查询流程定义 */ @Test public void queryProcessDefinition(){ // 获取引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // repositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); // 得到ProcessDefinitionQuery 对象 ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery(); // 查询出当前所有的流程定义 // 条件:processDefinitionKey =evection // orderByProcessDefinitionVersion 按照版本排序 // desc倒叙 // list 返回集合 List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("myEvection") .orderByProcessDefinitionVersion() .desc() .list(); // 输出流程定义信息 for (ProcessDefinition processDefinition : definitionList) { System.out.println("流程定义 id="+processDefinition.getId()); System.out.println("流程定义 name="+processDefinition.getName()); System.out.println("流程定义 key="+processDefinition.getKey()); System.out.println("流程定义 Version="+processDefinition.getVersion()); System.out.println("流程部署ID ="+processDefinition.getDeploymentId()); } }
输出结果:
流程定义id:myEvection:1:4 流程定义名称:出差申请单 流程定义key:myEvection 流程定义版本:1
5.6 流程删除
public void deleteDeployment() { // 流程部署id String deploymentId = "1"; ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 通过流程引擎获取repositoryService RepositoryService repositoryService = processEngine .getRepositoryService(); //删除流程定义,如果该流程定义已有流程实例启动则删除时出错 repositoryService.deleteDeployment(deploymentId); //设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式,如果流程 //repositoryService.deleteDeployment(deploymentId, true); }
说明:
-
使用repositoryService删除流程定义,历史表信息不会被删除
-
如果该流程定义下没有正在运行的流程,则可以用普通删除。
如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。
先删除没有完成流程节点,最后就可以完全删除流程定义信息
项目开发中级联删除操作一般只开放给超级管理员使用.
5.7 流程资源下载
现在我们的流程资源文件已经上传到数据库了,如果其他用户想要查看这些资源文件,可以从数据库中把资源文件下载到本地。
解决方案有:
1、jdbc对blob类型,clob类型数据读取出来,保存到文件目录
2、使用activiti的api来实现
使用commons-io.jar 解决IO的操作
引入commons-io依赖包
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
通过流程定义对象获取流程定义资源,获取bpmn和png
import org.apache.commons.io.IOUtils; @Test public void deleteDeployment(){ // 获取引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取repositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); // 根据部署id 删除部署信息,如果想要级联删除,可以添加第二个参数,true repositoryService.deleteDeployment("1"); } public void queryBpmnFile() throws IOException { // 1、得到引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 2、获取repositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); // 3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionKey("myEvection") .singleResult(); // 4、通过流程定义信息,得到部署ID String deploymentId = processDefinition.getDeploymentId(); // 5、通过repositoryService的方法,实现读取图片信息和bpmn信息 // png图片的流 InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName()); // bpmn文件的流 InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName()); // 6、构造OutputStream流 File file_png = new File("d:/evectionflow01.png"); File file_bpmn = new File("d:/evectionflow01.bpmn"); FileOutputStream bpmnOut = new FileOutputStream(file_bpmn); FileOutputStream pngOut = new FileOutputStream(file_png); // 7、输入流,输出流的转换 IOUtils.copy(pngInput,pngOut); IOUtils.copy(bpmnInput,bpmnOut); // 8、关闭流 pngOut.close(); bpmnOut.close(); pngInput.close(); bpmnInput.close(); }
说明:
-
deploymentId为流程部署ID
-
resource_name为act_ge_bytearray表中NAME_列的值
-
使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称
-
使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流
最后的将输入流中的图片资源进行输出。
5.8 流程历史信息的查看
即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在activiti的act_hi_*相关的表中。所以我们还是可以查询流程执行的历史信息,可以通过HistoryService来查看相关的历史记录。
/** * 查看历史信息 */ @Test public void findHistoryInfo(){ // 获取引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取HistoryService HistoryService historyService = processEngine.getHistoryService(); // 获取 actinst表的查询对象 HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery(); // 查询 actinst表,条件:根据 InstanceId 查询 // instanceQuery.processInstanceId("2501"); // 查询 actinst表,条件:根据 DefinitionId 查询 instanceQuery.processDefinitionId("myEvection:1:4"); // 增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序 instanceQuery.orderByHistoricActivityInstanceStartTime().asc(); // 查询所有内容 List<HistoricActivityInstance> activityInstanceList = instanceQuery.list(); // 输出 for (HistoricActivityInstance hi : activityInstanceList) { System.out.println(hi.getActivityId()); System.out.println(hi.getActivityName()); System.out.println(hi.getProcessDefinitionId()); System.out.println(hi.getProcessInstanceId()); System.out.println("<==========================>"); } }
四、与项目整合
流程实例(ProcessInstance)代表流程定义的执行实例
4.1 启动流程实例 并添加Businesskey(业务标识)
流程定义部署在activiti后,就可以在系统中通过activiti去管理该流程的执行,执行流程表示流程的一次执行。
比如部署系统出差流程后,如果某用户要申请出差这时就需要执行这个流程,如果另外一个用户也要申请出差则也需要执行该流程,每个执行互不影响,每个执行是单独的流程实例。
启动流程实例时,指定的businesskey,就会在act_ru_execution #流程实例的执行表中存储businesskey。
Businesskey:业务标识,通常为业务表的主键,业务标识和流程实例一一对应。业务标识来源于业务系统。存储业务标识就是根据业务标识来关联查询业务系统的数据。
4.2 关联BusinessKey
在activiti实际应用时,查询流程实例列表时可能要显示出业务系统的一些相关信息,比如:查询当前运行的出差流程列表需要将出差单名称、出差天数等信息显示出来,出差天数等信息在业务系统中存在,而并没有在activiti数据库中存在,所以是无法通过activiti的api查询到出差天数等信息。
业务表:
4.3 挂起、激活流程实例
4.3.1 全部流程实例挂起
操作流程定义为挂起状态,该流程定义下边所有的流程实例全部暂停:
流程定义为挂起状态该流程定义将不允许启动新的流程实例,同时该流程定义下所有的流程实例将全部挂起暂停执行。
/** * 全部流程实例挂起与激活 */ @Test public void SuspendAllProcessInstance(){ // 获取processEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取repositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); // 查询流程定义的对象 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery(). processDefinitionKey("myEvection"). singleResult(); // 得到当前流程定义的实例是否都为暂停状态 boolean suspended = processDefinition.isSuspended(); // 流程定义id String processDefinitionId = processDefinition.getId(); // 判断是否为暂停 if(suspended){ // 如果是暂停,可以执行激活操作 ,参数1 :流程定义id ,参数2:是否激活,参数3:激活时间 repositoryService.activateProcessDefinitionById(processDefinitionId, true, null ); System.out.println("流程定义:"+processDefinitionId+",已激活"); }else{ // 如果是激活状态,可以暂停,参数1 :流程定义id ,参数2:是否暂停,参数3:暂停时间 repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null); System.out.println("流程定义:"+processDefinitionId+",已挂起"); } }
4.3.2 单个流程实例挂起
操作流程实例对象,针对单个流程执行挂起操作,某个流程实例挂起则此流程不再继续执行,完成该流程实例的当前任务将报异常。
/** * 单个流程实例挂起与激活 */ @Test public void SuspendSingleProcessInstance(){ // 获取processEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // RuntimeService RuntimeService runtimeService = processEngine.getRuntimeService(); // 查询流程定义的对象 ProcessInstance processInstance = runtimeService. createProcessInstanceQuery(). processInstanceId("15001"). singleResult(); // 得到当前流程定义的实例是否都为暂停状态 boolean suspended = processInstance.isSuspended(); // 流程定义id String processDefinitionId = processInstance.getId(); // 判断是否为暂停 if(suspended){ // 如果是暂停,可以执行激活操作 ,参数:流程定义id runtimeService.activateProcessInstanceById(processDefinitionId); System.out.println("流程定义:"+processDefinitionId+",已激活"); }else{ // 如果是激活状态,可以暂停,参数:流程定义id runtimeService.suspendProcessInstanceById( processDefinitionId); System.out.println("流程定义:"+processDefinitionId+",已挂起"); } }
五、个人任务
5.1 分配任务负责人
5.1.1 固定分配
在进行业务流程建模时指定固定的任务负责人, 如图:
5.1.2 表达式分配
由于固定分配方式,任务只管一步一步执行任务,执行到每一个任务将按照 bpmn 的配置去分配任 务负责人。
5.1.2.1 UEL 表达式
Activiti 使用 UEL 表达式, UEL 是 java EE6 规范的一部分, UEL(Unified Expression Language)即 统一表达式语言, activiti 支持两个 UEL 表达式: UEL-value 和 UEL-method。
1)UEL-value 定义
如图:
assignee 这个变量是 activiti 的一个流程变量,
或者使用这种方式定义:
user 也是 activiti 的一个流程变量, user.assignee 表示通过调用 user 的 getter 方法获取值。
2)UEL-method 方式
如图:
userBean 是 spring 容器中的一个 bean,表示调用该 bean 的 getUserId()方法。
5.2流程变量
流程变量在 activiti 中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti 结合时少不了流程变量,流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量。
注意:虽然流程变量中可以存储业务数据可以通过activiti的api查询流程变量从而实现 查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti设置流程变量是为了流程执行需要而创建。
流程变量的使用方法
5.2.1 在属性上使用UEL表达式
可以在 assignee 处设置 UEL 表达式,表达式的值为任务的负责人,比如: ${assignee}, assignee 就是一个流程变量名称。
Activiti获取UEL表达式的值,即流程变量assignee的值 ,将assignee的值作为任务的负责人进行任务分配
5.2.2 在连线上使用UEL表达式
可以在连线上设置UEL表达式,决定流程走向。
比如:${price<10000} 。price就是一个流程变量名称,uel表达式结果类型为布尔类型。
如果UEL表达式是true,要决定 流程执行走向。
5.3 监听器分配
可以使用监听器来完成很多Activiti流程的业务。
使用监听器的方式来指定负责人,那么在流程设计时就不需要指定assignee。
任务监听器是发生对应的任务相关事件时执行自定义 java 逻辑 或表达式。 任务相当事件包括:
Event的选项包含:
Create:任务创建后触发 Assignment:任务分配后触发 Delete:任务完成后触发 All:所有事件发生都触发
定义任务监听类,且类必须实现 org.activiti.engine.delegate.TaskListener 接口
public class MyTaskListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { if(delegateTask.getName().equals("创建出差申请")&& delegateTask.getEventName().equals("create")){ //这里指定任务负责人 delegateTask.setAssignee("张三"); } } }
六、组任务:
在流程定义中在任务结点的 assignee 固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn 文件中,如果临时任务负责人变更则需要修改流程定义,系统可扩展性差。
6.1 组任务办理流程
a、查询组任务
指定候选人,查询该候选人当前的待办任务。
候选人不能立即办理任务。
List<Task> list = taskService.createTaskQuery() .processDefinitionKey(processDefinitionKey) .taskCandidateUser(candidateUser)//根据候选人查询 .list();
b、拾取(claim)任务
该组任务的所有候选人都能拾取。
将候选人的组任务,变成个人任务。原来候选人就变成了该任务的负责人。
Task task = taskService.createTaskQuery() .taskId(taskId) .taskCandidateUser(userId)//根据候选人查询 .singleResult(); if(task!=null){ //拾取任务 taskService.claim(taskId, userId); System.out.println("任务拾取成功"); }
c、查询个人任务
查询方式同个人任务部分,根据assignee查询用户负责的个人任务。
TaskService taskService = processEngine.getTaskService(); List<Task> list = taskService.createTaskQuery() .processDefinitionKey(processDefinitionKey) .taskAssignee(assignee) .list();
d、办理个人任务
processEngine.getTaskService() .complete(taskId);
e、 归还组任务
如果个人不想办理该组任务,可以归还组任务,归还后该用户不再是该任务的负责人
// 校验userId是否是taskId的负责人,如果是负责人才可以归还组任务 Task task = taskService .createTaskQuery() .taskId(taskId) .taskAssignee(userId) .singleResult(); if (task != null) { // 如果设置为null,归还组任务,该 任务没有负责人 taskService.setAssignee(taskId, null); }
f、 任务交接
任务交接,任务负责人将任务交给其它候选人办理该任务
Task task = taskService .createTaskQuery() .taskId(taskId) .taskAssignee(userId) .singleResult(); if (task != null) { taskService.setAssignee(taskId, candidateuser); }
七、网关
网关用来控制流程的流向
7.1 排他网关ExclusiveGateway
7.1.1 什么是排他网关:
排他网关,用来在流程中实现决策。 当流程执行到这个网关,所有分支都会判断条件是否为true,如果为true则执行该分支,
注意:排他网关只会选择一个为true的分支执行。如果有两个分支条件都为true,排他网关会选择id值较小的一条分支去执行。
为什么要用排他网关?
不用排他网关也可以实现分支,如:在连线的condition条件上设置分支条件。
在连线设置condition条件的缺点:如果条件都不满足,流程就结束了(是异常结束)。
如果 使用排他网关决定分支的走向,如下:
7.1.2 流程定义
排他网关图标,红框内:
7.2 并行网关ParallelGateway
7.2.1 什么是并行网关
并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进入和外出顺序流的:
l fork分支:
并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。
l join汇聚:
所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。
注意,如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
与其他网关的主要区别是,并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。
例子:
7.2.2 流程定义
并行网关图标,红框内:
7.3 包含网关InclusiveGateway
7.3.1 什么是包含网关
包含网关可以看做是排他网关和并行网关的结合体。
和排他网关一样,你可以在外出顺序流上定义条件,包含网关会解析它们。 但是主要的区别是包含网关可以选择多于一条顺序流,这和并行网关一样。
包含网关的功能是基于进入和外出顺序流的:
l 分支:
所有外出顺序流的条件都会被解析,结果为true的顺序流会以并行方式继续执行, 会为每个顺序流创建一个分支。
l 汇聚:
所有并行分支到达包含网关,会进入等待状态, 直到每个包含流程token的进入顺序流的分支都到达。 这是与并行网关的最大不同。换句话说,包含网关只会等待被选中执行了的进入顺序流。 在汇聚之后,流程会穿过包含网关继续执行。
7.3.2 流程定义:
出差申请大于等于3天需要由项目经理审批,小于3天由技术经理审批,出差申请必须经过人事经理审批。
包含网关图标,红框内:
定义流程:
注意:通过包含网关的每个分支的连线上设置condition条件。
7.4 事件网关EventGateway
事件网关允许根据事件判断流向。网关的每个外出顺序流都要连接到一个中间捕获事件。 当流程到达一个基于事件网关,网关会进入等待状态:会暂停执行。与此同时,会为每个外出顺序流创建相对的事件订阅。
事件网关的外出顺序流和普通顺序流不同,这些顺序流不会真的"执行", 相反它们让流程引擎去决定执行到事件网关的流程需要订阅哪些事件。 要考虑以下条件:
-
事件网关必须有两条或以上外出顺序流;
-
事件网关后,只能使用intermediateCatchEvent类型(activiti不支持基于事件网关后连接ReceiveTask)
-
连接到事件网关的中间捕获事件必须只有一个入口顺序流。
7.4.1流程定义
事件网关图标,红框内
intermediateCatchEvent:
intermediateCatchEvent支持的事件类型:
Message Event: 消息事件
Singal Event: 信号事件
Timer Event: 定时事件
使用事件网关定义流程: