先从工作流的启动开始讲,Activiti提供了四种工作流的启动方式
1.空启动事件
2.定时启动事件
3.异常启动事件
4.消息启动事件
空启动事件中标签内没有任何其他元素的定义
1 <startEvent id="startEvent" name="StartEvent"></startEvent>
Activity根据需求在空启动事件上进行了扩展,activiti:formKey表示与这个启动事件所关联的外置表单,activiti:initiator表示启动该流程的人员的id
1 <startEvent id ="StartEvent" name="startevent" activiti:formKey="user.form"></startEvent> 2 <startEvent id ="StartEvent" name ="startevent" activiti:initiator="user.id"></startEvent>
定时启动事件可以用于定期循环流程和一次性流程,比如企业的月报每月末汇总一次
1 <startEvent id="startEvent" name="time sart for process"> 2 <timerEventDefinition> 3 <timeCycle>R1/2018-3-31T00:00/PM1M</timeCycle> 4 </timerEventDefinition> 5 <startEvent>
异常启动事件不能被runTimeService.startProcess()调用启动,他是通过另外一个流程的异常结束事件触发,下面是通过一个scripTask来捕获异常代码为AII001的异常并输出捕获语句
1 <startEvent id ="startEvent"> 2 <errorEventDefinition erroeRef="AII001"></errorEventDefinition> 3 </startEvent> 4 <scriptTask id = "scripttask" name="scriptask" scriptFrommat="Groovy"> 5 <script><![CDATA[out:println "catch an error";]]</script> 6 </scriptTask>
消息启动事件通过一个消息名称触发从而启动一个流程实例,通常结合消息抛出事件一起使用。
1 <message id = "reSendFile" name="重新发送消息"> 2 <startEvent id = "messageStart"> 3 <messageEventDefinition messageRef="reSendFile"/> 4 </startEvent>
结束事件包括空结束事件,异常结束事件,终止结束事件,取消结束事件
空结束事件不处理抛出结果,也可以理解为抛出空
1 <endEvent id = "endEvent" name= "end Event"/>
异常结束事件定义了抛出的异常错误代码,如果定义了异常开始事件怎会根据错误代码匹配到对应的异常开始事件触发对应的流程
1 <endEvent id = "endEvent" name="end Event"> 2 <errorEventDefinition errorRef="AIA-001" /> 3 </endEvent>
终止结束事件可以终止一个流程,当一个流程因为某些原因不能继续向下进行的时候则可以将该流程的一条输出流指向终止结束事件,空结束事件结束的是一次执行,而终止结束事件结束的是整个流程。
1 <endEvent id="endEvent" name="终止结束事件"> 2 <terminateEventDefinition></terminateEventDefinition> 3 </endEvent>
取消结束事件可以取消一个事物子流程的执行,也只能在子流程中使用,当子流程出现异常需要取消时可以定义一个取消结束事件,当输出流指向一个取消结束事件是流程就会中断执行。
1 <endEvent id = "endEvent" name="cancel"> 2 <cancelEventDefinition /> 3 <endEvent>
顺序流
标准顺序流
标准顺序流是连接两个或多个模型建立关系
<sequenceFlow id = "flow" sourceRef="startEvent" targertRef="userTask"><sequenceFlow>
条件顺序流
条件顺序流是在标准顺序流上面添加条件表达式,只用通过条件才可以达到目标活动
1 <sequenceFlow id="flow" name="条件顺序流" sourceRef="startEvent" targetRef="usertask"> 2 <conditionExpression xsi:type="tFormalExpression"> 3 <![CDATA[${pass==true}]]> 4 </conditionExpression> 5 </sequenceFlow>
任务
任务是流程中比较重要的部分,根据业务需求的不同任务也可以分为很多种
1.用户任务
2.脚本任务
3.WebService任务
4.业务规则任务
5.邮件任务
6.Mule任务
7.Camel任务
8.手动任务
9.Java Service 任务
10.Shell任务
用户任务
用户任务需要人参与, Activiti在BPMN2.0的基础上的基础上对属性进行了扩展
activiti:assignee指定了任务的处理人
activiti:cadidateUsers指定了用户任务的候选人,多个用逗号隔开
activiti:cadidateGroups指定了用户任务的候选组,多个用逗号隔开
activiti:dueDate 指定了用户任务的到期日
activiti:priority 指定了用户任务的优先级
下面用户任务指定了候选组为deptLeader 并且执行任务的时候提交一个动态表单(后面会讲)
<userTask id="deptLeaderAudit" name="部门领导审批" activiti:candidateGroups="deptLeader"> <extensionElements> <activiti:formProperty id="startDate" name="请假开始日期" type="date" value="${startDate}" datePattern="yyyy-MM-dd" readable="true" writable="false"></activiti:formProperty> <activiti:formProperty id="endDate" name="请假结束日期" type="date" value="${endDAte}" datePattern="yyyy-MM-dd" readable="true" writable="false"></activiti:formProperty> <activiti:formProperty id="reason" name="请假原因" type="string" value="${reason}" readable="true" writable="false"></activiti:formProperty> <activiti:formProperty id="deptLeaderPass" name="审批意见" type="enum" required="true" writable="true"> <activiti:value id="true" name="同意"></activiti:value> <activiti:value id="false" name="不同意"></activiti:value> </activiti:formProperty> </extensionElements> </userTask>
脚本任务可以运行引擎依赖语言之外的脚本语言,activiti支持的语言包括Groovy,JavaScript,Juel,activiti扩展的属性有
scriptFormat:指定脚本所依赖的语言
resultVariable:将脚本中返回的结果保存在变量里,当然这个变量需要在脚本里定义
1 <scriptTask id="initvars" name="初始化变量" scriptFormat="groovy"> 2 <script> 3 <![CDATA[def name="铁头哥哥" ; 4 execution.setVariable("name",name);]]> 5 </script> 6 </scriptTask> 7 <scriptTask id="printvars" name="输出变量" scriptFormat="groovy"> 8 <script> 9 <![CDATA[out:println:name;]]> 10 </script> 11 </scriptTask>
JavaService Task允许定义一个实现指定接口的java类或者表达式,java类必须实现JavaDelegate,ActivityBehavior其中一个,还可以配置执行java类时所传入的变量
activiti:expression可以使用UEL定义需要执行的任务内容,例如计算公示,调用Bean的方法等
activiti:delegateExpression功能和activiti:class类似,而且同样需要实现JavaDelegate或ActivityBehavior中一个接口,只不过这里不是指定一个具体的实现类,而是运行的时候动态设置
1 <serviceTask id ="myServiceTask" name="Java Service" activiti:class="tietougege.activiti.JavaServiceDelegate"> 2 </serviceTask>
1 <serviceTask id ="myService2" name="JavaService" activiti:expression="#{leaveService.back()}"/>
1 <serviceTask id ="myService3" name="JavaService" activiti:expression="${leaveServiceDelegate}"/>
通过Web Service任务可以调用外部的Web Service 资源,通过implementation="##WebService"可以定义task为webService类型,通过ioSpecification定义元素输入输出参数
dataInputAssociation定义了属性输入关系,dataOutputAssociation定义了属性输出关系
1 <serviceTask id="checkGeneralManagerAudit" name="是否需要总经理审批" 2 implementation="##WebService" operationRef="tns:auditOperation"> 3 <ioSpecification> 4 <dataInput itemSubjectRef="tns:generalManagerAuditRequestItem" 5 id="dataInput" /> 6 <dataOutput itemSubjectRef="tns:generalManagerAuditResponseItem" 7 id="dataOutput" /> 8 <inputSet> 9 <dataInputRefs>dataInput</dataInputRefs> 10 </inputSet> 11 <outputSet> 12 <dataOutputRefs>dataOutput</dataOutputRefs> 13 </outputSet> 14 </ioSpecification> 15 <!-- 属性名称必须映射,否则报异常 https://gist.github.com/5994803 --> 16 <dataInputAssociation> 17 <sourceRef>startDate</sourceRef> 18 <targetRef>startDate</targetRef> 19 </dataInputAssociation> 20 <dataInputAssociation> 21 <sourceRef>endDate</sourceRef> 22 <targetRef>endDate</targetRef> 23 </dataInputAssociation> 24 <dataOutputAssociation> 25 <sourceRef>needed</sourceRef> 26 <targetRef>needed</targetRef> 27 </dataOutputAssociation> 28 </serviceTask>
网关
1.排他网关
2.并行网关
3.包容网关
4.事件网关
排他网关:流程执行到该网关时,按照输出流的顺序逐个计算,当条件计算结果为true时,继续执行当前网关的输出流,在排他网关中,如果多个网关的计算结果都为true,那么他只会执行第一个值为true的网关,忽略其他表达式为true的网关,如果多个网关没有为true的时,他会抛出异常
1 <excludsiveGateway id="exclusiveGateway" default="flow1"/>
1 <exclusiveGateway id="exclusivegateway5" name="Exclusive Gateway"></exclusiveGateway> 2 <sequenceFlow id="flow3" sourceRef="deptLeaderAudit" 3 targetRef="exclusivegateway5"></sequenceFlow> 4 <sequenceFlow id="flow4" name="拒绝" sourceRef="exclusivegateway5" 5 targetRef="modifyApply"> 6 <conditionExpression xsi:type="tFormalExpression"><![CDATA[${deptLeaderApproved == 'false'}]]></conditionExpression> 7 </sequenceFlow> 8 <sequenceFlow id="flow5" name="同意" sourceRef="exclusivegateway5" 9 targetRef="hrAudit"> 10 <conditionExpression xsi:type="tFormalExpression"><![CDATA[${deptLeaderApproved == 'true'}]]></conditionExpression> 11 </sequenceFlow>
并行网关:对并发的任务进行流程建模,他能把单条线路任务拆分成多个路径并执行或将多条线路合并
1 <parallelGateway id="fork" name="Parallel GateWay Fork"></parallelGateway> 2 <userTask id ="usertask1" name="部门领导审批"></userTask> 3 <userTask id="usertask2" name="人事审批"></userTask> 4 <parallelGateway id="join" name="Parallel Gateway Join"></parallelGateway> 5 <userTask id="usertask3" name="考勤归档"></userTask> 6 <endEvent id="endEvent1" name="end"></endEvent> 7 <userTask id="usertask4" name="请假申请"></userTask> 8 <sequenceFlow id="flow2" name="" sourceRef="usertask4" targetRef="fork"/> 9 <sequenceFlow id="flow3" name="" sourceRef="fork" targetRef="usertask1"/> 10 <sequenceFlow id="flow4" name="" sourceRef="fork" targetRef="usertask2"/> 11 <sequenceFlow id="flow5" name="" sourceRef="usertask1" targetRef="join"/> 12 <sequenceFlow id="flow6" name="" sourceRef="usertask2" targetRef="join"/> 13 <sequenceFlow id="flow7" name="" sourceRef="join" targetRef="usertask3"/> 14 <sequenceFlow id="flow8" name="" sourceRef="usertask3" targetRef="endevent1"/> 15 <sequenceFlow id="flow9" name="" sourceRef="startevent1" targetRef="usertask4"/>
包容网关:包容网关融合了排他网关和并行网关的特性,排他网关允许在每条线路上设置条件,并行网关可以执行多条线路,包容网关既可以同时执行多条线路又可以在网关上设置条件
第一行定义了fork类型的包容网关,第二行定义了join类型的包容网关,第九行和第十四行是两个条件顺序流
1 <inclusiveGateway id="igFork" name="Inclusive Gateway fork"></inclusiveGateway> 2 <inlcusiveGateway id="igJoin" name="Inclusive GAteway Join"></inclusiveGateway> 3 <userTask id="usertask1" name="部门领导审批"></userTask> 4 <userTask id="usertask2" name="人事审批"></userTask> 5 <userTask id="usertask3" name="考勤归档"></userTask> 6 <endEvent id ="endEvent1" name="end" ></endEvent> 7 <userTask id="usertask4" name="请假申请"></userTask> 8 <sequenceFlow id="flow2" name="" sourceRef="usertask4" targetRef="igFork"/> 9 <sequenceFlow id="flow3" name="需要部门领导审批?" sourceRef="igFork" targetRef="usertask1"/> 10 <conditionExpression xsi:type="tFormalExpression"> 11 <![CDATA[${leader==true}]]> 12 </conditionExpression> 13 <sequenceFlow> 14 <sequenceFlow id="flow4" name="需要人事审批?" sourceRef="igFork" targetRef="usertask2"> 15 <conditionExpression xsi:type="tFormalExpression"> 16 <![CDATA[${hr==true}]]> 17 </conditionExpression> 18 </sequenceFlow> 19 <sequenceFlow id="flow5" name="" sourceRef="usertask1" targetRef="igJoin"/> 20 <sequenceFlow id="flow6" name="" sourceRef="usertask2" targetRef="igJoin"/> 21 <sequenceFlow id="flow7" name="" sourceRef="igJoin" targetRef="usertask3"/> 22 <sequenceFlow id="flow8" name="" sourceRef="usertask3" targetRef="endevent1"/> 23 <sequenceFlow id ="flow9" name="" sourceRef="startevent" targetRef="usertask4"/>
事件网关:事件网关是专门为中间捕获事件设置的,它允许设置多个输出流指向多个不同的中间捕获事件(最少两个)。在流程执行到事件网关后,流程处于“等待”状态,因为中间捕获事件需要依赖中间抛出事件触发才能更改“等待”状态为“活动”状态,当然,定时捕获事件除外(他由时间驱动)
1 <signal id="alertSignal" name="alert"></signal> 2 <process id="EventGateway" name="EventGateway"> 3 <startEvent id="startevent1" name="Start"></startEvent> 4 <eventBaseGateway id="eventgateway1" name="Event Gateway"></eventBaseGateway> 5 <intermediateCatchEvent id="timeintermediatecatchevent1" name="TimeCatchEvent"> 6 <timeEventDefinition> 7 <timeDuration>PT1S</timeDuration> 8 </timeEventDefinition> 9 </intermediateCatchEvent> 10 <scriptTask id="scripttask1" name="定时器任务执行之后" scriptformat="groovy"><script><!CDATA[out:println "after time event";]]></script> 11 </scriptTask> 12 <intermediateCatchEvent id="signalintermediatecatcheevent1" name="SignalCatchEvent"> 13 <signalEventDefinition signalRef="alertSignal"> 14 </signalEventDefinition> 15 </intermediateCatchEvent> 16 <scriptTask id="scripttask2" name="信号捕获事件之后" scriptformat="groovy"><script><!CDATA[out:println "after signal event";]]></script></scriptTask> 17 <endEvent id="endEvent" name="END"></endEvent> 18 <sequenceFlow id="flow1" name="" soureRef="startevent1" targetRef="eventgateway1"> 19 <sequenceFlow id="flow2" name="" soureRef="eventgateway1" targetRef="timeintermediatecatchevent1"> 20 <sequenceFlow id="flow3" name="" soureRef="timeintermediatecatchevent1" targetRef="scripttask1"> 21 <sequenceFlow id="flow4" name="" soureRef="eventgateway1" targetRef="signalintermediatecatcheevent1"> 22 <sequenceFlow id="flow5" name="" soureRef="signalintermediatecatcheevent1" targetRef="scripttask2"> 23 <sequenceFlow id="flow6" name="" soureRef="scripttask1" targetRef="endEvent"> 24 <sequenceFlow id="flow7" name="" soureRef="scripttask2" targetRef="endEvent">
第一行定义一个信号等待中间信号捕获事件捕获,第五号定义了一个时间中间捕获事件,第12行定义了信号中间捕获事件,流程启动后两个输出流均处于等状态,等到中间捕获事件处理完成后变成活跃状态
子流程
在企业中还有一些通用的业务流程,例如,付款流程作为公司业务运作的核心流程之一,在业务设计和架构设计上会保持通用,或者在业务架构中作为一个通用的模块,不同的业务根据财务流程 的规范传入指定的参数就可以使用付款流程。
1.只能切仅能包含一个空启动流程
2.至少有一个结束流程
3.在子流程中顺序流不能直接设置输出流到子流程之外的活动中去,如果需要可以通过边界事件替代
1 <process id="subprocess" name="subprocess"> 2 <startEvent id ="startevent1" name="start"></startEvent> 3 <userTask id ="usertask1" name="下单" ></userTask> 4 <endEvent id="end" name="end"></endEvent> 5 <subProcess id ="subprocess1" name="付款子流程"> 6 <startEvent id="startEvent2" name="start"></startEvent> 7 <userTask id="usertask2" name="银行付款"></userTask> 8 <endEvent id ="endEvent1" name="End"></endEvent> 9 <serviceTask id="mailtask1" name="发送邮件" activiti:type="mail"> 10 </serviceTask> 11 <sequenceFlow id="flow1" name="" sourceRef="startEvent2" targetRef="usertask2"></sequenceFlow> 12 <sequenceFlow id="flow2" name="" sourceRef="usertask2" targetRef="mailtask1"></sequenceFlow> 13 <sequenceFlow id="flow3" name="" sourceRef="mailtask1" targetRef="endEvent1"></sequenceFlow> 14 </subProcess> 15 <sequenceFlow id="flow4" name="" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> 16 <sequenceFlow id="flow5" name="" sourceRef="usertask1" targetRef="subprocess1"></sequenceFlow> 17 <sequenceFlow id="flow6" name="" sourceRef="subprocess1" targetRef="end"></sequenceFlow> 18 </process>
调用活动:调用活动解决的问题是流程的通用性,和子流程的作用一致,但是表现方式不同,使用一个调用活动却带嵌入子流程方式的活动即可,通过创建一个调用活动模型并指定外部流程的ID方式作为主流程的一个活动。
1 <callActivity id="callactivity1" name="调用付款流程" calledElement="payment"> 2 <extensionElements> 3 <activiti: in source="amount" target="amount"></activiti:in> 4 <activiti:out source="paid" target="paid"></activiti:out> 5 <activiti:out sourceExpression="${payTime}" target="payTime"></activiti:out> 6 </extensionElements>