在JBPM的使用过程中,由于JBPM完全屏蔽了流程内部的细节。所以有时候很难从全局上掌握流行的运行情况。比如你提交一个请求,只知道请求提交了,通常你是不知道提交到那里,也不知道你的请求目前在那个位置。这样必须专门通过程序去查看流程的整体运行情况。查看的方式越简单明了越好。
我采用图片的方式,能够显示出流程进过的历史和当前任务所在的节点。方便用户查询。
这个技术分成两个重要部分。第一个是查询当前流程的流程定义图片,将其转换成输出流。第二点是将查询任务经过的节点和当前节点,得到他们的坐标。在html中使用图像标注出来。
一:获得流程定义图片。
public InputStream findProcessInstancePic(String processInstanceId) { ProcessInstance processInstance = executionService .findProcessInstanceById(processInstanceId); String processDefinitionId = processInstance.getProcessDefinitionId(); ProcessDefinition processDefinition = repositoryService .createProcessDefinitionQuery() .processDefinitionId(processDefinitionId).uniqueResult(); return repositoryService.getResourceAsStream( processDefinition.getDeploymentId(), processDefinition.getImageResourceName()); }
这个方法是通过流程实例ID获取流程定义,然后将流程定义对应的图片得到。返回输出流。流程定义图片是部署流程的时候和流程定义一起部署到JBPM中的。得到图片以后,在界面使用img标签显示出图片。
</center> <img src="${ctx}/service/processInstance/pic.do?processInstanceId=${id }" style="position:absolute;left:0px;top:0px;"/> <c:if test="${activityCoordinates!=null }"> <div style="position:absolute;border:3px solid red;left:${activityCoordinates.x }px;top:${activityCoordinates.y }px;width:${activityCoordinates.width }px;height:${activityCoordinates.height}px;"></div> </c:if> <c:if test="${ac!=null }"> <c:forEach items="${ac }" var="a"> <div style="position:absolute;border:3px solid blue;left:${a.x }px;top:${a.y }px;width:${a.width }px;height:${a.height}px;"></div> </c:forEach> </c:if> </body> </html>
<imgsrc="${ctx}/service/processInstance/pic.do?processInstanceId=${id }"style="position:absolute;left:0px;top:0px;"/>
请求一个controller显示图片。
controller代码如下:
/** * 显示流程图片 * * @param request * @param response * @param id */ @RequestMapping("/service/processInstance/pic.do") public void pic(HttpServletRequest request, HttpServletResponse response, String processInstanceId) { InputStream inputStream = workflowManager .findProcessInstancePic(processInstanceId); PrintWriter pw = null; if (inputStream == null) { try { pw = response.getWriter(); pw.write("error"); } catch (IOException e) { e.printStackTrace(); } finally { pw.close(); } } else { byte[] b = new byte[1024]; int len = -1; ServletOutputStream sos = null; try { sos = response.getOutputStream(); while ((len = inputStream.read(b, 0, 1024)) != -1) { sos.write(b, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { if (sos != null) { try { sos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
二:显示流程坐标。
首先根据流程实例ID查询出该流程实例进过的节点的名称。然后再在流程定义中查询这些节点的坐标。
public ActivityCoordinates findActivityCoordinates(String id) { ProcessInstance processInstance = executionService .findProcessInstanceById(id); if (null==processInstance||processInstance.isSuspended()) { return null; } Set<String> activityNames = processInstance.findActiveActivityNames(); return repositoryService.getActivityCoordinates(processInstance .getProcessDefinitionId(), activityNames.iterator().next()); }
@Override public List<ActivityCoordinates> findHistoryActivityInfo(String processId) { List<ActivityCoordinates> activityCoordinates = new ArrayList<ActivityCoordinates>(); List<HistoryActivityInstance> hisIns = historyService.createHistoryActivityInstanceQuery().processInstanceId(processId).list(); ProcessInstance processInstance = executionService.findProcessInstanceById(processId); if (null==processInstance||processInstance.isSuspended()) { return null; } for(Iterator<HistoryActivityInstance> iter = hisIns.iterator();iter.hasNext() ; ){ activityCoordinates.add(repositoryService.getActivityCoordinates(processInstance.getProcessDefinitionId(), iter.next().getActivityName())); } return activityCoordinates; }
其中第一个方法是返回当前节点坐标,第二个方法是返回进过节点坐标(包括当前节点,这就需要去掉当前的节点),这个操作在controller中完成,然后返回到页面中。
/** * 显示流程坐标 * * @param request * @param id * @return */ @RequestMapping("service/processInstance/view.do") public String view(HttpServletRequest request, String id) { // 流程图活动坐标 ActivityCoordinates activityCoordinates = workflowManager .findActivityCoordinates(id); List<ActivityCoordinates> ac = null; if(activityCoordinates != null){ ac = workflowManager.findHistoryActivityInfo(id); ac.remove(activityCoordinates); } request.setAttribute("ac", ac); request.setAttribute("activityCoordinates", activityCoordinates); request.setAttribute("id", id); return "/mtdev/module/myflow/image"; }
jsp界面和上面的一样。这里的关键是使用div在图片上标记出节点。给div加上边框,看起来就和图片合在一起一样。
下面是效果图。