版本:Flowable 6.7.0
配置完成条件
会签:${nrOfCompletedInstances==nrOfInstances}
或签:${nrOfCompletedInstances>=1}
固定集合、变量参数为approverList、approver
自定义多实例并行行为解析类
package com.twqc.modules.lowcode.bpm.framework.flowable.core.behavior;
import com.twqc.common.system.api.ISysBaseAPI;
import com.twqc.common.util.CollectionUtils;
import com.twqc.modules.lowcode.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
import com.twqc.modules.lowcode.bpm.service.definition.BpmTaskAssignRuleService;
import com.twqc.modules.lowcode.bpm.service.definition.BpmUserGroupService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Activity;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import java.util.*;
/**
* 多实例并行行为解析类
*
* @author wsl
* @date 2023/5/4
*/
@Slf4j
public class MultiInstanceParallelBehavior extends ParallelMultiInstanceBehavior {
@Setter
private BpmTaskAssignRuleService bpmTaskRuleService;
@Setter
private BpmUserGroupService userGroupService;
@Setter
private ISysBaseAPI iSysBaseAPI;
@Setter
private BpmTaskAssignUsersResolve bpmTaskAssignUsersResolve;
/**
* 任务分配脚本
*/
private Map scriptMap = Collections.emptyMap();
public void setScripts(List scripts) {
this.scriptMap = CollectionUtils.convertMap(scripts, script -> script.getEnum().getId());
}
public MultiInstanceParallelBehavior(Activity activity, AbstractBpmnActivityBehavior originalActivityBehavior) {
super(activity, originalActivityBehavior);
}
@Override
protected int createInstances(DelegateExecution multiInstanceRootExecution) {
log.info("MultiInstanceParallelBehavior.createInstances start");
// 获取当前节点的候选执行人
List userList = new ArrayList<>();
HandleAssignmentsCommon handleAssignmentsCommon = new HandleAssignmentsCommon();
handleAssignmentsCommon.setBpmTaskRuleService(bpmTaskRuleService);
handleAssignmentsCommon.setUserGroupService(userGroupService);
handleAssignmentsCommon.setISysBaseAPI(iSysBaseAPI);
handleAssignmentsCommon.setScripts(scriptMap);
handleAssignmentsCommon.setBpmTaskAssignUsersResolve(bpmTaskAssignUsersResolve);
Set candidateUsers = handleAssignmentsCommon.calculateTaskCandidateUsers(multiInstanceRootExecution.getProcessDefinitionId(), multiInstanceRootExecution.getCurrentActivityId(), multiInstanceRootExecution.getId(), multiInstanceRootExecution.getProcessInstanceId());
candidateUsers.forEach(user -> {
userList.add(user);
});
// 设置候选执行人
multiInstanceRootExecution.setVariable("approverList", userList);
setLoopVariable(multiInstanceRootExecution, NUMBER_OF_INSTANCES, userList.size());
setLoopVariable(multiInstanceRootExecution, NUMBER_OF_ACTIVE_INSTANCES, userList.size());
return super.createInstances(multiInstanceRootExecution);
}
}
自定义多实例串行行为解析类
package com.twqc.modules.lowcode.bpm.framework.flowable.core.behavior;
import com.twqc.common.system.api.ISysBaseAPI;
import com.twqc.common.util.CollectionUtils;
import com.twqc.modules.lowcode.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
import com.twqc.modules.lowcode.bpm.service.definition.BpmTaskAssignRuleService;
import com.twqc.modules.lowcode.bpm.service.definition.BpmUserGroupService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Activity;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import java.util.*;
/**
* 多实例串行行为解析类
*
* @author wsl
* @date 2023/5/4
*/
@Slf4j
public class MultiInstanceSequentialBehavior extends SequentialMultiInstanceBehavior {
@Setter
private BpmTaskAssignRuleService bpmTaskRuleService;
@Setter
private BpmUserGroupService userGroupService;
@Setter
private ISysBaseAPI iSysBaseAPI;
@Setter
private BpmTaskAssignUsersResolve bpmTaskAssignUsersResolve;
/**
* 任务分配脚本
*/
private Map scriptMap = Collections.emptyMap();
public void setScripts(List scripts) {
this.scriptMap = CollectionUtils.convertMap(scripts, script -> script.getEnum().getId());
}
public MultiInstanceSequentialBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) {
super(activity, innerActivityBehavior);
}
@Override
protected int createInstances(DelegateExecution multiInstanceRootExecution) {
log.info("MultiInstanceSequentialBehavior.createInstances start");
// 获取当前节点的候选执行人,此处自行替换为获取候选用户逻辑
List userList = new ArrayList<>();
HandleAssignmentsCommon handleAssignmentsCommon = new HandleAssignmentsCommon();
handleAssignmentsCommon.setBpmTaskRuleService(bpmTaskRuleService);
handleAssignmentsCommon.setUserGroupService(userGroupService);
handleAssignmentsCommon.setISysBaseAPI(iSysBaseAPI);
handleAssignmentsCommon.setBpmTaskAssignUsersResolve(bpmTaskAssignUsersResolve);
handleAssignmentsCommon.setScripts(scriptMap);
Set candidateUsers = handleAssignmentsCommon.calculateTaskCandidateUsers(multiInstanceRootExecution.getProcessDefinitionId(), multiInstanceRootExecution.getCurrentActivityId(), multiInstanceRootExecution.getId(), multiInstanceRootExecution.getProcessInstanceId());
candidateUsers.forEach(user -> {
userList.add(user);
});
// 设置候选执行人
multiInstanceRootExecution.setVariable("approverList", userList);
setLoopVariable(multiInstanceRootExecution, NUMBER_OF_INSTANCES, userList.size());
setLoopVariable(multiInstanceRootExecution, NUMBER_OF_ACTIVE_INSTANCES, userList.size());
return super.createInstances(multiInstanceRootExecution);
}
}
工厂实现类
package com.twqc.modules.lowcode.bpm.framework.flowable.core.behavior;
import com.twqc.common.system.api.ISysBaseAPI;
import com.twqc.modules.lowcode.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
import com.twqc.modules.lowcode.bpm.service.definition.BpmTaskAssignRuleService;
import com.twqc.modules.lowcode.bpm.service.definition.BpmUserGroupService;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import lombok.ToString;
import org.flowable.bpmn.model.Activity;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.impl.el.ExpressionManager;
import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory;
import java.util.List;
/**
* 自定义的 ActivityBehaviorFactory 实现类,目的如下:
* 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配
*
* @author YT
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
@Setter
private BpmTaskAssignRuleService bpmTaskRuleService;
@Setter
private BpmUserGroupService userGroupService;
@Setter
private ISysBaseAPI iSysBaseAPI;
@Setter
private List scripts;
@Setter
private BpmTaskAssignUsersResolve bpmTaskAssignUsersResolve;
private ExpressionManager expressionManager;
/**
* 重写父类的方法,自定义串行多实例行为,用于控制顺序(串行)多实例任务的执行逻辑。
*
* @param activity
* @param innerActivityBehavior
* @return
*/
@Override
public SequentialMultiInstanceBehavior createSequentialMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) {
MultiInstanceSequentialBehavior multiInstanceSequentialBehavior = new MultiInstanceSequentialBehavior(activity, innerActivityBehavior);
multiInstanceSequentialBehavior.setBpmTaskRuleService(bpmTaskRuleService);
multiInstanceSequentialBehavior.setISysBaseAPI(iSysBaseAPI);
multiInstanceSequentialBehavior.setUserGroupService(userGroupService);
multiInstanceSequentialBehavior.setScripts(scripts);
multiInstanceSequentialBehavior.setBpmTaskAssignUsersResolve(bpmTaskAssignUsersResolve);
return multiInstanceSequentialBehavior;
}
/**
* 重写父类的方法,自定义并行多实例行为,用于控制并行多实例任务的执行逻辑。
*
* @param activity
* @param innerActivityBehavior
* @return
*/
@Override
public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) {
MultiInstanceParallelBehavior multiInstanceParallelBehavior = new MultiInstanceParallelBehavior(activity, innerActivityBehavior);
multiInstanceParallelBehavior.setBpmTaskRuleService(bpmTaskRuleService);
multiInstanceParallelBehavior.setISysBaseAPI(iSysBaseAPI);
multiInstanceParallelBehavior.setUserGroupService(userGroupService);
multiInstanceParallelBehavior.setScripts(scripts);
multiInstanceParallelBehavior.setBpmTaskAssignUsersResolve(bpmTaskAssignUsersResolve);
return multiInstanceParallelBehavior;
}
}
多实例任务监听器
package com.twqc.modules.lowcode.bpm.framework.flowable.core.listener;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.common.engine.impl.event.FlowableEntityEventImpl;
import org.flowable.engine.ProcessEngines;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Component;
/**
* 多任务监听,用于设置审批人
* 配置在多人任务节点的任务监听器中
*
* @author wangsl
*/
@Component
@Slf4j
public class BpmMultiInstanceTaskListener implements FlowableEventListener {
@Override
public void onEvent(FlowableEvent event) {
// 判断是否为任务创建事件
if (FlowableEngineEventType.TASK_CREATED.equals(event.getType())) {
if (event instanceof FlowableEntityEventImpl) {
FlowableEntityEventImpl entityEvent = (FlowableEntityEventImpl) event;
Object entity = entityEvent.getEntity();
if (entity instanceof TaskEntity) {
TaskEntity taskEntity = (TaskEntity) entity;
// 判断是否为多实例任务
boolean isMultiInstance = isMultiInstance(taskEntity);
if (isMultiInstance) {
log.info("task is multiInstance, taskId:{}", taskEntity.getId());
String taskId = taskEntity.getId();
TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();
Object user = taskService.getVariable(taskId, "approver");
// 设置审批人
if (ObjectUtil.isNotEmpty(user)) {
String userId = user.toString();
taskService.setAssignee(taskId, userId);
}
}
}
}
}
}
@Override
public boolean isFailOnException() {
return false;
}
@Override
public boolean isFireOnTransactionLifecycleEvent() {
return false;
}
@Override
public String getOnTransaction() {
return null;
}
private boolean isMultiInstance(TaskEntity task) {
// 获取流程定义id
boolean flag = false;
String processDefinitionId = task.getProcessDefinitionId();
Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
FlowElement flowElement = process.getFlowElement(task.getTaskDefinitionKey());
// 根据活动id获取活动实例
if (flowElement instanceof UserTask) {
UserTask userTask = (UserTask) flowElement;
if (userTask.getBehavior() instanceof ParallelMultiInstanceBehavior) {
ParallelMultiInstanceBehavior behavior = (ParallelMultiInstanceBehavior) userTask.getBehavior();
if (behavior != null && behavior.getCollectionExpression() != null) {
flag = true;
}
}
if (userTask.getBehavior() instanceof SequentialMultiInstanceBehavior) {
SequentialMultiInstanceBehavior behavior = (SequentialMultiInstanceBehavior) userTask.getBehavior();
if (behavior != null && behavior.getCollectionExpression() != null) {
flag = true;
}
}
}
return flag;
}
}