在做流程的流转历史时,通常情况下还是以列表的形式表现,但是这样总是感觉不太直观,JBPM号称是面向图的编程,那么为什么我们不能在流程图上显示我们的流转历史呢,至少我们可以在流程图上高亮显示当前流程执行到了哪个节点,如果能这样的话用户可以很轻松而且一目了然的看到流程的流转情况。
我发现在JBPM自带的例子中有类似的效果,后来无意中又在网上发现了一篇文章《 JBPM图形化流程监控》,作者简单的阐述了图形化流程监控的实现思路,让我欣喜万分,最终决定一试,呵呵,首先让我秀一下战果吧:
图1:当前任务节点
图2:当前流程中的活动任务
下面简单的说说实现思路:
1、首先如果我们想高亮显示某一任务节点,我们至少会知道该任务的某个实例,那么我们可以通过该taskInstance取得该任务所在的任务节点名称如:String nodeName = taskInstance.getTask().getTaskNode().getName();
2、其次我们使用JBPM的Eclipse插件画流程图的时候,工具除了生成流程图之外还会有一个gpd.xml,该文件记录了流程图的大小及其中的节点的坐标及每个节点的长宽,这就是说我们可以用DOM4J来解析该流程图,从而得到我们要高亮显示的那个节点的坐标及大小。
3、最后我们可以通过以上两步得到的信息,以该流程图中为背景图案在其上画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[] imageDimension = extractImageDimension(rootDiagramElement);
21 //具体的画图代码
22 String imageLink = processImagePath;
23 sbString.append("<table border=0 cellspacing=0 cellpadding=0 width=" + imageDimension[0] + " height=" + imageDimension[1] + " style=\"position:relative\">");
24 sbString.append(" <tr>");
25 sbString.append(" <td width=" + imageDimension[0] + " height=" + imageDimension[1] + " style=\"background-image:url(" + imageLink + ")\" 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[] imageDimension = extractImageDimension(rootDiagramElement);
19
20 String imageLink = processImagePath;
21 sbString.append("<table border=0 cellspacing=0 cellpadding=0 width=" + imageDimension[0] + " height=" + imageDimension[1] + " style=\"position:relative\">");
22 sbString.append(" <tr>");
23 sbString.append(" <td width=" + imageDimension[0] + " height=" + imageDimension[1] + " style=\"background-image:url(" + imageLink + ")\" 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的动态效果,实现更加强大的功能,希望能对你有所帮助!
posted on 2008-09-25 13:30
零全零美 阅读(6468)
评论(5) 编辑 收藏 所属分类:
jbpm