疯狂Activiti6.0连载(24)BPMN开始事件


声明:本文转载自https://my.oschina.net/JavaLaw/blog/1586650,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

本文节选自《疯狂工作流讲义(第2版)》

京东购买地址:https://item.jd.com/12246565.html

疯狂Activiti电子书:https://my.oschina.net/JavaLaw/blog/1570397

工作流Activiti教学视频:https://my.oschina.net/JavaLaw/blog/1577577

 

开始事件

        开始事件表示流程的开启,可以使用各种类型的开始事件来启动流程,例如使用定时器开始事件,定时启动业务流程,可以使用错误开始事件来表示错误业务流程的开始,根据前面章节所述,所有的开始事件都是Catching事件,即全部的开始事件都会等待着被触发。

无指定开始事件

        不为开始事件指定任何的触发条件(触发器)的事件为无指定开始事件,使用无指定开始事件,流程引擎并不知道流程将会在什么时候开始,如果需要启动流程,就必须使用RuntimeService的startProcessByXXX方法。需要注意的是,子流程(Sub-Process)中总会是一个无指定开始事件,即使将子流程中的开始事件强制定义为其他开始事件,也会被看作无指定开始事件,因为流程到达子流程(Sub-Process)时,就意味着子流程需要启动,而并不需要其他的启动条件。图11-1为无指定开始事件的图形,代码清单11-5为一个含有无指定开始事件的流程XML配置。

图11-1 无指定开始事件图形

        代码清单11-5:codes\11\11.3\start-event\resource\bpmn\NoneStartEvent.bpmn

    <process id="myProcess" name="myProcess">         <startEvent id="startevent1" name="Start"></startEvent>         <userTask id="usertask1" name="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-5,使用startEvent元素定义了一个开始事件,该元素下没有任何的子元素,表示这个开始事件没有任何的事件定义,是一个无指定开始事件。定义了流程后,要启动该流程,需要使用RuntimeService的startProcessByXXX方法,以下为该流程的启动代码:

        // 创建流程引擎         ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();         // 得到流程存储服务组件         RepositoryService repositoryService = engine.getRepositoryService();         // 得到运行时服务组件         RuntimeService runtimeService = engine.getRuntimeService();         // 部署流程文件         repositoryService.createDeployment()                 .addClasspathResource("bpmn/NoneStartEvent.bpmn").deploy();         runtimeService.startProcessInstanceByKey("myProcess"); 

定时器开始事件

        在开始事件中加入定时器事件定义,该开始事件成为一个定时器开始事件,当符合时间条件后,流程启动,而并不需要像无指定开始事件一样,需要使用API启动流程。在日常生活中有许多需要定时启动的流程,例如要求项目经理每天下班时检查成员的工作日志,又如需要定时检查服务器端口是否存在等,此时可以使用定时器开始事件来实现流程的定时启动。图11-2定义了一个简单的工作流程,代码清单11-6为该流程的配置。

图11-2 定时器开始流程

        代码清单11-6:codes\11\11.3\start-event\resource\bpmn\TimerStartEvent.bpmn

    <process id="timerStartProcess" name="timerStartProcess">         <startEvent id="timerstartevent1" name="Timer start">             <timerEventDefinition>                 <timeCycle>0/5 * * * * ?</timeCycle>             </timerEventDefinition>         </startEvent>         <userTask id="usertask1" name="Check Log"></userTask>         <endEvent id="endevent1" name="End"></endEvent>         <sequenceFlow id="flow1" name="" sourceRef="timerstartevent1"             targetRef="usertask1"></sequenceFlow>         <sequenceFlow id="flow2" name="" sourceRef="usertask1"             targetRef="endevent1"></sequenceFlow>     </process> 

        代码清单11-6中,为开始事件添加了定时器事件定义,并且使用了timeCycle元素,该元素支持使用cron表达式,本例为了能看到测试效果,cron表达式中设置了流程将会在每分钟的第0秒开始,每隔5秒将会启动一次流程,代码清单11-7为运行代码。

        代码清单11-7:codes\11\11.3\start-event\src\org\crazyit\activiti\TimerStartEvent.java

        // 创建流程引擎         ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();                 // 得到流程存储服务组件         RepositoryService repositoryService = engine.getRepositoryService();         // 得到运行时服务组件         RuntimeService runtimeService = engine.getRuntimeService();         // 部署流程文件         repositoryService.createDeployment()             .addClasspathResource("bpmn/TimerStartEvent.bpmn").deploy();         // 等待时间条件         Thread.sleep(70 * 1000);         // 查询流程实例         List<ProcessInstance> ints = runtimeService.createProcessInstanceQuery().list();         System.out.println(ints.size()); 

        代码清单11-7中,并没有使用启动流程的API,在等待70秒后进行流程实例查询,根据查询的流程实例可知,在等待过程中,定时器已经帮我们启动了若干流程实例。

        BPMN2.0规范中规定了定时器开始事件可以使用在最高级流程(Top-Level Process)和事件子流程中(Event Sub-Process),而不能使用在其他子流程(嵌套子流程和调用子流程)中,当前Activiti也不支持定时器事件使用在事件子流程。

