在作流程的流转历史时,一般状况下仍是以列表的形式表现,可是这样老是感受不太直观,JBPM号称是面向图的编程,那么为何咱们不能在流程图上显示咱们的流转历史呢,至少咱们能够在流程图上高亮显示当前流程执行到了哪一个节点,若是能这样的话用户能够很轻松并且一目了然的看到流程的流转状况。
我发如今JBPM自带的例子中有相似的效果,后来无心中又在网上发现了一篇文章《
JBPM图形化流程监控》,做者简单的阐述了图形化流程监控的实现思路,让我欣喜万分,最终决定一试,呵呵,首先让我秀一下战果吧:
图1:当前任务节点
图2:当前流程中的活动任务
下面简单的说说实现思路:
一、首先若是咱们想高亮显示某一任务节点,咱们至少会知道该任务的某个实例,那么咱们能够经过该taskInstance取得该任务所在的任务节点名称如:String nodeName = taskInstance.getTask().getTaskNode().getName();
二、其次咱们使用JBPM的Eclipse插件画流程图的时候,工具除了生成流程图以外还会有一个gpd.xml,该文件记录了流程图的大小及其中的节点的坐标及每一个节点的长宽,这就是说咱们能够用DOM4J来解析该流程图,从而获得咱们要高亮显示的那个节点的坐标及大小。
三、最后咱们能够经过以上两步获得的信息,以该流程图中为背景图案在其上画DIV,来高亮显示相应节点。
须要说明的是,我这种实现思路跟JBPM自带例子的思路有一点不一样,JBPM是在部署流程定义的时候把流程定义图也同样的放入了数据库,因此他是以IO流的方式来处理,而我这种是彻底在本地解析XML文件。
呵呵,大致思路就是这样了,不知道我有没有说明白,不过不明白没关系,下面咱们就来看具体的代码实现,你们都是coder,仍是用代码交流起来比较方便啊,你们手头都有gpd.xml文件的模板,因此这个文件的代码就不往上贴了:
1
/**
2
* 功能描述:解析指定Node节点的x、y坐标以及该节点的width和height<br>
3
*
@param
root
4
*
@param
nodeName
5
*
@return
int[]
6
*/
7
private
int
[] extractBoxConstraint(Element root, String nodeName) {
8
int
[] result
=
new
int
[
4
];
9
XPath xPath
=
new
DefaultXPath(
"
//node[@name='
"
+
nodeName
+
"
']
"
);
10
Element node
=
(Element) xPath.selectSingleNode(root);
11
result[
0
]
=
Integer.valueOf(node.attribute(
"
x
"
).getValue()).intValue()
-
4
;
12
result[
1
]
=
Integer.valueOf(node.attribute(
"
y
"
).getValue()).intValue()
-
4
;
13
result[
2
]
=
Integer.valueOf(node.attribute(
"
width
"
).getValue()).intValue()
+
4
;
14
result[
3
]
=
Integer.valueOf(node.attribute(
"
height
"
).getValue()).intValue()
+
4
;
15
return
result;
16
}
17
18
/**
19
* 功能描述:获取gpd文件中流程图的width和height<br>
20
*
@param
root
21
*
@return
int[]
22
*/
23
private
int
[] extractImageDimension(Element root) {
24
int
[] result
=
new
int
[
2
];
25
result[
0
]
=
Integer.valueOf(root.attribute(
"
width
"
).getValue()).intValue();
26
result[
1
]
=
Integer.valueOf(root.attribute(
"
height
"
).getValue()).intValue();
27
return
result;
28
}
以上两个方法是纯DOM4J实现,做用就是解析gpd.xml文件以获取咱们想要获得的信息,这两段代码是JBPM例子中带有的,高亮显示的具体的应用代码以下:
1
/**
2
* 在流程图上高亮显示节点 功能描述:<br>
3
*
4
*
@param
taskInstanceId
5
* 任务实例ID
6
*
@param
gpdPath
7
* 流程图坐标文件路径
8
*
@param
processImagePath
9
* 流程图路径
10
*/
11
public
String ProcessImageForCurrentTask(
long
taskInstanceId,String gpdPath,String processImagePath) {
12
StringBuffer sbString
=
new
StringBuffer();
13
try
{
14
//
初始化dom4j
15
Element rootDiagramElement
=
new
SAXReader().read(gpdPath).getRootElement();
16
//
获取当前TaskInstance
17
TaskInstance taskInstance
=
this
.defaultJbpmDAO.findTaskInstance(taskInstanceId);
18
//
解析gpd.xml
19
int
[] boxConstraint
=
extractBoxConstraint(rootDiagramElement, taskInstance.getTask().getTaskNode().getName());
20
int
[] p_w_picpathDimension
=
extractImageDimension(rootDiagramElement);
21
//
具体的画图代码
22
String p_w_picpathLink
=
processImagePath;
23
sbString.append(
"
<table border=0 cellspacing=0 cellpadding=0 width=
"
+
p_w_picpathDimension[
0
]
+
"
height=
"
+
p_w_picpathDimension[
1
]
+
"
style=\
"
position:relative\
"
>
"
);
24
sbString.append(
"
<tr>
"
);
25
sbString.append(
"
<td width=
"
+
p_w_picpathDimension[
0
]
+
"
height=
"
+
p_w_picpathDimension[
1
]
+
"
style=\
"
background
-
p_w_picpath:url(
"
+ p_w_picpathLink +
"
)\
"
valign=top>
"
);
26
sbString.append(
"
<div style=\
"
position:absolute;
"
);
27
sbString.append(
"
left:
"
+
boxConstraint[
0
]
+
"
px; top:
"
+
boxConstraint[
1
]
+
"
px;width:
"
+
boxConstraint[
2
]
+
"
px;height:
"
+
boxConstraint[
3
]
+
"
px;
"
);
28
sbString.append(
"
z-index:1; border-color:red; border-width:4;
"
);
29
sbString.append(
"
border-style: groove; background-color: transparent;\
"
>
"
);
30
sbString.append(
"
</div>
"
);
31
sbString.append(
"
</td>
"
);
32
sbString.append(
"
</tr>
"
);
33
sbString.append(
"
</table>
"
);
34
35
}
catch
(Exception e) {
36
e.printStackTrace();
37
}
38
return
sbString.toString();
39
}
40
虽然代码比较多,可是思路很清晰,我也就不罗嗦了,上面是给出了指定的taskInstance的ID,能够用来高亮显示指定的任务节点,若是咱们想要显示指定流程中处于活跃状态的任务的话,能够传入processInstance的ID,而后获得该流程中的符合条件的任务,循环的生成DIV就好了,看具体代码:
1
/**
2
* 功能描述:在流程图上高亮显示指定流程中处于活跃状态的节点 <br>
3
*
4
*
@param
taskInstanceId
5
* 任务实例ID
6
*
@param
gpdPath
7
* 流程图坐标文件路径
8
*
@param
processImagePath
9
* 流程图路径
10
*/
11
public
String processImage(
final
long
processInstanceId,
final
String gpdPath,
final
String processImagePath) {
12
StringBuffer sbString
=
new
StringBuffer();
13
try
{
14
Element rootDiagramElement
=
new
SAXReader().read(gpdPath).getRootElement();
15
16
//
取得活跃状态的任务
17
List
<
TaskInstance
>
activeTaskObjectList
=
this
.defaultJbpmDAO.getTaskInstanceListFormProcess(processInstanceId, TaskStateType.TASK_UNFINISHED);
18
int
[] p_w_picpathDimension
=
extractImageDimension(rootDiagramElement);
19
20
String p_w_picpathLink
=
processImagePath;
21
sbString.append(
"
<table border=0 cellspacing=0 cellpadding=0 width=
"
+
p_w_picpathDimension[
0
]
+
"
height=
"
+
p_w_picpathDimension[
1
]
+
"
style=\
"
position:relative\
"
>
"
);
22
sbString.append(
"
<tr>
"
);
23
sbString.append(
"
<td width=
"
+
p_w_picpathDimension[
0
]
+
"
height=
"
+
p_w_picpathDimension[
1
]
+
"
style=\
"
background
-
p_w_picpath:url(
"
+ p_w_picpathLink +
"
)\
"
valign=top>
"
);
24
//
循环的画DIV,注意此处DIV的相对布局
25
for
(TaskInstance taskInstance : activeTaskObjectList) {
26
int
[] boxConstraint
=
extractBoxConstraint(rootDiagramElement, taskInstance.getTask().getTaskNode().getName());
27
sbString.append(
"
<div style=\
"
position:absolute;
"
);
28
sbString.append(
"
left:
"
+
boxConstraint[
0
]
+
"
px; top:
"
+
boxConstraint[
1
]
+
"
px; width:
"
+
boxConstraint[
2
]
+
"
px;height:
"
+
boxConstraint[
3
]
+
"
px;
"
);
29
sbString.append(
"
z-index:1; border-color: red; border-width: 4;
"
);
30
sbString.append(
"
border-style: groove; background-color: transparent;\
"
>
"
);
31
sbString.append(
"
</div>
"
);
32
}
33
sbString.append(
"
</td>
"
);
34
sbString.append(
"
</tr>
"
);
35
sbString.append(
"
</table>
"
);
36
37
}
catch
(Exception e) {
38
e.printStackTrace();
39
}
40
return
sbString.toString();
41
42
}
43
呵呵,到这咱们的目的就已经实现了,能够看到这样在页面上输出的是标准的HTML,咱们甚至能够加入JS的动态效果,实现更增强大的功能,但愿能对你有所帮助!