【JBPM4的子流程与父流程的设计及开发】
子流程与父流程的支持一般都要解决子流程的定义、父流程与子流程的关系定义。在 Jbpm4 中,子流程其也认为是一种独立的流程,这样的话,所以子流程与父流程的定义就不存在问题,但他们的关系如何休现, jbpm4的流程定义是通过xml文件来设定的,所以没有所谓的数据库外键关系,它却是在流程定义中,通过一个 <sub-process key=” 子流程的 key”/>节点来体现父与子流程之间的关系的。
JBPM4 的对子流程的支持也已经很完善了,但用起来感觉还不够方便,主要面临以下几个问题:
1. 子流程完成后,如何跳回主流程
2. 子流程的人员如何指派
3. 子流程与父流程如何传递数据
我们以下面两个流程为示例,其中仓库检验订单子流程也是这个父流程的一个节点,我们在流程设计器上则通过绑定其 key ,如 :
jbpm4 父流程设置子流程节点则需要设置Key,其子流程的定义如:
jbpm 在启动父流程运行后,当跳至下一步为子流程,其就会自动启动子流程,这个动作,在我们的 jbpmserviceimpl 类中有,完成当前任务并且跳至下一步时,我们会取到下一任务的执行人员,并且进行了授权。但当完成子流程时,需要跳至父流程,流程引擎则需要知道其跳转的 路径。
JBPM4 提供了三种方式来进行返回至父流程:
方法一(我们称之为输入活动节点)
父流程示意图:
其子流程示意图如:
对应的流程定义XML文件:
子流程:
<?xml version="1.0" encoding="UTF-8"?>
<process name="SubProcessReview" xmlns="http://jbpm.org/4.4/jpdl">
<start g="25,101,48,48">
<transition to="get approval"/>
</start>
<task name="get approval"
assignee="johndoe"
g="107,97,127,52">
<transition name="ok" to="ok" g="171,71:9,-16"/>
<transition name="nok" to="nok" g="-16,-16"/>
<transition name="reject" to="reject" g="170,179:8,3"/>
</task>
<end name="ok" g="269,48,88,52" />
<end name="nok" g="270,101,88,52" />
<end name="reject" g="270,156,88,52"/>
</process>
父流程:
<?xml version="1.0" encoding="UTF-8"?>
<process name="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl">
<start g="43,109,48,48">
<transition to="review" />
</start>
<sub-process name="review"
sub-process-key="SubProcessReview"
g="118,106,99,52">
<transition name="ok" to="next step" g="167,67:6,-19"/>
<transition name="nok" to="update" g="-22,-18"/>
<transition name="reject" to="close" g="167,200:7,3"/>
</sub-process>
<state name="next step" g="255,41,88,52"/>
<state name="update" g="256,106,88,52"/>
<state name="close" g="258,175,88,52"/>
</process>
我们发现子流程的跳至结束的 transition 名则为父流程中的子流程节点的跳出分支路径,这样,完成子流程任务的调用则为如下方式:
taskService.completeTask(task.getId(), "ok");
说明:这种方法要求我们的子流程跳出分支与外面的父流程中的子流程任务的跳出分支一致。
方法二(我们称之为输出对象)
子流程则如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<process name="SubProcessReview" xmlns="http://jbpm.org/4.4/jpdl">
<start g="20,20,48,48">
<transition to="get approval"/>
</start>
<task name="get approval"
assignee="johndoe"
g="96,16,127,52">
<transition to="end"/>
</task>
<end name="end" g="254,19,88,52" />
</process>
父流程定义:
<?xml version="1.0" encoding="UTF-8"?>
<process name="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl">
<start g="36,109,48,48">
<transition to="review" />
</start>
<sub-process name="review"
sub-process-key="SubProcessReview"
outcome="#{result}"
g="118,106,99,52">
<transition name="ok" to="next step" g="167,67:6,-19">
<outcome-value>
<int value="100"/>
</outcome-value>
</transition>
<transition name="nok" to="update" g="-22,-18">
<outcome-value>
<int value="200"/>
</outcome-value>
</transition>
<transition name="reject" to="close" g="167,200:7,3">
<outcome-value>
<int value="300"/>
</outcome-value>
</transition>
</sub-process>
<state name="next step" g="255,41,88,52"/>
<state name="update" g="256,106,88,52"/>
<state name="close" g="258,175,88,52"/>
</process>
其完成子流程任务调用方式:
// the result variable is set in the task
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("result", 100);
taskService.setVariables(task.getId(), variables);
// the task in the sub process instance is completed
taskService.completeTask(task.getId());
说明:这里则告诉我们,在完成子任务的时候,则是通过在子任务中完成的时候,加上结果的变量,父流程则在定义中通过结果的变量,以决定其跳至下一哪个节点。
这种方案则要求我们父流程定义需要进行变量参数判定,并且在子流程中加上变量参数值,以通过该方式来进行跳转。
方法三:我们称之为 ( 输出值 )
与方法二有点不尽相同,其父流程中的子流程那里的跳转没有加参数,其父定义如下:
<?xml version="1.0" encoding="UTF-8"?>
<process name="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl">
<start g="36,109,48,48">
<transition to="review" />
</start>
<sub-process name="review"
sub-process-key="SubProcessReview"
outcome="#{result}"
g="118,106,99,52">
<transition name="ok" to="next step" g="167,67:6,-19"/>
<transition name="nok" to="update" g="-22,-18"/>
<transition name="reject" to="close" g="167,200:7,3"/>
</sub-process>
<state name="next step" g="255,41,88,52"/>
<state name="update" g="256,106,88,52"/>
<state name="close" g="258,175,88,52"/>
</process>
其子流程任务的完成调用如下:
// the result variable is set in the task
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("result", "ok");
taskService.setVariables(task.getId(), variables);
// the task in the sub process instance is completed
taskService.completeTask(task.getId());
说明:这里调用返回的变量值则为父流程中了子流程节点的跳出分支。父流程的定义也相对简单了,假若我们子流程的跳出至父流程的分支由用户自己来选择的话,则方法三 是一种非常理想的做法。相对方法一来说,其又不需要在子流程的结束分支需要搞得跟父流程的子流程节点跳出分支一样。若需要在子流程表单中,根据业务表单的 计算情况,自动跳到父流程的相应节点上,则可以选择方法二。
在 J.Office2 中,我们则选择第三种方法,让用户自己选择跳转分支路径。我们把在子流程中的最后一步,准备跳到结束节点时,让用户自己去选择在父流程中分支跳转路径,并 且把用户选择的路径保存至流程变量中,流程引擎则自己帮我们实现跳转功能,因此,一切问题都迎刃而解。
下面我们来看一下,如何解决在子流程取到其在父流程中的跳转分支路径,我们通过子流程的任务 id 来获取,方法示例如:
/**
* 通过子流程的任务实例id,取得子流程在父流程的跳转分支
* @param subFlowTaskId 子流程的任务id
* @return
*/
public List<Transition> getTransitionsBySubFlowTaskId(String subFlowTaskId){
TaskImpl taskImpl = (TaskImpl) taskService.getTask(subFlowTaskId);
if(taskImpl.getExecution().getSuperProcessExecution()!=null){
ExecutionImpl parentPi=taskImpl.getExecution().getSuperProcessExecution();
EnvironmentFactory environmentFactory = (EnvironmentFactory) processEngine;
EnvironmentImpl env = environmentFactory.openEnvironment();
try {
if (parentPi.getActivity() != null) {
List outTrans=parentPi.getActivity().getOutgoingTransitions();
return outTrans;
}
} finally {
env.close();
}
}
return new ArrayList();
}
当我们在执行子流程时,我们看到如下的示意图:
在子流程中的任务表单中,则可以选择跳回父流程的分支。
那么子流程与父流程中的是如何传递参数?
其还是采用流程变量方式,也则是在子流程变量中设置的流程变量,在父流程还是可以取到,只不过是需要设置输出至父流程。
如子流程定义为:
<?xml version="1.0" encoding="UTF-8"?>
<process name="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl">
<start g="20,20,48,48">
<transition to="review" />
</start>
<sub-process name="review"
sub-process-key="SubProcessReview"
g="96,16,127,52">
<parameter-in var="document" subvar="document" />
<parameter-out var="reviewResult" subvar="result" />
<transition to="wait" />
</sub-process>
<state name="wait" g="255,16,88,52"/>
</process>
在子流程设置变量为名为 result ,其父流程则通过取名为 reviewResult 可以取到对应值。
调用如:
String result = (String) executionService.getVariable(processInstance.getId(), "reviewResult");
整个实现效果演示可以参考:
http://www.jee-soft.cn/demoDetail.htm?demoId=5&decorator=blank