根据条件在多个流转路径中选择其中一条路径通过,也就是做一个决定性的判断,这时候就可以使用 decision 活动。
decision 活动可以拥有多个流出转移,当流程实例到达 decision 活动时,会根据最先匹配成功的一个条件自动地通过相应的路径。
在 decision 活动中可以使用以下三种方法来判断需要流向哪一个流出路径。
1 使用 decision 活动的 condition 元素
decision 活动中会运行并判断其中的每一个 transition 元素里的流转条件(condition元素)。当遇到一个 transition 元素的 condition 值为 true 或者是一个没有设置 condition 值的 transition 元素,这时流程就会立即转向这个 transition 元素。
decision 活动的 condition 元素属性:
属性 | 类型 | 默认值 | 是否必需 | 描述 |
---|---|---|---|---|
expr | 表达式 | 无 | 必需 | 描述转移条件的表达式 |
lang | 表达式的语言名称 | 脚本引擎配置文件(jbpm.default.scriptmanager.xml)中定义的默认表达式语言名称,默认为 jUEL,即 EL 表达式语言 | 可选 | 转移条件表达式的语言类型 |
举个例子:
流程定义如下:
<?xml version="1.0" encoding="UTF-8"?>
<process key="DecisionConditions" name="DecisionConditions" xmlns="http://jbpm.org/4.4/jpdl">
<start g="301,169,48,48" name="start1">
<transition to="exclusive1"/>
</start>
<decision g="417,165,48,48" name="exclusive1">
<transition g="441,103:" to="提交文档">
<condition expr="#{content=='good'}"/>
</transition>
<transition to="再试一次">
<condition expr="#{content=='bad'}"/>
</transition>
<transition g="443,282:" to="放弃"/>
</decision>
<state g="556,78,167,52" name="提交文档"/>
<state g="563,166,92,52" name="再试一次"/>
<state g="570,258,92,52" name="放弃"/>
</process>
测试:
Map<String,Object> variables=new HashMap<String,Object>();
variables.put("content","good");
//发起实例并传入变量
ProcessInstance processInstance = executionService.startProcessInstanceByKey
("DecisionConditions",variables);
//断言流程实例流向了 “提交文档”
assertTrue(processInstance.isActive("提交文档"));
2 使用 decision 活动的 expr 属性
可以利用 decision 活动本身的 expr(表达式)属性来决定流程的转向。decision 活动的 expr 属性值可以直接返回字符串类型的流出转移名称,来指定需要转移的路径。
decision 活动支持的属性:
属性 | 类型 | 默认值 | 是否必需 | 描述 |
---|---|---|---|---|
expr | 表达式 | 无 | 必需 | 描述转移名称的表达式 |
lang | 表达式语言名称 | 脚本引擎配置文件(jbpm.default.scriptmanager.xml)中定义的默认表达式语言名称,默认为 jUEL,即 EL 表达式语言 | 可选 | 指定转移条件表达式语言的类型 |
举个例子:
流程定义如下:
<?xml version="1.0" encoding="UTF-8"?>
<process key="DecisitonExpression" name="DecisitonExpression" xmlns="http://jbpm.org/4.4/jpdl">
<start g="309,137,48,48" name="start1">
<transition to="exclusive1"/>
</start>
<decision expr="#{content}" g="417,136,48,48" name="exclusive1">
<transition g="443,100:60,-22" name="好" to="提交文档"/>
<transition g="-9,-22" name="坏" to="再试一次"/>
<transition g="445,240:53,-22" name="糟糕" to="放弃"/>
</decision>
<state g="566,77,167,52" name="提交文档"/>
<state g="570,143,92,52" name="再试一次"/>
<state g="570,221,92,52" name="放弃"/>
</process>
测试:
Map<String,Object> variables=new HashMap<String,Object>();
variables.put("content","好");
//发起实例并传入变量
ProcessInstance processInstance = executionService.startProcessInstanceByKey
("DecisitonExpression",variables);
//断言流程实例流向了 “提交文档”
assertTrue(processInstance.isActive("提交文档"));
3 使用 decision 活动的 handler 元素
如果需要在判断流程时计算大量、复杂的业务逻辑,那么,可以自己实现判断处理接口,即通过 decision handler 的方式来实现。
首先,必须实现 DecisionHandler 接口,将流转判断的决定权委派给这个实现类。这个接口定义如下:
/** interface for supplying user programmed decisions.
*
* @author Tom Baeyens */
public interface DecisionHandler extends Serializable {
//接口定义了一个唯一的方法,提供流程实例的执行上下文(execution)作为参数,需要返回字符串型的转移名称
/** the name of the selected outgoing transition */
String decide(OpenExecution execution);
}
这个 handler 是作为 decision 活动的子元素被配置的。
这里的流程图表面上看,与 “使用 decision 活动的 expr 属性” 小节的流程图一样,但这里内部定义中使用的是 handler。
流程定义:
<?xml version="1.0" encoding="UTF-8"?>
<process key="DecisionHandler" name="DecisionHandler" xmlns="http://jbpm.org/4.4/jpdl">
<start g="309,137,48,48" name="start1">
<transition to="exclusive1"/>
</start>
<decision g="417,136,48,48" name="exclusive1">
<!-- 所有的流程判断逻辑都委托给了这个 ContentEvaluation 类统一处理-->
<handler class="net.deniro.jbpm.test.ContentEvaluation" />
<transition g="439,104:54,-23" name="好" to="提交文档"/>
<transition g="-16,-23" name="坏" to="再试一次"/>
<transition g="444,233:47,-23" name="糟糕" to="放弃"/>
</decision>
<state g="566,77,167,52" name="提交文档"/>
<state g="567,133,92,52" name="再试一次"/>
<state g="574,210,92,52" name="放弃"/>
</process>
判断处理器 ContentEvaluation:
public class ContentEvaluation implements DecisionHandler {
@Override
public String decide(OpenExecution execution) {
//获取流程变量
String content = (String) execution.getVariable("content");
if (content.equals("你很棒")) {
return "好";
}
if (content.equals("你需要努力")) {
return "坏";
}
//上述条件都不满足,就流向 ugly
return "糟糕";
}
}
测试代码:
Map<String,Object> variables=new HashMap<String,Object>();
variables.put("content","你很棒");
//发起实例并传入变量
ProcessInstance processInstance = executionService.startProcessInstanceByKey
("DecisionHandler",variables);
//断言流程实例流向了 submit document
assertTrue(processInstance.isActive("提交文档"));
decision 活动 和 state 活动都能实现条件流转,这两种方式有何区别,在实际业务应用中该选择何种方式呢?
- 如果 decision 活动定义的流转条件没有任何一个得到满足,那么流程实例将无法进行下去,会抛出异常。
- 如果 state 活动有多个流出转移,且同样没有任何一个得到满足,那么流程实例将流向 state 活动定义的第一条流出转移,从而进行下去。
因此,decision 活动具有更加严格的条件判断特性,如果不定义默认路径,则没有条件得到满足,也就会直接抛错哦O(∩_∩)O~