在作流程的流轉歷史時,一般狀況下仍是以列表的形式表現,可是這樣老是感受不太直觀,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的動態效果,實現更增強大的功能,但願能對你有所幫助!