activiti是原来不支持节点跳转的,他要求有线才能走,但实际业务中,需要支持动态跳转到各个节点。
一开始,这里的做法是动态构造一条虚拟线的,相关代码如下:
/**
* 流程转向操作
*
* @param taskId
* 当前任务ID
* @param activityId
* 目标节点任务ID
* @param variables
* 流程变量
* @throws Exception
*/
public static void turnTransition(String taskId, String activityId, Map<String, Object> variables)
throws Exception {
TaskEntity taskEntitiy=findTaskById(taskId);
// 当前节点
ActivityImpl currActivity = findActivitiImpl(taskId, null);
// 清空当前流向
List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity);
// 创建新流向
TransitionImpl newTransition = currActivity.createOutgoingTransition();
// 目标节点
ActivityImpl pointActivity = findActivitiImpl(taskId, activityId);
// 设置新流向的目标节点
newTransition.setDestination(pointActivity);
// 执行转向任务
taskService.complete(taskId, variables);
// 删除目标节点新流入
pointActivity.getIncomingTransitions().remove(newTransition);
// 还原以前流向
restoreTransition(currActivity, oriPvmTransitionList);
}
这种情况一直好好的,但后续发现流程通过时,自动跳到前面的节点。
经查,原因是这样的:
这种方法可以实现动态跳转,不需要修改Activiti自身执行,但是会动态修改系统中的流程定义缓存对象。理论上这会出现一个多线程下,全局变量不安全的问题。单个Activiti流程引擎中,流程定义缓存对象是被所有线程共用的,当一个应用服务器同时收到两个不同流程实例、同个流程定义、同个环节的任务提交请求。a要求驳回,所以该线程动态修改了流程定义;与此同时,b要求正常流转,但是执行过程中,依据的流程定义已被修改,可能导致b也走向了驳回。
那怎么整,上网查了一下,发现了分享牛的代码,但他的代码存在问题,不支持多实例跳转多实例。
后续将代码修改如下:
package com.meicloud.meiqing.workflow.engine.operation.base;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.meicloud.meiqing.workflow.engine.constants.CdpActivitiConstant;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmException;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ScopeImpl;
import org.activiti.engine.impl.pvm.runtime.AtomicOperation;
import org.activiti.engine.impl.pvm.runtime.InterpretableExecution;
/**
* @description: 自由跳转流程
* @create: 2018-06-13 09:22
**/
public class JDJumpTaskCmd implements Command<Void> {
protected String taskId;//任务id
protected String executionId;//执行实例id
protected String parentId;//流程实例id
protected ActivityImpl desActivity;//目标节点
protected Map<String, Object> paramvar;//变量
protected ActivityImpl currentActivity;//当前的节点
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = Context
.getCommandContext().getExecutionEntityManager();
ExecutionEntity executionEntity = executionEntityManager
.findExecutionById(executionId);
//寻找根路径
String id = null;
if (executionEntity.getParent() != null) {
executionEntity = executionEntity.getParent();
if (executionEntity.getParent() != null) {
executionEntity = executionEntity.getParent();
id = executionEntity.getId();
}
id = executionEntity.getId();
}
//设置相关变量
executionEntity.setVariables(paramvar);
//executionEntity.setExecutions(null);
executionEntity.setEventSource(this.currentActivity);
executionEntity.setActivity(this.currentActivity);
// 根据executionId 获取Task
Iterator<TaskEntity> localIterator = Context.getCommandContext()
.getTaskEntityManager().findTasksByProcessInstanceId(parentId).iterator();
//删除无用的工作项
while (localIterator.hasNext()) {
TaskEntity taskEntity = (TaskEntity) localIterator.next();
System.err.println("==================" + taskEntity.getId());
if(taskId.equals(taskEntity.getId())) {
// 触发任务监听
taskEntity.fireEvent("complete");
// 删除任务的原因
Context.getCommandContext().getTaskEntityManager()
.deleteTask(taskEntity, "completed", false);
}else {
// 删除任务的原因
Context.getCommandContext().getTaskEntityManager()
.deleteTask(taskEntity, "deleted", false);
}
}
//删除相关执行子路径,只保留根执行路径
List<ExecutionEntity> list = executionEntityManager
.findChildExecutionsByParentExecutionId(parentId);
for (ExecutionEntity executionEntity2 : list) {
ExecutionEntity findExecutionById = executionEntityManager.findExecutionById(executionEntity2.getId());
List<ExecutionEntity> parent = executionEntityManager
.findChildExecutionsByParentExecutionId(executionEntity2
.getId());
for (ExecutionEntity executionEntity3 : parent) {
executionEntity3.remove();
System.err.println(executionEntity3.getId()
+ "----------------->>>>>>>>>>");
Context.getCommandContext().getHistoryManager()
.recordActivityEnd(executionEntity3);
}
executionEntity2.remove();
Context.getCommandContext().getHistoryManager().recordActivityEnd(executionEntity2);
System.err.println(findExecutionById + "----------------->>>>>>>>>>");
}
commandContext
.getIdentityLinkEntityManager().deleteIdentityLinksByProcInstance(parentId);
//要激活交路径
executionEntity.setActive(true);
//去掉无用的变量,不去掉,会导致很多莫名奇妙的问题
executionEntity.removeVariable("loopCounter");
//去掉多实例的变量,如果变量不知道是啥,自己从节点定义里查
executionEntity.removeVariable("cdp_atuser");
//触发事件监听器
this.execute(executionEntity);
InterpretableExecution propagatingExecution = null;
if (this.desActivity.isScope()) {
propagatingExecution = (InterpretableExecution) executionEntity.createExecution();
executionEntity.setTransition(null);
executionEntity.setActivity(null);
executionEntity.setActive(false);
// log.debug("create scope: parent {} continues as execution {}", execution, propagatingExecution);
propagatingExecution.initialize();
} else {
propagatingExecution = executionEntity;
}
propagatingExecution.executeActivity(this.desActivity);
return null;
}
protected ScopeImpl getScope(InterpretableExecution execution) {
return (ScopeImpl) execution.getActivity();
}
/*
触发事件监听器
*/
public void execute(InterpretableExecution execution) {
ScopeImpl scope = getScope(execution);
List<ExecutionListener> exectionListeners = scope.getExecutionListeners(getEventName());
for (ExecutionListener listener : exectionListeners) {
execution.setEventName(getEventName());
execution.setEventSource(scope);
try {
listener.notify(execution);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new PvmException("couldn't execute event listener : " + e.getMessage(), e);
}
}
}
protected String getEventName() {
return org.activiti.engine.impl.pvm.PvmEvent.EVENTNAME_END;
}
/**
* 构造参数 可以根据自己的业务需要添加更多的字段
* @param taskId
* @param executionId
* @param desActivity
* @param paramvar
* @param currentActivity
*/
public JDJumpTaskCmd(String taskId,String executionId, String parentId,
ActivityImpl desActivity, Map<String, Object> paramvar,
ActivityImpl currentActivity) {
this.taskId=taskId;
this.executionId = executionId;
this.parentId = parentId;
this.desActivity = desActivity;
this.paramvar = paramvar;
this.currentActivity = currentActivity;
}
}
经测试,功能正常!