消息开始事件

        为开始事件加入消息事件的定义可以让其成为消息开始事件,此时可以使用RuntimeService的startProcessByMessage方法启动流程。代码清单11-8定义了一个含有消息开始事件的流程,图11-3为流程图。

图11-3 消息开始事件

        代码清单11-8:codes\11\11.3\start-event\resource\bpmn\MessageStartEvent.bpmn

    <message id="msgA" name="msgA"></message>     <process id="myProcess" name="myProcess">         <userTask id="usertask1" name="My Task"></userTask>         <endEvent id="endevent1" name="End"></endEvent>         <startEvent id="messagestartevent1" name="Message start">             <messageEventDefinition messageRef="msgA"></messageEventDefinition>         </startEvent>         <sequenceFlow id="flow1" name="" sourceRef="messagestartevent1"             targetRef="usertask1"></sequenceFlow>         <sequenceFlow id="flow2" name="" sourceRef="usertask1"             targetRef="endevent1"></sequenceFlow>     </process> 

        代码清单11-8,定义了一个消息开始事件,其中消息事件的定义引用了“msgA”的消息,那么此时可以使用RuntimeService的startProcessByMessage方法来启动流程,需要注意的是,消息事件定义引用的是“message”元素的id,而startProcessByMessage方法传入的参数是“message”元素的name属性。

        在BPMN2.0规范中,消息表示的是流程参与者的沟通信息对象,在一般流程中,流程的各个角色的沟通信息,均会有可能导致流程的开始,流程开始事件,可以理解为另外一种启动流程的方式或者途径,使用该开始事件,即达到“接收消息”的条件后启动流程。代码清单11-9加载代码清单11-8的流程文件并启动流程。

        代码清单11-9:codes\11\11.3\start-event\src\org\crazyit\activiti\MessageStartEvent.java

        // 创建流程引擎         ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();         // 得到流程存储服务组件         RepositoryService repositoryService = engine.getRepositoryService();         // 得到运行时服务组件         RuntimeService runtimeService = engine.getRuntimeService();         // 部署流程文件         repositoryService.createDeployment()             .addClasspathResource("bpmn/MessageStartEvent.bpmn").deploy();             // 启动流程         runtimeService.startProcessInstanceByMessage("msgA");         // 查询流程         System.out.println("流程实例数量:" + runtimeService.createProcessInstanceQuery().count()); 

        运行代码清单11-9,查询到的流程实例数量为1。

错误开始事件

        BPMN2.0规定了错误开始事件只能使用在事件子流程(Event Sub-Process)中,该事件不能使用在其他的流程中,包括最高级流程(Top-Level Porcess)、嵌套子流程(Sub-Process)和调用子流程(Call Activity)。假设当前有一个检查服务器8080端口的流程,当流程启动时,会执行检查服务器的8080端口是否存在,如果不存在,则进行事件子流程,该流程对应的流程图如图11-4所示,对应的流程文件内容如代码清单11-10所示。

