说说 jBPM 流程定义语言(8)—— sub-process(子流程活动)

当我们的流程复杂到一定程度时,就需要按照一定规则把业务拆分成若干子流程,这样业务模块之间才能明晰易于划分。

jBPM4 提供了 sub-process – 子流程活动,这可以在 “ 主干流程 ” 定义中调用其他的流程定义,从而 “ 组装 ” 我们的流程定义 。在运行到子流程活动时,工作流引擎将创建一个子流程实例,然后等待直到完成,当子流程实例完成后,流程就会流向下一个节点。

sub-process 活动的属性:

属性 类型 默认值 是否必需 描述
sub-process-id 字符串 sub-process-id 与 sub_process-key,必需其一 流程定义的 ID 标识,可以通过一个流程的 ID 去引用此流程定义的指定版本 。
sub-process-key 字符串 sub-process-id 与 sub_process-key,必需其一 流程 key 标识,通过 key 去引用流程定义,也就意味着引用了该流程定义的最新版本 。 注意,该流程定义的最新版本会在每次活动实例执行时计算得出 。
outcome 表达式 当 sub-process 活动的 transition 元素具有 outcome-value 时必需 当子流程活动执行结束时执行的表达式 。 表达式值用来匹配流出转移中的 outcome-value 元素值,起到选择 sub-process 活动下一步流向的作用 。

sub-process 活动的元素:

元素 聚合关系 描述
parameter-in 0..* 子流程输入参数。即声明一个变量,在创建子流程实例时传入。
parameter-out 0..* 子流程输出参数。即声明一个变量,在子流程实例结束时,返回父流程实例。

sub-process 的 parameter-in – 子流程活动输入元素的属性:

属性 类型 默认值 是否必需 描述
subvar 字符串 必需 被赋值的子流程变量的名称。
var 字符串 var 与 expr 必需二选一 从父流程中输入的变量名称。
expr 字符串 var 与 expr 必需二选一 此表达式会在父流程中被解析,结果值会被输入到对应的子流程变量中。
lang 字符串 EL 表达式 可选 表达式使用的脚本语言。

sub-process 的 parameter-out – 子流程活动输出元素的属性:

属性 类型 默认值 是否必需 描述
var 字符串 必需 输出的目标 – 父流程中的变量名称。
subvar 字符串 subvar 与 expr 必需二选一 子流程中需要被输出的变量名称。
expr 字符串 subvar 与 expr 必需二选一 此表达式会在子流程中被解析,结果会被传入到对应的父流程变量中。
lang 字符串 EL 表达式 可选 表达式使用的脚本语言。

sub-process 活动的 outcome 元素必须有与之相呼应的 outcome-value 元素,这个 outcome-value 元素被定义在子流程活动的流出转移( transition )中 。

sub-process transition 的 outcome-value 元素:

元素 聚合关系 描述
outcome-value 0..1 它是一个值表达式 。 子流程活动结束时,如果子流程中某个转移的 outcome-value 值与子流程的 outcome 值相匹配,那么,父流程会通过此转移 。 注意:这个 outcome-value 值是在 transition 元素中定义的 。

1 流程变量

父子流程是通过流程变量来传递数据的:父流程在子流程启动把值输入,子流程结束时把值输出。

假设有这样一个场景,父流程中的一个节点是审查,而这个节点是通过子流程实现的:

jPDL:



<process key="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl">
   <start g="211,136,48,48" name="start1">
      <transition to="审核"/>
   start>
   <sub-process g="315,135,92,52" name="审核" sub-process-key="SubProcessReview">
            
        <parameter-in subvar="document" var="document"/>
           
        <parameter-out subvar="result" var="reviewResult"/>
      <transition to="等待"/>
   sub-process>
   <state g="467,137,92,52" name="等待"/>
process>

这里引用了下面定义的子流程:

在实际的业务中,存在着各种各样的子流程,它们会被其他流程所引用。
jPDL:



<process name="SubProcessReview" xmlns="http://jbpm.org/4.4/jpdl">
   <start g="269,233,48,48" name="start1">
      <transition to="同意"/>
   start>
   <task assignee="deniro" g="384,232,107,52" name="同意">
      <transition to="end1"/>
   task>
   <end g="548,236,48,48" name="end1"/>
process>

测试代码:

//创建变量,并设置
Map<String, Object> variables = new HashMap<>();
variables.put("document", "This document");

//带父变量发起流程实例
ProcessInstance processInstance = executionService.startProcessInstanceByKey
        ("SubProcessDocument", variables);

//获取用户任务列表
List<Task> taskList = taskService.findPersonalTasks("deniro");
Task task = taskList.get(0);

//获取任务变量(来自父流程)
String document = (String) taskService.getVariable(task.getId(), "document");
assertEquals("This document", document);

//在子流程任务上设置新变量 result(实践一般来自于用户填写的表单)
variables = new HashMap<>();
variables.put("result", "accept");

