activiti多实例节点的任意跳转

简介: activiti是原来不支持节点跳转的,他要求有线才能走,但实际业务中,需要支持动态跳转到各个节点。一开始,这里的做法是动态构造一条虚拟线的,相关代码如下:/** * 流程转向操作 * * @param taskId...

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;

    }
}

经测试,功能正常!

相关文章
|
4月前
|
缓存 前端开发
ProFlow 流程编辑器框架问题之创建一个自定义节点如何解决
ProFlow 流程编辑器框架问题之创建一个自定义节点如何解决
53 1
|
6月前
|
DataWorks API 调度
DataWorks产品使用合集之在调度配置配置了节点的上游节点输出,没办法自动生成这个flow的依赖,该怎么操作
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
6月前
|
数据采集 分布式计算 DataWorks
DataWorks产品使用合集之如何设置节点A执行失败,自动执行节点B,否则执行节点C
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
7月前
|
移动开发 前端开发 数据库
ruoyi-nbcio 基于flowable规则的多重并发网关的任意跳转
ruoyi-nbcio 基于flowable规则的多重并发网关的任意跳转
141 0
activiti 会签多实例任务,设置为候选组或个人任务的总结
activiti 会签多实例任务,设置为候选组或个人任务的总结
1062 0
activiti 会签多实例任务,设置为候选组或个人任务的总结
|
7月前
|
JSON JavaScript 小程序
uniapp的配置文件、入口文件、主组件、页面管理部分
uniapp的配置文件、入口文件、主组件、页面管理部分
|
存储 NoSQL MongoDB
第一个路由节点创建|学习笔记
快速学习第一个路由节点创建
第一个路由节点创建|学习笔记
Activiti原理分析(二)多实例,会或签与依次审批
Activiti 原理分析系列文章的第二篇。这里我们重点研究在 Activity 中如何实现会或签以及依次审批的功能,以及 BPMN 中的多实例规范。
4225 2
Activiti原理分析(二)多实例,会或签与依次审批
SpringBoot+Activiti6流程节点的任意跳转
项目中遇到的要求,在此记录一下。可以回退,可以任意跳转,都会有记录。
1018 0
|
Kubernetes 调度 数据中心
阿里云注册集群—混合集群-使用自定义节点添加脚本
混合集群的添加云上节点的方式依赖本地数据中心自建Kubernetes集群的搭建方式,比如使用Kubeadm搭建、使用Kubernetes二进制文件打击那或者使用Rancher平台搭建等。本文将介绍如何编写自定义节点添加脚本。
640 0