图11-4 含有事件子流程的流程

        代码清单11-10:codes\11\11.3\start-event\resource\bpmn\ErrorStartEvent.bpmn

    <error id="connectError" errorCode="error"></error>     <process id="errorStartProcess" name="errorStartProcess">         <startEvent id="startevent1" name="Start"></startEvent>         <subProcess id="eventsubprocess1" name="Event sub Process"             triggeredByEvent="true">             <startEvent id="errorstartevent1" name="Error start">                 <errorEventDefinition errorRef="connectError"></errorEventDefinition>             </startEvent>             <serviceTask id="usertask1" name="Sub Task"                 activiti:class="org.crazyit.activiti. HandleErrorDelegate">                 </serviceTask>             <endEvent id="endevent1" name="End"></endEvent>             <sequenceFlow id="flow2" name="" sourceRef="errorstartevent1"                 targetRef="usertask1"></sequenceFlow>             <sequenceFlow id="flow3" name="" sourceRef="usertask1"                 targetRef="endevent1"></sequenceFlow>         </subProcess>         <serviceTask id="servicetask1" name="Service Task"             activiti:class="org.crazyit.activiti.CheckServerDelegate">         </serviceTask>         <endEvent id="endevent2" name="End"></endEvent>         <sequenceFlow id="flow4" name="" sourceRef="startevent1"             targetRef="servicetask1"></sequenceFlow>         <sequenceFlow id="flow5" name="" sourceRef="servicetask1"             targetRef="endevent2"></sequenceFlow>     </process> 

        图11-4中,定义了一个普通的流程,该流程中除了开始事件和结束事件外,还有一个Service Task,该ServiceTask对应的是代码清单11-10中的粗体字代码,ServiceTask对应的是CheckServerDelegate类,该类主要用于检查服务器的8080端口是否存在,如果8080端口不存在,则抛出异常,然后错误开始事件捕获到该异常后,就会启动事件子流程。对应的CheckServerDelegate代码如代码清单11-11所示。

        代码清单11-11:codes\11\11.3\start-event\src\org\crazyit\activiti\CheckServerDelegate.java

        try {             System.out.println("开始检查8080端口");             // 连接本机的8080端口             Socket socket = new Socket("127.0.0.1", 8080);             System.out.println("检查8080端口完成");         } catch (Exception e) {             System.out.println("检查时出现异常,抛出错误");             // 连接出现异常,则抛出BpmnError,且error code为“error”             throw new org.activiti.engine.delegate.BpmnError("error");         } 

        代码清单11-11中,使用Socket连接到本机的8080端口,如果连接失败,则为抛出BpmnError,BpmnError是一个RuntimeException,该类会维护一个errorCode的属性,如果设置该属性并抛出,就会触发引用了相同errorCode的错误开始事件,如果一个错误开始事件并没有引用错误(error元素),那么将会不管抛出的errorCode是什么,都会触发该事件。

        代码清单11-10中,一个事件子流程中使用了错误开始事件,该事件引用了id为“connectError”的error元素,该error元素的errorCode为“error”,当CheckServerDelegate中抛errorCode为“error”的BpmnError时,就会触发该错误开始事件。本例中为了能看到效果,在子流程中,触发了错误开始事件后,会到达一个ServiceTask,该ServiceTask对应的类是HandleErrorDelegate(codes\11\11.3\start-event\src\org\crazyit\activiti\HandleErrorDelegate.java),该类只会输出“8080端口关闭,开始处理...”一句话。代码清单11-12加载流程文件并启动流程。

        代码清单11-12:codes\11\11.3\start-event\src\org\crazyit\activiti\ErrorStartEvent.java

        // 创建流程引擎         ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();         // 得到流程存储服务组件         RepositoryService repositoryService = engine.getRepositoryService();         // 得到运行时服务组件         RuntimeService runtimeService = engine.getRuntimeService();         // 部署流程文件         repositoryService.createDeployment()             .addClasspathResource("bpmn/ErrorStartEvent.bpmn").deploy();         // 启动流程         runtimeService.startProcessInstanceByKey("errorStartProcess"); 

        由于在本机并没有开启8080端口,因此运行代码清单11-12后,输出结果为:

开始检查8080端口 检查时出现异常,抛出错误 8080端口关闭,开始处理... 

        为了查看8080端口启动时的效果,需要将8080启动,启动方法可以使用一些web服务器或者直接使用编码方式启动,本例直接使用编启动方法,启动8080端口如代码清单11-13所示。

        代码清单11-13:codes\11\11.3\start-event\src\org\crazyit\activiti\Server8080.java

        ServerSocket serverSocket = new ServerSocket(8080);         while (true) {                     } 

        直接使用ServerSocket建立8080端口,使用代码清单11-13开启了8080端口后,此时再次运行代码清单11-12,看到运行效果下:

开始检查8080端口 检查8080端口完成 

        当检查到8080端口已经开启,并没有抛出BpmnError,因此不会触发错误启动事件,也不会进入事件子流程。本小节中关于事件子流程、嵌套子流程和调用流程的内容,请见流程与子流程一章。

本文节选自《疯狂工作流讲义(第2版)》

京东购买地址:https://item.jd.com/12246565.html

疯狂Activiti电子书:https://my.oschina.net/JavaLaw/blog/1570397

工作流Activiti教学视频:https://my.oschina.net/JavaLaw/blog/1577577

本书代码目录:https://gitee.com/yangenxiong/CrazyActiviti

本文发表于2017年12月08日 10:33
(c)注:本文转载自https://my.oschina.net/JavaLaw/blog/1586650,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2344 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1