1. 什么是完成条件 (completionCondition)?
在多实例活动(如多人会签)中,completionCondition 是一个可以配置的表达式。Flowable 在每个实例任务完成时都会对这个表达式进行求值。
如果表达式求值结果为 true,那么多实例活动就会立即结束,所有其他未完成的实例任务都会被删除,流程继续向下流转。
如果表达式求值结果为 false,流程会继续等待其他实例任务的完成。
如果所有实例任务都已完成,但该条件从未为 true,那么多实例活动也会正常结束。
2. "动态"体现在哪里?
“动态”的核心在于,这个表达式不仅能使用 Flowable 内置的循环变量,还能访问流程实例的所有自定义流程变量(Process Variables)。
这意味着你可以根据业务逻辑,在任务处理过程中动态地改变流程变量的值,从而影响最终的完成条件判断。
3. 可在表达式中使用的变量
a. 内置循环变量
Flowable 在多实例活动期间会自动维护一组非常有用的只读变量,你可以直接在表达式中使用它们。
变量名 类型 描述
nrOfInstances Integer 总实例数。即会签的总人数。等于你提供的集合的大小。
nrOfCompletedInstances Integer 已完成的实例数。每次有审批人完成任务,此值加一。
nrOfActiveInstances Integer 当前活动的实例数。即尚未完成任务的人数。
loopCounter Integer 循环计数器。一个从0开始的索引,表示当前是第几次循环。在并行会签中意义不大,但在串行会签中非常有用。
b. 自定义流程变量
你可以定义任何你需要的变量,并在任务完成时去更新它。这是实现复杂逻辑的关键。例如:
voteResult (String): 存储每次投票的结果(如 ‘agree’, ‘reject’)。
rejectionCount (Integer): 专门用于统计“拒绝”票数的计数器。
approvedCount (Integer): 专门用于统计“同意”票数的计数器。
4. 经典场景与表达式示例
场景一:比例通过(例如,超过60%的人同意即通过)
这是最简单的动态场景,仅使用内置变量即可。
逻辑:已完成人数占总人数的比例达到或超过0.6。
<userTask id="countersignTask" name="会签" ...>
<multiInstanceLoopCharacteristics isSequential="false" flowable:collection="userList">
...
<completionCondition>
${nrOfCompletedInstances / nrOfInstances >= 0.6}
</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
注意:这种方式无法区分同意和拒绝,它只关心“完成”的数量。要实现精确的“同意”比例,需要引入自定义变量。
场景二:一票否决(One-vote Veto)
这是最经典的自定义变量场景。只要有一个人选择“拒绝”,整个会签环节就立即结束并标记为不通过。
逻辑:会签结束的条件是:
有人投了拒绝票。或者
所有人都投了票(并且没有人投拒绝票,即正常完成)。
BPMN配置:
<userTask id="vetoTask" name="一票否决会签" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false" flowable:collection="userList">
<flowable:elementVariable>assignee</flowable:elementVariable>
<completionCondition>
<!-- 如果拒绝票数大于0,或者所有人都完成了审批,则结束 -->
${rejectionCount > 0 || nrOfCompletedInstances == nrOfInstances}
</completionCondition>
</multiInstanceLoopCharacteristics>
<!-- 关键:需要一个任务监听器来更新 rejectionCount -->
<flowable:taskListener event="complete" class="com.example.VoteListener" />
</userTask>
实现步骤:
初始化变量:在进入此会签节点前,需要初始化一个流程变量 rejectionCount 为0。
创建任务监听器 (TaskListener): 这是核心。监听器会在每个任务完成时被触发,检查审批结果并更新 rejectionCount。
import org.flowable.engine.delegate.DelegateTask;
import org.flowable.engine.delegate.TaskListener;
public class VoteListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
// 从任务的本地变量或表单中获取审批结果
// 假设用户完成任务时,会提交一个名为 "approved" 的变量 (true/false)
Boolean approved = (Boolean) delegateTask.getVariable("approved");
if (approved != null && !approved) { // 如果是拒绝
// 1. 从执行域获取当前的拒绝票数
Object countObj = delegateTask.getExecution().getVariable("rejectionCount");
int currentCount = (countObj == null) ? 0 : (Integer) countObj;
// 2. 票数加一,并设置回流程变量中
delegateTask.getExecution().setVariable("rejectionCount", currentCount + 1);
}
}
}
当第一个人选择拒绝时,rejectionCount 变为1,Flowable在任务完成后检查 ,发现 ${rejectionCount > 0} 为 true,会签立即结束。