JBPM显示流程图有很多种方式,下面我讲述一下关于我的做法,点击流程图可以显示具每个节点的执行人,审批时间等
/**
* @authour wu 获得流程定义图片输入流
* @Date:2014年10月24日
* @param processInstanceId
* @return
*/
public InputStream findProcessInstancePic(String processInstanceId){
//获得流程实例processInstance,对于已完结的流程processInstance为null,所以应该通过HistoryProcessInstance查询processDefinitionId
//一般情况下processInstanceId与ExecutionId(newSite.10001)会相同,但在fork-join分叉流程时会不同,
//ProcessInstance processInstance = processEngine.getExecutionService().findProcessInstanceById(processInstanceId);
//String processDefinitionId = processInstance.getProcessDefinitionId();
HistoryService hs = processEngine.getHistoryService();
HistoryProcessInstance hpi = hs.createHistoryProcessInstanceQuery().processInstanceId(processInstanceId).uniqueResult();
String processDefinitionId = hpi.getProcessDefinitionId();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).uniqueResult();
String deploymentId = processDefinition.getDeploymentId();
//获取图片名称,如果发布流程时只发布了 xml 文件 , imageName就会是null,
//所以需要同时发布png图片:1.具体可参考zip方式发布流程;2、非ZIp流程的发布http://blog.csdn.net/yusewuhen/article/details/40510039
String imageName = processDefinition.getImageResourceName();
return repositoryService.getResourceAsStream( deploymentId,imageName);
}
这个方法是通过流程实例 ID 获取流程定义,然后将流程定义对应的图片得到。返回输出流。流程定义图片是部署流程的时候和流程定义一起部署到 JBPM 中的。得到图片以后,在界面使用 img 标签显示出图片。
<img src="<%=basePath%>newIndoorSite!pic.action?flow_id=${flow_id}" style="position:absolute;left:0px;top:0px;"/>
<!-- 两个C:if顺序不能改变,这样容易区分驳回流程的活动节点 -->
<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">
<!-- border计算是为了防止已走过节点被驳回节点覆盖 -->
<div
style="position:absolute;border:2px solid green;left:${a.x+3 }px;top:${a.y+3 }px;width:${a.width-4}px;height:${a.height-4}px;"
title="执行人:${a.tasker}(${a.tasker_role})
接收时间:${a.receiveTime}
完成时间:${a.completionTime}
意 见:${a.comment} ">
</div>
</c:forEach>
</c:if>
二:显示流程坐标。
首先根据流程实例ID查询出该流程实例进过的节点的名称。然后再在流程定义中查询这些节点的坐标。
/**
* @authour wu 获得流程当前活动节点的坐标
* @Date:2014年10月24日
* @param id
* @return
*/
public ActivityCoordinates findActivityCoordinates(String processInstanceId) {
//对于已经完结的流程 processInstance为NUll,将无法查询end节点
ProcessInstance processInstance = processEngine.getExecutionService()
.findProcessInstanceById(processInstanceId);
String processDefinitionId ;
String activtyName ;
if (null==processInstance||processInstance.isSuspended()) {
//已完结流程 processInstance为NUll 从HistoryProcessInstance获得需要的信息
HistoryService hs = processEngine.getHistoryService();
HistoryProcessInstance ss = hs.createHistoryProcessInstanceQuery().processInstanceId(processInstanceId).uniqueResult();
//获得end节点
activtyName = ss.getEndActivityName();
processDefinitionId = ss.getProcessDefinitionId();
} else{
//未完结的流程
processDefinitionId=processInstance.getProcessDefinitionId();
Set<String> activtyNames = processInstance.findActiveActivityNames();
activtyName = activtyNames.iterator().next();
}
RepositoryService repositoryService = processEngine.getRepositoryService();
return repositoryService.getActivityCoordinates(processDefinitionId, activtyName);
}
<pre name="code" class="java">/** * @authour wu 根据流程实例ID查询出该流程实例经过的节点的名称 * @Date:2014年10月24日 * @param processId * @return */ public List<CompleteTaskHistory> findHistoryActivityInfo(String processId) { HistoryService historyService = processEngine.getHistoryService(); RepositoryService repositoryService = processEngine.getRepositoryService(); HistoryService hs = processEngine.getHistoryService(); //已完结流程 processInstance为NUll 可从HistoryProcessInstance获得需要的信息 HistoryProcessInstance hpi = hs.createHistoryProcessInstanceQuery().processInstanceId(processId).uniqueResult(); List<HistoryActivityInstance> hisIns = historyService.createHistoryActivityInstanceQuery().processInstanceId(processId).list(); String pdId = hpi.getProcessDefinitionId(); List<CompleteTaskHistory> listHist = new ArrayList<>(); //获得当前活动的节点 ActivityCoordinates nowac= findActivityCoordinates(processId); for (int i = 0; i < hisIns.size(); i++) { HistoryActivityInstance hai = hisIns.get(i); ActivityCoordinates ac= repositoryService.getActivityCoordinates(pdId, hai.getActivityName()); //如果当前历史节点等于活动节点,则不想集合中再次添加 if(ac!=nowac){ //把节点的坐标、宽高加入到CompleteTaskHistory对象中 CompleteTaskHistory cth = jbpmHistoryService.getCompleteTaskHistory(processId, hai.getStartTime().toString(),hai.getActivityName()); cth.setX(ac.getX()); cth.setY(ac.getY()); cth.setWidth(ac.getWidth()); cth.setHeight(ac.getHeight()); listHist.add(cth); } } return listHist; }其中第一个方法是返回当前节点坐标,第二个方法是返回进过节点坐标(包括当前节点、执行人执行时间CompleteTaskHistory是我自己创建的model比ActivityCoordinates多了执行人、执行时间等属性,jbpmHistoryService是通过该节点的processId和start_在jbpm4_hist_actinst表中查出需要的相关信息在联合其它表查出执行人意见等信息),这个操作在action中完成,然后返回到页面中。
Action中代码 需要在struts中配置
/**
* @authour wu 显示流程图
* @Date:2014年10月24日
*/
public void pic(){
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
String processInstanceId = request.getParameter("flow_id");
InputStream inputStream = flowBase.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();
}
}
}
}
}
/** * @authour wu 显示流程坐标 * @Date:2014年10月24日 * @return */ public String viewPic() { HttpServletRequest request = ServletActionContext.getRequest(); String processInstanceId = request.getParameter("flow_id"); // 流程图活动坐标 ActivityCoordinates activityCoordinates = flowBase .findActivityCoordinates(processInstanceId); List<CompleteTaskHistory> ac = flowBase.findHistoryActivityInfo(processInstanceId); /*if(activityCoordinates != null){ ac = flowBase.findHistoryActivityInfo(processInstanceId); ac.remove(activityCoordinates); } */ request.setAttribute("ac", ac); request.setAttribute("activityCoordinates", activityCoordinates); request.setAttribute("flow_id", processInstanceId); return "viewPic"; }其实原理分为两步1、以流的方式读取出流程图片PNG作为背景图片;2、根据xml中记录的坐标在JSP页面使用div画出相应的border边框
红框代表当前节点,红绿相间的边框代表该节点被驳回后,再次走到该节点。如下图:现在流程走到“计划部审批”驳回到“二次审核”