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);
}
}
}
activiti获取可回退的节点的更多相关文章
- activiti获取流程图中的所有信息包括变量名
今天在看activiti的变量的时候,都是由用户来设置变量,我们在后台写代码通过变量设置或取一些参数的时候,非常的不方便. 比如:设置变量的时候通过页面设置 设置之后,我们如何动态的给这个变量设置参数 ...
- 解析某些特殊格式XML文件时,获取不到根节点问题
还是在语音识别这块.在读取本地的SRGS的XML后,无法获取到根节点<grammar>. 下面是SRGS.XML文件(只给出了根节点) <?xml version="1.0 ...
- 获取Json数据某节点的值
时间匆忙,直接上代码,回家还得做清蒸鱼呢! #region 获取Json字符串某节点的值 /// <summary> /// 获取Json字符串某节点的值 /// </summary ...
- I.MX6 Linux 自动获取AR1020 event input节点
/*********************************************************************** * I.MX6 Linux 自动获取AR1020 ev ...
- 获取所有树叶子节点 注册添加事件 if ($(node).tree('isLeaf', node.target)) 是否叶子节点
//获取所有树叶子节点 注册添加事件 if ($(node).tree('isLeaf', node.target)) 是否叶子节点 $(function () { $('.easyui-tree') ...
- react.js 获取真实的DOM节点
为了获取真实的dom节点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点. var MyComponent = React.crea ...
- vue_elementUI_ tree树形控件 获取选中的父节点ID
el-tree 的 this.$refs.tree.getCheckedKeys() 只可以获取选中的id 无法获取选中的父节点ID想要获取选中父节点的id;需要如下操作1. 找到工程下的node_m ...
- JavaScript的DOM_获取和操作层次节点
一.层次节点的概述 节点的层次结构可以划分为:父节点与子节点.兄弟节点这两种.当我们获取其中一个元素节点的时候,就可以使用层次节点属性来获取它相关层次的节点. 二.childNodes 属性 chil ...
- 获取iframe子页面节点,响应浏览器宽高
获取iframe子页面节点,响应浏览器宽高 html部分代码 <div> <iframe width="100%" height="100%" ...
随机推荐
- leetcode — substring-with-concatenation-of-all-words
import java.util.*; /** * Source : https://oj.leetcode.com/problems/substring-with-concatenation-of- ...
- 将H5页面的应用打包成APP(苹果和安卓版本)
今天在清理手机上的应用时看到了“联名会员”这个“app”,我感觉只是个H5页面,不是一个原生的APP,但看起来和原生APP一模一样,心想,如果以后我开发了H5应用是不是可以把它搞成APP形式供别人下载 ...
- hexo自动部署到git、ftp(虚拟主机等)、云服务器的方式
自动部署很有用,当你写完文章后,直接使用hexo d就可以自动更新你的网站了 部署到git 首先你需要在你的blog下安装git deployer插件:npm install hexo-deploye ...
- Java与c#的一些细节区别
实习中用的语言是c#,第一次接触到这种语言,然后写的过程中,发觉和Java几乎一摸一样,好像根本是无缝切换,但细节仍有很大的区别,称有空总结一波里面的部分细节实现. ps. 我写c#过程中,发觉c#有 ...
- HTML之marquee(文字滚动)详解
语法: <marquee></marquee> 以下是一个最简单的例子: 代码如下: <marquee><font size=+3 color=red> ...
- SQL不重复查找数据及把一列多行内容拼成一行
如下表: 表名:Test ID RowID Col1 Col2 1 1 A A 2 1 B A 3 1 A B 4 1 C B 1,查找表中字段重复的只查找一次 select distinct Col ...
- [PHP]算法- 二叉树的深度的PHP实现
二叉树的深度: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 思路: 1.非递归层序遍历 2.使用辅助队列,根结点先入队列 ...
- maven配置之:<distributionManagement>snapshot快照库和release发布库
在使用maven过程中,我们在开发阶段经常性的会有很多公共库处于不稳定状态,随时需要修改并发布,可能一天就要发布一次,遇到bug时,甚至一天要发布N次.我们知道,maven的依赖管理是基于版本管理的, ...
- C++ enum的使用
enum day {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 默认情况下,枚举符的值从0开始,其后值总是前面一个+1. 即Sun=0,Mon=1,Tue=2,Wed=3,Thu= ...
- webpack4 系列教程(五): 处理CSS
这节课讲解webpack4中打包css的应用.v4 版本和 v3 版本并没有特别的出入. >>> 本节课源码 >>> 所有课程源码 教程所示图片使用的是 githu ...