Activiti任务退回、任意跳转(任务调度)功能实现及思路(简版)
原创文章:转载请备注:原创文章地址
需求:
1.在当前任务节点退回至上一节点;
2.需要跳过某一个或者几个节点后,指定节点开始继续执行此任务;
3.在流程运行时跳转到任意一节点(有没有执行过都可以跳转);
这种解决的思路都是同一种方式:
模拟一个需求:nowNode跳转到toNode处
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX5lERPBTVE9UejpXT4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jMwcjMwcTM3EzMwQDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
思路:
1.拿到当前节点(这里称之为nowNode)所有连接其他节点的线(outGoingPath)保存起来,然后删除这些线;
2.拿到当前节点(nowNode)和指定跳转(toNode)的节点,然后new一条线,连接当前节点(nowNode)和指定节点(toNode);
3.执行完成任务操作(此时,当前节点因为删除了原本连接着其他节点的线,所有只有刚刚连接着当前节点(nowNode)和指定节点(toNode)的一条线),只有一条线,也就是说任务跳转到指定节点(toNode);
4.恢复原流程图(将new出来的那条线删除,将原本nowNode节点上删除的那些线恢复);
这里就是总体思路,接下来贴代码。
/**
* 流程转向操作
*
* @param taskId 当前任务ID
* @param activityId 目标节点任务ID
* @param variables 流程变量
* @throws Exception
*/
public static void turnTransition(String taskId, String activityId, Map<String, Object> variables) {
// 当前节点
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);
}
/**
* 根据任务ID和节点ID获取活动节点 <br>
*
* @param taskId
* @param activityId 活动节点ID <br>
* 如果为null或"",则默认查询当前活动节点 <br>
* 如果为"end",则查询结束节点 <br>
* @return
* @throws Exception
*/
public static ActivityImpl findActivitiImpl(String taskId, String activityId) {
// 取得流程定义
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(taskService.createTaskQuery().taskId(taskId).singleResult().getProcessDefinitionId());
// 获取当前活动节点ID
if (StringUtils.isEmpty(activityId)) {
activityId = getTaskById(taskId).getTaskDefinitionKey();
}
// 根据流程定义,获取该流程实例的结束节点
ProcessDefinitionImpl processDefinitionImpl = (ProcessDefinitionImpl) getReadOnlyProcessDefinitionByProcDefId(processDefinition.getId());
if (activityId.toUpperCase().equals("END")) {
for (ActivityImpl activityImpl : processDefinitionImpl.getActivities()) {
List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();
if (pvmTransitionList.isEmpty()) {
return activityImpl;
}
}
}
// 根据节点ID,获取对应的活动节点
ActivityImpl activityImpl = processDefinitionImpl.findActivity(activityId);
// 此处改动,无法获取到对应的活动节点,所以此处采用迂回的方式,如果前面可以取到则跳过,如果没有取到则自己取
if (activityImpl == null) {
List<ActivityImpl> activities = processDefinitionImpl.getActivities();
for (ActivityImpl actImpl : activities) {
if (actImpl.getId().equals(activityId)) {
activityImpl = actImpl;
break;
}
}
}
return activityImpl;
}
/**
* 清空指定活动节点现有流向,且将清空的现有流向返回
*
* @param activityImpl 活动节点
* @return 节点流向集合
*/
public static List<PvmTransition> clearTransition(ActivityImpl activityImpl) {
// 存储当前节点所有流向临时变量
List<PvmTransition> oriPvmTransitionList = new ArrayList<>();
// 获取当前节点所有流向,存储到临时变量,然后清空
List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();
for (PvmTransition pvmTransition : pvmTransitionList) {
oriPvmTransitionList.add(pvmTransition);
}
pvmTransitionList.clear();
return oriPvmTransitionList;
}
/**
* 根据任务ID和节点ID获取活动节点 <br>
*
* @param taskId
* @param activityId 活动节点ID <br>
* 如果为null或"",则默认查询当前活动节点 <br>
* 如果为"end",则查询结束节点 <br>
* @return
* @throws Exception
*/
public static ActivityImpl findActivitiImpl(String taskId, String activityId) {
// 取得流程定义
ProcessDefinitionEntity processDefinition = getProcDefEntityByTaskId(taskId);
// 获取当前活动节点ID
if (StringUtils.isEmpty(activityId)) {
activityId = getTaskById(taskId).getTaskDefinitionKey();
}
// 根据流程定义,获取该流程实例的结束节点
ProcessDefinitionImpl processDefinitionImpl = (ProcessDefinitionImpl) getReadOnlyProcessDefinitionByProcDefId(processDefinition.getId());
if (activityId.toUpperCase().equals("END")) {
for (ActivityImpl activityImpl : processDefinitionImpl.getActivities()) {
List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();
if (pvmTransitionList.isEmpty()) {
return activityImpl;
}
}
}
// 根据节点ID,获取对应的活动节点
ActivityImpl activityImpl = processDefinitionImpl.findActivity(activityId);
// 此处改动,无法获取到对应的活动节点,所以此处采用迂回的方式,如果前面可以取到则跳过,如果没有取到则自己取
if (activityImpl == null) {
List<ActivityImpl> activities = processDefinitionImpl.getActivities();
for (ActivityImpl actImpl : activities) {
if (actImpl.getId().equals(activityId)) {
activityImpl = actImpl;
break;
}
}
}
return activityImpl;
}
/**
* 清空指定节点现有流向,且将新流向接入
*
* @param activityImpl 活动节点
* @param oriPvmTransitionList 新流向节点集合
*/
public static void restoreTransition(ActivityImpl activityImpl, List<PvmTransition> oriPvmTransitionList) {
// 清空现有流向
List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();
pvmTransitionList.clear();
// 还原以前流向
for (PvmTransition pvmTransition : oriPvmTransitionList) {
pvmTransitionList.add(pvmTransition);
}
}
ps:简版不涉及1.单任务回退并行节点(单变多);
2.并行任务节点回退单任务节点(多变单);
3.并行任务节点回退并行任务节点(多变多);
4.并行多实例回退并行多实例任务(恶心);
这些会留在以后的文章讲解。