BPMN学习第二 步:请假流程图

  在前面简单流程图基础上, 我们引入网关学习稍微复杂一点的请假流程图,设计请假流程,一般人会用通常思考方式设计:

  1. 提出请假
  2. 经理审核

可能会设计两个用户任务,一个用户任务是员工提出请假,一个用户任务是经理审核,其实这是一种粗粒度的设计,因为没有将BPMN的元素引入其中,BPMN的开始事件表示流程启动了,那么可以用启动事件直接表达提出的请假,没有必要再设计请假用户任务;其次,经理审核是需要用户任务UserTask完成,但是这里有两个结果,同意或不同意,不同处理结果导致流程不同,因此需要用流程把这个细节从背后明确地表达出来,这里就使用到BPMN的专用网关了。

 

这里如果经理批准请假,建立了一个发邮件的任务,给申请者发送邮件,而如果不同意,则修改请假的内容然后打回重新审核。

这个流程的XML比如复杂一些,但是了解了BPMN几大元素以后,无外乎就是由任务 事件和网关三种元素组成,就像人由男人和女人组成一样:

<process id="vacationRequest" name="vacationRequest" isExecutable="true">
<startEvent id="startEvent" name="请假" activiti:initiator="employeeName" activiti:formKey="vaform">

</startEvent>
<userTask id="handle_vacation_request" name="审核请假" activiti:assignee="$INITIATOR" activiti:formKey="review">
<documentation>======= ${reason}</documentation>

</userTask>
<exclusiveGateway id="sid-12A577AE-5227-4918-8DE1-DC077D70967C"></exclusiveGateway>
<userTask id="modify_vacation_request" name="修改请假请求" activiti:assignee="$INITIATOR" activiti:formKey="modifyRequest">
<documentation>---- ${reason}</documentation>

</userTask>
<sequenceFlow id="flow1" name="flow1" sourceRef="startEvent" targetRef="handle_vacation_request"></sequenceFlow>
<sequenceFlow id="flow2" name="flow2" sourceRef="handle_vacation_request" targetRef="sid-12A577AE-5227-4918-8DE1-DC077D70967C"></sequenceFlow>
<endEvent id="EndEvent" name="请求结束"></endEvent>
<sequenceFlow id="flow4" name="拒绝" sourceRef="sid-12A577AE-5227-4918-8DE1-DC077D70967C" targetRef="modify_vacation_request">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${form_review_outcome== 'reject'}]]></conditionExpression>
</sequenceFlow>
<serviceTask id="sendmail" name="发送email" activiti:async="true" activiti:type="mail">

</serviceTask>
<sequenceFlow id="flow7" name="flow7" sourceRef="sendmail" targetRef="EndEvent"></sequenceFlow>
<sequenceFlow id="flow3" name="批准" sourceRef="sid-12A577AE-5227-4918-8DE1-DC077D70967C" targetRef="sendmail">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${form_review_outcome== 'agree'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow6" name="Don't Resend" sourceRef="modify_vacation_request" targetRef="EndEvent">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${resubmit == "false"}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow5" name="重发申请" sourceRef="modify_vacation_request" targetRef="handle_vacation_request">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${resubmit == "true"}]]></conditionExpression>
</sequenceFlow>
</process>

这里用到了在节点之间共享数据的方式,比如${reason}这是一个类似JSP的EL(Expression Language)表示法,就是引用变量名为reason的值,而reason="xxxx"这对键值是之前节点,也就是starEnd时输入的,如何输入呢?这里activiti:formKey="vaform">,也就是通过一个表单varform输入的,如果你自己实现表单系统,需要将表单输入的变量名和值以键值放入流程变量中,以Activiti为例使用setVariable方法设置进去就可以了。

数据对象如何和流程节点结合是不同流程引擎的不同做法。

四眼原则

工作流与BPM