// result 作为子流程变量返回给父流程实例
taskService.setVariables(task.getId(), variables);
taskService.completeTask(task.getId());//完成任务,结束子流程实例

processInstance = executionService.findProcessInstanceById(processInstance.getId());

//断言父流程已完成子流程活动,并到达了 wait 节点
assertNotNull(processInstance.findActiveExecutionIn("等待"));

//验证父流程的 reviewResult 变量值(它是子流程的输出结果)
String result = (String) executionService.getVariable(processInstance.getId(),
        "reviewResult");
assertEquals("accept", result);

注意:如果是在 eclipse 中使用 jBPM 的插件来生成的 jPDL ,jPDL 会默认生成 sub-process-id,这样就无法通过 id 来得到子流程的定义信息(因为我们在子流程中没有定义 ID,用的是 sub-process-key)。

2 决定父流程流出转移(使用 outcome 属性)

现在,我们使用 sub-process 活动的 outcome 属性来决定父流程的流出转移。

jPDL:



<process name="SubProcessDocument2" xmlns="http://jbpm.org/4.4/jpdl">
   <start name="start1" g="113,224,48,48">
      <transition to="审查"/>
   start>

   
   <sub-process name="审查" sub-process-key="SubProcessReview" outcome="#{result}"
                g="226,220,92,52">
      
      <transition name="同意" to="下一步" g="275,173:28,-27"/>
      <transition name="需要完善" to="更新" g="-16,-22"/>
      <transition name="拒绝" to="关闭" g="274,313:28,-21"/>
   sub-process>
   <state name="下一步" g="384,148,92,52"/>
   <state name="更新" g="387,221,92,52"/>
   <state name="关闭" g="388,289,92,52"/>
process>

子流程定义与之前的定义相同:

测试代码:

//带父变量发起流程实例
ProcessInstance processInstance = executionService.startProcessInstanceByKey
        ("SubProcessDocument2");

//获取用户任务列表
List taskList = taskService.findPersonalTasks("deniro");
Task task = taskList.get(0);

//在子流程任务上设置新变量 result,这个值会被传递给 outcome 属性以决定父流程的走向
Map variables = new HashMap<>();
variables.put("result", "同意");

// result 作为子流程变量返回给父流程实例
taskService.setVariables(task.getId(), variables);
taskService.completeTask(task.getId());//完成任务,结束子流程实例

processInstance = executionService.findProcessInstanceById(processInstance.getId());

//断言父流程已完成子流程活动,并到达了“下一步”节点
assertNotNull(processInstance.findActiveExecutionIn("下一步"));

3 决定父流程流出转移(使用子流程的 end 活动)

这种方法比 outcome 属性更容易理解。因为一个流程可以定义多个 end 活动,那么我们可以为子流程定义多个不同名称的 end 活动,这些 end 活动名称会自动与父流程的流出转移名称做同名关联。

父流程的定义与上一个父流程定义相比,仅少了 outcome 属性:

jPDL:



<process name="SubProcessDocument3" xmlns="http://jbpm.org/4.4/jpdl">
   <start name="start1" g="113,224,48,48">
      <transition to="审查"/>
   start>
   <sub-process name="审查" sub-process-key="SubProcessReview2" g="226,220,92,52">
      <transition name="同意" to="下一步" g="275,173:28,-27"/>
      <transition name="需要完善" to="更新" g="-16,-22"/>
      <transition name="拒绝" to="关闭" g="274,313:28,-21"/>
   sub-process>
   <state name="下一步" g="384,148,92,52"/>
   <state name="更新" g="387,221,92,52"/>
   <state name="关闭" g="388,289,92,52"/>
process>

jPDL:



<process name="SubProcessReview2" xmlns="http://jbpm.org/4.4/jpdl">
   <start g="269,233,48,48" name="start1">
      <transition to="同意"/>
   start>
   <task assignee="deniro" g="384,232,107,52" name="同意">
      <transition to="end1" name="需要完善" g="-23,-22"/>
      <transition name="同意" to="end2" g="439,178:38,-22"/>
      <transition name="拒绝" to="end3" g="442,339:30,-26"/>
   task>
   <end g="548,236,48,48" name="end1"/>
   <end name="end2" g="550,154,48,48"/>
   <end name="end3" g="546,315,48,48"/>
process>

测试代码:

//带父变量发起流程实例
ProcessInstance processInstance = executionService.startProcessInstanceByKey
        ("SubProcessDocument3");

//获取用户任务列表
List taskList = taskService.findPersonalTasks("deniro");
Task task = taskList.get(0);

// 让任务流向 “同意”转移
taskService.completeTask(task.getId(),"同意");//完成任务,结束子流程实例

processInstance = executionService.findProcessInstanceById(processInstance.getId());

//断言父流程已完成子流程活动,并到达了“下一步”节点
assertNotNull(processInstance.findActiveExecutionIn("下一步"));

你可能感兴趣的:(jBPM)