• activiti获取可回退的节点


        在处理流程回退时,需要获取某个节点当前可以回退到的节点,简单分析下:

    1. 只支持回退到userTask。

    2. 如果流程流转过某节点时生成了多个任务,从其中某一个任务回退到该节点后,不处理另外的任务。

    3. 只能回退到当前节点前已经处理过的节点。

        基于这个考虑,获取哪些节点可以回退按如下处理:

    1. 从历史任务表查当前节点所在流程实例已经完成过的所有任务,有可能包括当前节点以后的任务(比如当前节点本来就是由后面节点回退的)

    2. 判断任务是不是当前节点以前的userTask节点任务,如果是,加入返回列表。

    3. 同一个节点只返回一次。

        在这种处理前提下,需要获取流程中所有userTask节点的前后关系。我用深度优先的方式对流程的所有节点进行了一个遍历,把所有节点的前后关系保存在一个map里,map的内容为:

        key: 前面的节点编号#后面的节点编号

        value:从前面节点到后面节点中间要经过几个节点。

        如果一个节点前有多个节点,比如 流程是 A-->B-->C-->D,那么 map的数据类似:

       {A#B:1,A#C:2,A#D:3,B#C:1,B#D:2,C#D:1}

       在这种情况下,所有的可能性都存储了一份,但是在后面判断节点的前后关系时相对比较容易,只要把要判断的节点和当前节点编号拼接在一起,判断 要判断的节点#当前节点 是不是在map里存在就好了。

       一般来说,流程的节点数不会太多,这样已经够用了。

      由于回退不是在流程上通过划线处理的,所以一般不会出现环状的流程图,因此用深度优先方式遍历也适用,感觉上应该用广度优先的方式遍历更合适一点。

      附部分代码:

    private static Map<String,Map<String,Object>> PROCESS_NODE_MAP = null;
    private Map getFlowNodeRel(String processDefKey){
            if (null == PROCESS_NODE_MAP){
                PROCESS_NODE_MAP = new HashMap<String, Map<String, Object>>();
            }
            if(null == PROCESS_NODE_MAP.get(processDefKey)){
                ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
                List<Process> processList = engine.getRepositoryService().getBpmnModel(processDefKey).getProcesses();
                Process process = null;
                if(processList.size()>0){
                    process = processList.get(0);
                    Map relationMap = new HashMap<String,Integer>();
                    setFlowNodeRel(process,relationMap);
                    PROCESS_NODE_MAP.put(processDefKey, relationMap);
                }
            }
            return PROCESS_NODE_MAP.get(processDefKey);
        }
        
        //根据process往relationMap里写入UserTask之间的前后关系,从start开始遍历节点,不循环
        private void setFlowNodeRel(Process process,Map relationMap){
            Iterator<FlowElement> iterator = process.getFlowElements().iterator();
            HashMap nodeMap = new HashMap<String,FlowElement>();
            setFlowNodeMap(process,nodeMap);
            //获取start节点
            StartEvent startEvent = (StartEvent) nodeMap.get("startEvent");
            //处理节点关系
            setFlowNodeRel("","startEvent",nodeMap,relationMap,1);
        }
        
        //根据节点ID设置关系
        private void setFlowNodeRel(String parentKey,String nodeId,Map<String,FlowElement> nodeMap,Map relationMap,int level){
            FlowElement element = nodeMap.get(nodeId);
            if(element instanceof UserTask){
                relationMap.put(nodeId, element);
            }
            if(!(element  instanceof FlowNode)){
                return;
            }
            
            List<SequenceFlow> outFlows = ((FlowNode)element).getOutgoingFlows(); 
            if(outFlows.size() == 0){
                return;
            }
            
            //采用深度遍历
            for(int index=0;index < outFlows.size();index++){
                SequenceFlow tmpSequence = outFlows.get(index);
                String target = tmpSequence.getTargetRef();
                String key = nodeId + "#" + target;
                
                String loopKey = target + "#" + nodeId;
                
                FlowElement tmpElement = nodeMap.get(target);
                //只是源和目标都是 用户任务 才写入
                if(relationMap.containsKey(loopKey) || relationMap.containsKey(key)){
                    continue;
                }
                if(tmpElement instanceof UserTask && element instanceof UserTask){
                    setRelMapValue(relationMap,parentKey,target, level);
                }
                //递归找下一个任务的关系
                setFlowNodeRel(parentKey+"#"+target,target,nodeMap,relationMap,level+1);
            }
        }
        
        private void setRelMapValue(Map relationMap,String parentKey,String nodeKey,int level){
            if(parentKey.length() > 0){
                String[] parentArr = parentKey.split("#");
                for(String parent:parentArr){
                    if(StringUtils.isNotEmpty(parent)){
                        String key = parent + "#" + nodeKey;
                        String loopKey = nodeKey + "#" + parent;
                        if(relationMap.containsKey(loopKey) || relationMap.containsKey(key)){
                            continue;
                        }else{
                            relationMap.put(key, level);
                        }
                    }
                }
            }
        }
        
        //把流程节点设置到map属性里
        private void setFlowNodeMap(Process process,Map<String,FlowElement> nodeMap){
            Iterator<FlowElement> iterator = process.getFlowElements().iterator();
            
            while(iterator.hasNext()){
                FlowElement element = iterator.next();                    
                if(element instanceof StartEvent){
                    nodeMap.put("startEvent", element);
                }else{
                    nodeMap.put(element.getId(),element);
                }
            }
        }
    View Code

    ------------------------------------

    当天空没有颜色的时候,就用自己的双手画出绚烂的彩虹。程序员的天空,永远都是多彩多姿的。

  • 相关阅读:
    mysql 数据库检查与修复的办法
    SECPATH透明模式下VLAN透传配置实例
    腾讯QQ所有的服务器
    AutoRuns 9.13 汉化版
    IP地址在数据库中的存储解决方案
    DNS智能解析 for windows 2003
    Windows Media Player ActiveX 控件参数
    删除nvidia右键菜单
    通过js控制cookies
    正确使用|(按位或)和||(逻辑或)
  • 原文地址:https://www.cnblogs.com/kevinYX/p/3480125.html
Copyright © 2020-2023  润新知