疯狂Activiti6.0连载(25)BPMN结束事件
来源:互联网 发布:js 设置按钮失效 编辑:程序博客网 时间:2024/06/06 03:04
本文节选自《疯狂工作流讲义(第2版)》
京东购买地址:https://item.jd.com/12246565.html
工作流Activiti6电子书:http://blog.csdn.net/boxiong86/article/details/78488562
工作流Activiti6教学视频:http://blog.csdn.net/boxiong86/article/details/78608585
BPMN结束事件
结束事件表示流程的结束,因此结束事件并不允许有输出的顺序流,BPMN2.0规定没有顺序流可以从结束事件中输出。根据前面的章节所述,结束事件总是抛出事件,这些事件会自动执行并反馈结果,并不需要触发。BPMN2.0中定义了多种结束事件,包括:无指定(None)结束事件、消息(Message)结束事件、升级(Escalation)结束事件、错误(Error)取消事件、取消(Cancel)结束事件、补偿(Compensation)结束事件、信号(Signal)结束事件、终止(Terminate)结束事件和组合(Multiple)结束事件,目前Activiti支持无指定结束事件、错误结束事件、取消结束事件和终止结束事件。
无指定结束事件
与无指定开始事件一样,无指定结束事件,是指流程在结束时,不会进行任何的额外操作,结束事件中不使用任何事件的定义。图11-5为结束事件的图形。
图11-5结束事件的图形
在流程描述文件中,使用endEvent元素定义一件结束事件,代码清单11-14为一个简单的流程配置内容,该段配置的粗体字代码,定义了一个无指定结束事件。
代码清单11-14:codes\11\11.4\end-event\resource\bpmn\NoneEndEvent.bpmn
<process id="myProcess" name="myProcess">
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="User Task"></userTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="usertask1"
targetRef="endevent1"></sequenceFlow>
</process>
错误结束事件
当执行流到达错误结束事件时,会结束该执行流并且抛出错误,该错误可以被“错误边界事件”捕获,如果没有定义任何的错误边界事件,那么将会被当作无指定错误事件执行,因此,错误结束事件一般使用在子流程当中。错误事件结束后,就会触发依附在该子流程上的错误边界事件。图11-6定义了一个含有错误结束事件和错误边界事件的流程。
图11-6含有错误结束事件和错误边界事件的流程
如图11-6所示,该流程一启动,就会进入一个嵌套子流程,当完成了“Sub Task”的用户任务后,会遇到单向网关,此时会产生两个分支,一个分支会正常结束该子流程,另外一个分支会触发错误结束事件,如果正常结束该子流程,流程会到达“End Task”任务,而触发错误结束事件后,流程会到达“Error Task”任务。该流程图对应的流程文件如代码清单11-15所示。
代码清单11-15:codes\11\11.4\end-event\resource\bpmn\ErrorEndEvent.bpmn
<error id="myError" errorCode="myError"></error>
<process id="errorEndProcess" name="errorEndProcess">
<startEvent id="startevent1" name="Start"></startEvent>
<subProcess id="subprocess1" name="Sub Process">
<startEvent id="startevent2" name="Start"></startEvent>
<userTask id="usertask1" name="Sub Task"></userTask>
<endEvent id="endevent1" name="ErrorEnd">
<errorEventDefinition errorRef="myError"></errorEventDefinition>
</endEvent>
<sequenceFlow id="flow2" name="" sourceRef="startevent2"
targetRef="usertask1"></sequenceFlow>
<exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
<endEvent id="endevent3" name="End"></endEvent>
<sequenceFlow id="flow7" name="" sourceRef="usertask1"
targetRef="exclusivegateway1"></sequenceFlow>
<sequenceFlow id="flow8" name="" sourceRef="exclusivegateway1"
targetRef="endevent3">
<conditionExpression xsi:type="tFormalExpression">${success == true}
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow9" name="" sourceRef="exclusivegateway1"
targetRef="endevent1">
<conditionExpression xsi:type="tFormalExpression">${success ==
false}</conditionExpression>
</sequenceFlow>
</subProcess>
<boundaryEvent id="boundaryerror1" cancelActivity="true"
attachedToRef="subprocess1">
<errorEventDefinition errorRef="myError"></errorEventDefinition>
</boundaryEvent>
<userTask id="usertask3" name="End Task"></userTask>
<endEvent id="endevent2" name="End"></endEvent>
<userTask id="usertask4" name="Error Task"></userTask>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="subprocess1"></sequenceFlow>
<sequenceFlow id="flow4" name="" sourceRef="subprocess1"
targetRef="usertask3"></sequenceFlow>
<sequenceFlow id="flow5" name="" sourceRef="usertask3"
targetRef="endevent2"></sequenceFlow>
<sequenceFlow id="flow6" name="" sourceRef="boundaryerror1"
targetRef="usertask4"></sequenceFlow>
</process>
代码清单11-15中的粗体字代码的endEvent和boundaryEvent,分别定义了一个错误结束事件和错误边界事件,这两个事件中的错误事件定义,均引用了“myError”的错误,需要注意的是,在代码清单11-15中,需要使用单向网关,当流程参数“success”的值为true时,将会正常完成子流程,如果流程参数“success”的值为false时(代码清单的粗体部分的表达式),将会触发错误结束事件。代码清单11-16加载该流程文件并执行相应的流程控制。
代码清单11-16:codes\11\11.4\end-event\src\org\crazyit\activiti\ErrorEndEvent.java
//创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//得到流程存储服务组件
RepositoryService repositoryService = engine.getRepositoryService();
//得到运行时服务组件
RuntimeService runtimeService = engine.getRuntimeService();
//获取流程任务组件
TaskService taskService = engine.getTaskService();
//部署流程文件
repositoryService.createDeployment()
.addClasspathResource("bpmn/ErrorEndEvent.bpmn").deploy();
//启动流程
runtimeService.startProcessInstanceByKey("errorEndProcess");
//结束子流程中的任务,并设置结束参数
Task subTask = taskService.createTaskQuery().singleResult();
Map<String, Object> vars = new HashMap<String, Object>();
//设置success参数为true
vars.put("success", "true");
taskService.complete(subTask.getId(), vars);
//查看到达的任务
List<Task> tasks = taskService.createTaskQuery().list();
for (Task task : tasks) {
System.out.println(task.getName());
}
注意代码清单11-16的粗体字代码,该句代码主要用于设置“success”流程参数值,此处设置为“true”,即运行以上代码,将会正常完成子流程,流程会到达“End Task”的任务(不会触发错误结束事件),最终输出结果:End Task;如果将“success”的参数值设置为false,那么将会触发错误结束事件,此时依附在子流程中的错误边界事件将会捕获到错误,流程会到达“Error Task”任务,最终输出结果:Error Task。
在Activiti中,如果触发了边界事件,那么将会产生新的执行流,如果不希望取消原来的执行流,那么可以设置边界事件的cancelActivity属性为false(本例为true),即使新产生的执行流结束,原来的执行流也不会中断,原来执行流的当前活动仍然为边界事件,如果cancelActivity设置为true,原来的执行流将会被取消。
取消结束事件和取消边界事件
取消结束事件只能使用在事务子流程(Transaction Sub-Process)中,该事件表示事务将会取消,并且会触发依附在事务子流程上的取消边界事件,与错误结束事件类似,取消结束事件会被抛出,而取消边界事件则会捕获事件。除此之外,事务子流程的取消事件的触发,还会导致补偿的触发。
在BPMN2.0中,对于已经完成的活动,可以使用补偿机制,而对于一些正在进行的(活跃的)活动,不能使用补偿机制,而可以使用取消机制。当取消边界事件被触发,则会将当前的执行流中断,然后会同步地进行补偿机制,取消边界事件在离开事件子流程前,会一直等待补偿的结束,当补偿结束后,执行流会从取消边界事件离开事务子流程。假设现在有一个汇款的流程,该汇款流程作为一个事务子流程使用在主流程中,当汇款完成后,需要用户进行最终确认,如果用户确认,则结束流程,否则将触发取消结束事件并进行补偿操作,图11-7为该业务流程的流程图。
图11-7汇款业务的流程图
图11-7的流程启动后,会马上进入事务子流,进入子流程后,会直接进行汇款操作,在此是一个ServiceTask,完成了汇款操作后,会进行用户的确认,用户确认完后会到达一个单向网关,判断用户确认的结果,如果用户确认的结果为false,则会进入取消结束事件,最后会触发依附在事务子流程中的取消边界事件(在此之前会触发事务子流程中的补偿事件)。图11-7对应的流程描述文件内容如代码清单11-17所示。
代码清单11-17:codes\11\11.4\end-event\resource\bpmn\CancelEndEvent.bpmn
<process id="cancelProcess" name="cancelProcess">
<startEvent id="startevent1" name="Start"></startEvent>
<transaction id="subprocess1" name="Sub Process">
<serviceTask id="servicetask1" name="汇款操作"
activiti:class="org.crazyit.activiti.RemitDelegate"></serviceTask> ①
<boundaryEvent id="boundarysignal1" attachedToRef="servicetask1"> ②
<compensateEventDefinition></compensateEventDefinition>
</boundaryEvent>
<startEvent id="startevent2" name="Start"></startEvent>
<serviceTask id="servicetask2" name="取消汇款" ③
activiti:class="org.crazyit.activiti.RollbackRemitDelegate"
isForCompensation="true"></serviceTask>
<userTask id="usertask1" name="确认汇款"></userTask>
<exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
<endEvent id="endevent1" name="End"></endEvent>
<endEvent id="endevent2" name="End"> ④
<cancelEventDefinition></cancelEventDefinition>
</endEvent>
<sequenceFlow id="flow3" name="" sourceRef="startevent2"
targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow4" name="" sourceRef="servicetask1"
targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow5" name="" sourceRef="usertask1"
targetRef="exclusivegateway1"></sequenceFlow>
<sequenceFlow id="flow6" name="" sourceRef="exclusivegateway1"
targetRef="endevent1">
<conditionExpression xsi:type="tFormalExpression">${confirm == true}
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow7" name="" sourceRef="exclusivegateway1"
targetRef="endevent2">
<conditionExpression xsi:type="tFormalExpression">${confirm ==
false}
</conditionExpression>
</sequenceFlow>
<association associationDirection="One" id="a1"
sourceRef="boundarysignal1" targetRef="servicetask2" />
</transaction>
<boundaryEvent id="boundarysignal2" cancelActivity="true" ⑤
attachedToRef="subprocess1">
<cancelEventDefinition></cancelEventDefinition>
</boundaryEvent>
<serviceTask id="servicetask3" name="接收取消操作" ⑥
activiti:class="org.crazyit.activiti.ReceiveCancelDelegate"></serviceTask>
<endEvent id="endevent3" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="subprocess1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="subprocess1"
targetRef="endevent3"></sequenceFlow>
<sequenceFlow id="flow8" name="" sourceRef="boundarysignal2"
targetRef="servicetask3"></sequenceFlow>
</process>
注意代码清单11-17的粗体字代码,其中①③⑥定义了三个ServiceTask,对应的是流程中的汇款操作、取消汇款操作和接收取消操作的ServiceTask,①对应的是RemitDelegate类(codes\11\11.4\end-event\src\org\crazyit\activiti\RemitDelegate.java),该类用于处理汇款操作,本例只输出“处理汇款业务”。
代码清单11-17中的③定义的ServiceTask,对应的是RollbackRemitDelegate类(codes\11\11.4\end-event\src\org\crazyit\activiti\RollbackRemitDelegate.java),该ServiceTask会在补偿边界事件被触发后执行,RollbackRemitDelegate在业务上表示用于处理汇款的回滚(取消汇款)操作,此处只会输出“处理回滚汇款业务”。
需要注意的是,在定义取消汇款的ServiceTask的时候,需要为serviceTask加入isForCompensation属性并将值设置为true,该属性表示这个ServiceTask是一个补偿处理者的角色。代码清单中的⑥为接收取消通知的ServiceTask,对应的类为ReceiveCancelDelegate类(codes\11\11.4\end-event\src\org\crazyit\activiti\ReceiveCancelDelegate.java),如果事务子流程被触发并且处理完全部的补偿事件后,则会执行该ServiceTask,本例中该类输出“处理子流程取消后的业务”。
代码清单11-17中的②定义了一个补偿边界事件,如果该补偿边界事件所处的事务子流程被取消,则该补偿边界事件就会被触发,在本例中,如果②的补偿边界事件被触发,就会执行“取消汇款”的ServiceTask。
代码清单11-17中的④定义了一个取消结束事件,当执行流到达取消结束事件时,就会抛出取消事件,而在代码清11-17中的⑤则会捕获该事件,⑤定义了一个取消边界事件,取消边界事件用于捕获取消事件,当捕获到事件后,则会中断当前的执行流,然后触发事务子流程中的补偿事件,最后流程离开取消边界事件,最后执行⑥所定义的ServiceTask,代码清单11-18加载该流程文件。
代码清单11-18:codes\11\11.4\end-event\src\org\crazyit\activiti\CancelEndEvent.java
//创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//得到流程存储服务组件
RepositoryService repositoryService = engine.getRepositoryService();
//得到运行时服务组件
RuntimeService runtimeService = engine.getRuntimeService();
//获取流程任务组件
TaskService taskService = engine.getTaskService();
//部署流程文件
repositoryService.createDeployment()
.addClasspathResource("bpmn/CancelEndEvent.bpmn").deploy();
//启动流程
runtimeService.startProcessInstanceByKey("cancelProcess");
//初始化流程参数
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("confirm", false);
//设置参数,完成用户确认的Task
Task task = taskService.createTaskQuery().singleResult();
taskService.complete(task.getId(), vars);
当图11-7的流程启动后,会经过“汇款操作”的ServiceTask,此时会输出“处理汇款业务”,然后到达“用户确认”的Task,代码清单11-18中将“用户确认”的Task完成并设置“confirm”参数为false,这个时候流程会到达取消结束事件,取消结束事件被触发并抛出,此时取消边界事件会捕获该抛出事件,触发事务子流程里面的补偿事件(此处为代码清单11-17中的②)。事务子流程里面“取消汇款”(代码清单11-17中的③)是“汇款操作”(代码清单11-17中的①)的补偿,当补偿事件被触发后,“取消汇款”的ServiceTask被执行,输出“处理回滚汇款业务”。当整个事务子流程里面的补偿事件都处理完后,流程离开取消边界事件(代码清单11-17中的⑤),到达“接收取消操作”的ServiceTask,输出“处理子流程取消后的业务”。运行代码清单11-18,输出结果如下:
处理汇款业务
处理回滚汇款业务
处理子流程取消后的业务
终止结束事件
当流程执行到终止结束事件,当前的流程将会被终结,该事件可以使用在嵌入子流程、调用子流程、事件子流程或者事务子流程中。终止结束事件使用terminateEventDefinition元素作为事件定义,如果将该元素的activiti:terminateAll属性设置为true,那么当终止结束事件被触发事时,流程实例的全部执行流均会被终结。图11-8是一个简单流程,对应的流程XML文件如代码清单11-19所示。
图11-8测试终止结束事件流程
代码清单11-19:codes\11\11.4\end-event\resource\bpmn\TerminateEndEvent_TerminateAll.bpmn
<process id="terminateAll" name="terminateAll" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
<subProcess id="subprocess1" name="Sub Process">
<startEvent id="startevent2" name="Start"></startEvent>
<serviceTask id="servicetask2" name="子流程的ServiceTask"
activiti:class="org.crazyit.activiti.SubProcessDelegate"></serviceTask>
<endEvent id="terminateendevent1" name="TerminateEndEvent">
<terminateEventDefinition
activiti:terminateAll="true"></terminateEventDefinition>
</endEvent>
<sequenceFlow id="flow7" sourceRef="startevent2"
targetRef="servicetask2"></sequenceFlow>
<sequenceFlow id="flow8" sourceRef="servicetask2"
targetRef="terminateendevent1"></sequenceFlow>
</subProcess>
<userTask id="servicetask1" name="第一个用户任务"></userTask>
<parallelGateway id="parallelgateway1" name="Parallel Gateway"></parallelGateway>
<sequenceFlow id="flow1" sourceRef="startevent1"
targetRef="parallelgateway1"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="parallelgateway1"
targetRef="subprocess1"></sequenceFlow>
<sequenceFlow id="flow3" sourceRef="parallelgateway1"
targetRef="servicetask1"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<userTask id="usertask1" name="第二个用户任务"></userTask>
<sequenceFlow id="flow4" sourceRef="subprocess1"
targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow5" sourceRef="servicetask1"
targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow6" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow>
</process>
代码清单11-19中的粗体字代码,定义了终止结束事件,并将activiti:terminateAll属性设置为true,流程启动后,会分为两个执行流,一个到达子流程,一个到达“第一个用户任务”,子流程会自动执行ServictTask并触发终止结束事件,由于设置了activiti:terminateAll属性,因此当子流程中的结束事件触发后,整个流程实例会被结束。代码清单11-20为测试代码。
代码清单11-20:codes\11\11.4\end-event\src\org\crazyit\activiti\TerminateEndEvent.java
//创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
//得到流程存储服务组件
RepositoryService repositoryService = engine.getRepositoryService();
//得到运行时服务组件
RuntimeService runtimeService = engine.getRuntimeService();
//部署流程文件
repositoryService
.createDeployment()
.addClasspathResource(
"bpmn/TerminateEndEvent_TerminateAll.bpmn")
.addClasspathResource("bpmn/TerminateEndEvent.bpmn").deploy();
//启动含有terminateAll属性的流程
ProcessInstance pi1 = runtimeService
.startProcessInstanceByKey("terminateAll");
//查询执行流数量
long exeCount = runtimeService.createExecutionQuery()
.processInstanceId(pi1.getId()).count();
System.out.println("含有terminateAll 属性的流程,中断结束事件触发后执行流数量:" + exeCount);
//启动不含 有 terminateAll属性的流程
ProcessInstance pi2 = runtimeService
.startProcessInstanceByKey("terminateEvent");
//查询全部执行流数量
exeCount = runtimeService.createExecutionQuery()
.processInstanceId(pi2.getId()).count();
System.out.println("不含有terminateAll属性的流程,中断结束事件触发后执行流数量:" + exeCount);
注意代码清单10-20中加载了两份流程文件,一份将activiti:terminateAll设置为true,而另外一份则没有设置该属性(默认值为false),两份流程文件的流程图与图11-8一致。代码清单10-20加载两份流程文件后,分别启动两个流程实例,然后再进行执行流查询。运行代码清单10-20,得到以下结果:
含有 terminateAll属性的流程,中断结束事件触发后执行流数量:0
不含有terminateAll属性的流程,中断结束事件触发后执行流数量:3
根据输出结果可知,如果终止结束事件的activiti:terminateAll属性被设置为true,终止结束事件触发后,整个流程实例将会被终结,查询不到任何执行流。
京东购买地址:https://item.jd.com/12246565.html
工作流Activiti6电子书:http://blog.csdn.net/boxiong86/article/details/78488562
工作流Activiti6教学视频:http://blog.csdn.net/boxiong86/article/details/78608585
本书代码共享地址:https://gitee.com/yangenxiong/CrazyActiviti
- 疯狂Activiti6.0连载(25)BPMN结束事件
- 疯狂Activiti6.0连载(24)BPMN开始事件
- 疯狂Activiti6.0连载(26)BPMN边界事件
- 疯狂Activiti6.0连载(27)BPMN中间事件
- 疯狂Activiti6.0连载(28)BPMN补偿中间事件
- 疯狂Activiti6.0连载(23)BPMN事件分类与事件定义
- 疯狂Activiti6.0连载(13)DMN的XML规范
- 疯狂Activiti6.0连载(15)DMN规则匹配表达式
- 疯狂Activiti6.0连载(16) Drools介绍与运行
- 疯狂Activiti6.0连载(17) Drools规则语法概述
- 疯狂Activiti6.0连载(18) Activiti与Drools整合
- 疯狂Activiti6.0连载(19)Activiti整合Spring
- 疯狂Activiti6.0连载(20)Activiti与Spring Boot
- 疯狂Activiti6.0连载(21)Activiti的Web Service
- 疯狂Activiti6.0连载(22)流程存储Web Service
- 疯狂Activiti6.0连载(29)任务监听器
- 疯狂Activiti6连载(11)Activiti6的流程控制逻辑
- 疯狂Activiti6连载(1)Activiti介绍
- AWSCE2搭建PPTP VPN服务器
- OKhttp的异步get和post烦人封装
- gq arm汇编
- MvP_retrofit的封装
- C__va_list变参数处理
- 疯狂Activiti6.0连载(25)BPMN结束事件
- 上拉刷新
- 用java语言实现从文本文件导入一批学生信息的数据到数据库中,1.并完成数据的增删改查,同时导出简单的报表,2.查询籍贯属于黑龙江省的所有学生,并按照生日排序,查询结果导出为csv文件。
- C语言复习
- hdu 1502
- kuangbin专题五 并查集 POJ 1182食物链(带权并查集)重要
- C语言小游戏——五子棋
- vim中的删除,复制和撤销操作
- Excel打开csv文件中文乱码解决方法