如下图选择Sequential(串行)或者Parallel(并行):
会根据 “变量(Multi-instance)” 设置的Key值到 “集合(Multi-instance)” 的集合中通过 “任务” 的表达式获取 assigneeList 中每个值,然后每个值单独生成一个任务数据,这样 assigneeList 中的每个用户都会受到一个待办事项,这三个需要配套使用,变量(Multi-instance) 要和 任务 保持一致。
可以为空,默认是所有人完成
nrOfInstances 实例总数
nrOfCompletedInstances 已完成多实例数目
loopCounter 已经循环的次数
nrOfActiveInstances 已经完成的实例个数
比如:只要50%的人审批完后就直接流转当前实例(${nrOfCompletedInstances/nrOfInstances >= 0.6})
@Test
public void multiInstanceTest() {
// 1、发布流程,当流程的key相同时则以版本来控制,每次启动流程实例时默认取最新版本
Deployment deployment = repositoryService.createDeployment().name("多实例会签流程").addClasspathResource("processes/multiInstance.bpmn20.xml").deploy();
Map variable = new HashMap<>();
variable.put("userList", Lists.newArrayList("张三", "李四", "王五", "赵六"));
// 2、启动一个流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("multiInstance", variable);
// 3、查询当前任务
List tasks = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();
System.out.println("当前任务数量:" + tasks.size());
for (Task task : tasks) {
System.out.println("任务名:" + task.getName() + ",任务处理人:" + task.getAssignee());
}
// 下面演示先完成一个任务,看流程是否会流转
taskService.complete(tasks.get(0).getId());
tasks = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();
System.out.println("完成一个任务后,当前任务数量:" + tasks.size());
for (Task task : tasks) {
System.out.println("任务名:" + task.getName() + ",任务处理人:" + task.getAssignee());
}
}
查看控制台输出:
当前任务数量:4
任务名:会签审批环节,任务处理人:张三
任务名:会签审批环节,任务处理人:李四
任务名:会签审批环节,任务处理人:王五
任务名:会签审批环节,任务处理人:赵六
完成一个任务后,当前任务数量:3
任务名:会签审批环节,任务处理人:李四
任务名:会签审批环节,任务处理人:王五
任务名:会签审批环节,任务处理人:赵六
当增加一个结束条件后,即 ${nrOfCompletedInstances > 0} ,xml配置变为:
当前任务数量:4
任务名:会签审批环节,任务处理人:张三
任务名:会签审批环节,任务处理人:李四
任务名:会签审批环节,任务处理人:王五
任务名:会签审批环节,任务处理人:赵六
完成一个任务后,当前任务数量:0
业务需求 : 会签人数是N个人只有所有人都审批过了才会通过,只要有一人拒绝都会驳回到上一节点。
解决逻辑 : 会签人员审批通过时正常审批,若有一人审批则通过减签的方式把其余的任务都减掉,比如会签需要四个人审批,则第一个人审批不通过,则把其余三个人通过减签的方式都去掉。
实现方式:activity监听器
代码:事件配置要选择:complete事件
package com.pactera.workflow.interceptor;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ExecutionQuery;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
//多实例任务完成事件监听器
//触发完成事件时才会触发此监听器
@Component
public class CompleteMultiTaskListner implements TaskListener, ExecutionListener {
private static RuntimeService runtimeService;
private static RepositoryService repositoryService;
@Autowired
public void setRuntimeService(RuntimeService runtimeService){
this.runtimeService=runtimeService;
}
@Autowired
public void setRepositoryService(RepositoryService repositoryService){
this.repositoryService=repositoryService;
}
@Override
public void notify(DelegateTask delegateTask) {
//获取当前的执行实例
ExecutionQuery executionQuery =runtimeService.createExecutionQuery();
ExecutionEntity executionEntity = (ExecutionEntity)executionQuery.executionId(delegateTask.getExecutionId()).singleResult();
String activityId=executionEntity.getActivityId();
//获取当前活动节点信息
FlowNode flowNode=getFlowNode(delegateTask.getProcessDefinitionId(),activityId);
//获取当前审批人的审批意向
String circulationConditions=(String) delegateTask.getVariable("circulationConditions");
//处理并行网关的多实例
if ("N".equals(circulationConditions) && flowNode.getBehavior() instanceof MultiInstanceActivityBehavior){
// ExecutionEntity executionEntity = (ExecutionEntity)runtimeService.createExecutionQuery().executionId(delegateTask.getExecutionId()).singleResult();
String parentId=executionEntity.getParentId();
//此处获得的Execution是包括所有Execution和他们的父Execution,减签的时候要先删除子的才能删除父的
List executions =runtimeService.createExecutionQuery().processInstanceId(delegateTask.getProcessInstanceId()).onlyChildExecutions().list();
System.out.println(parentId);
for (Execution execution:executions){
if (!execution.getId().equals(parentId) && !executionEntity.getId().equals(execution.getId())){
System.out.println(execution.getParentId());
runtimeService.deleteMultiInstanceExecution(execution.getId(),false);
}
}
}
}
//获取当前节点的节点信息
private FlowNode getFlowNode(String processDefinitionId, String activityId){
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
return flowNode;
}
@Override
public void notify(DelegateExecution execution) {
execution.getCurrentFlowElement();
}
}
这样,正常驳回到上一个节点。