在處理流程回退時,需要獲取某個節點當前可以回退到的節點,簡單分析下:
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); } } }