activiti流程图上获取各节点的信息获取

背景:

        由于项目的需要,当用户在查看流程图时,当点击某个流程图片上的节点时,需要提示一些信息,这就需要获取各个节点的信息,此处获取id和name的值。         

        activiti流程图上获取各节点的信息获取_第1张图片   activiti流程图上获取各节点的信息获取_第2张图片

       注意这个并不是流程图的高亮,即当点击网点申请环节时,获取该节点的id和name,即B001和网点申请,点击部门申请时,获取B002和部门经理审批

解释说明: 博文来源:http://www.fhadmin.org/webnewsdetail1.html

     1.下方说的x和y:     

     

      2.流程定义的key: 即为下方id的值

     

     3.节点的id和name的值:

     

难点分析:

      由 于activiti在部署时,如果没有流程图片,则activiti会自动生成一张图片,而我们项目中使用的是activiti modeler实现的在线画流程图,部署时没有图片,是由activiti自动生成。而activiti在生成图片时,会对图片做一个裁剪操作,所有最终 各个节点的坐标会比实际的要小。

      (即:activiti自动生成的图片,会做一个裁剪操作,各个节点实际的x和y的值比xml文件中的要小)

        而我们的难点在于,各个节点实际坐标的获取。如下图所示:         

       activiti流程图上获取各节点的信息获取_第3张图片  

        即我们实际上获取的坐标需要在减去一个minX和minY,得到的才是我们的各个节点实际的坐标。

 

步骤分析:

      1.根据流程定义的key,重新生成流程图片,而不是获取流程图片。

      2.还是根据流程定义的key,获取各个节点的信息。(此处需要注意的是各个节点实际的x和y的值的获取的方法

      3.在jsp页面上使用绝对定位,给点击的节点加上高亮。

 

步骤实现:  1.根据流程定义的key,重新生成流程图片,而不是获取流程图片。

    此处重新生成图片的原因:

           因为有些时候我们在部署流程时,将图片也部署进去了,此时使用的就是自己的图片,activiti不会进行图片的裁剪。因为我在下一步获取流程节点的信息时,对x和y的进行了特殊处理,因此此处需要重新生成 流程图片。

 

Java代码   收藏代码  博文来源:http://www.fhadmin.org/webnewsdetail1.html
  1. /** 
  2. * 根据流程的key生成图片 
  3.  
  4. * @param request 
  5. * @param response 
  6. * @param wfKey 流程定义的key 
  7. */  
  8. @RequestMapping("/genericImageByWfKey")  
  9. public void genericImageByWfKey(HttpServletRequest request, HttpServletResponse response, String wfKey) {  
  10.     Context.setProcessEngineConfiguration(processEngineConfiguration);  
  11.     RepositoryService repositoryService = this.processEngine.getRepositoryService();  
  12.     ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey(wfKey).latestVersion().singleResult();  
  13.     BpmnModel bm = repositoryService.getBpmnModel(pd.getId());  
  14.     "color: #ff6600;">InputStream is = ProcessDiagramGenerator.generatePngDiagram(bm); // 生成图片,获取图片的输入流  
  15.     try {  
  16.         int size = is.available();  
  17.         byte data[] = new byte[size];  
  18.         is.read(data);  
  19.         response.setContentType("image/png"); // 设置返回的文件类型  
  20.         OutputStream os = response.getOutputStream();  
  21.         os.write(data);  
  22.         os.flush();  
  23.         os.close();  
  24.     } catch (IOException e) {  
  25.         log.error("读写流程图时出现异常!");  
  26.     }  
  27.         log.info("end....");  
  28. }  

 2.还是根据流程定义的key,获取各个节点的信息。

    获取各个节点的坐标之前,我们先看一下activiti中是如果获取到最小的x和y的,然后是如何裁剪图片的

    2.1获取节点包括线的最小x和最小y :

   跟踪acticiti的源码可以发现,最小x和y的获取(org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator.initProcessDiagramCanvas(BpmnModel)

 

Java代码   收藏代码
  1. protected static ProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel) {  
  2.     // We need to calculate maximum values to know how big the image will be in its entirety  
  3.     double minX = Double.MAX_VALUE;  
  4.     double maxX = 0;  
  5.     double minY = Double.MAX_VALUE;  
  6.     double maxY = 0;  
  7.   
  8.     for (Pool pool : bpmnModel.getPools()) {  
  9.       GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());  
  10.       minX = graphicInfo.getX();  
  11.       maxX = graphicInfo.getX() + graphicInfo.getWidth();  
  12.       minY = graphicInfo.getY();  
  13.       maxY = graphicInfo.getY() + graphicInfo.getHeight();  
  14.     }  
  15.       
  16.     List flowNodes = gatherAllFlowNodes(bpmnModel);  
  17.     for (FlowNode flowNode : flowNodes) {  
  18.   
  19.       GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());  
  20.         
  21.       // width  
  22.       if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {  
  23.         maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();  
  24.       }  
  25.       if (flowNodeGraphicInfo.getX() < minX) {  
  26.         minX = flowNodeGraphicInfo.getX();  
  27.       }  
  28.       // height  
  29.       if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {  
  30.         maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();  
  31.       }  
  32.       if (flowNodeGraphicInfo.getY() < minY) {  
  33.         minY = flowNodeGraphicInfo.getY();  
  34.       }  
  35.   
  36.       for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {  
  37.         List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());  
  38.         for (GraphicInfo graphicInfo : graphicInfoList) {  
  39.           // width  
  40.           if (graphicInfo.getX() > maxX) {  
  41.             maxX = graphicInfo.getX();  
  42.           }  
  43.           if (graphicInfo.getX() < minX) {  
  44.             minX = graphicInfo.getX();  
  45.           }  
  46.           // height  
  47.           if (graphicInfo.getY() > maxY) {  
  48.             maxY = graphicInfo.getY();  
  49.           }  
  50.           if (graphicInfo.getY()< minY) {  
  51.             minY = graphicInfo.getY();  
  52.           }  
  53.         }  
  54.       }  
  55.     }  
  56.       
  57.     int nrOfLanes = 0;  
  58.     for (Process process : bpmnModel.getProcesses()) {  
  59.       for (Lane l : process.getLanes()) {  
  60.           
  61.         nrOfLanes++;  
  62.           
  63.         GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());  
  64.         // // width  
  65.         if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {  
  66.           maxX = graphicInfo.getX() + graphicInfo.getWidth();  
  67.         }  
  68.         if (graphicInfo.getX() < minX) {  
  69.           minX = graphicInfo.getX();  
  70.         }  
  71.         // height  
  72.         if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {  
  73.           maxY = graphicInfo.getY() + graphicInfo.getHeight();  
  74.         }  
  75.         if (graphicInfo.getY() < minY) {  
  76.           minY = graphicInfo.getY();  
  77.         }  
  78.       }  
  79.     }  
  80.       
  81.     // Special case, see http://jira.codehaus.org/browse/ACT-1431  
  82.     if (flowNodes.size() == 0 && bpmnModel.getPools().size() == 0 && nrOfLanes == 0) {  
  83.       // Nothing to show  
  84.       minX = 0;  
  85.       minY = 0;  
  86.     }  
  87.       
  88.     return "color: #ff0000;">new ProcessDiagramCanvas((int) maxX + 10,(int) maxY + 10, (int) minX, (int) minY);  
  89.   }  

   2.2 图片的裁剪:

   还是activiti的源码:(org.activiti.engine.impl.bpmn.diagram.ProcessDiagramCanvas.generateImage(String)

  

Java代码   收藏代码 博文来源:http://www.fhadmin.org/webnewsdetail1.html
  1. /** 
  2.    * Generates an image of what currently is drawn on the canvas. 
  3.    *  
  4.    * Throws an {@link ActivitiException} when {@link #close()} is already 
  5.    * called. 
  6.    */  
  7.   public InputStream generateImage(String imageType) {  
  8.     if (closed) {  
  9.       throw new ActivitiException("ProcessDiagramGenerator already closed");  
  10.     }  
  11.   
  12.     ByteArrayOutputStream out = new ByteArrayOutputStream();  
  13.     try {  
  14.       // Try to remove white space  
  15.       minX = (minX <= 5) ? 5 : minX;  
  16.       minY = (minY <= 5) ? 5 : minY;  
  17.       BufferedImage imageToSerialize = processDiagram;  
  18.       if (minX >= 0 && minY >= 0) {  
  19.  "font-size: 16px; color: #ff0000;">       // 此处的最小x和最小y减去了5  
  20.         "color: #ff0000;">imageToSerialize = processDiagram.getSubimage(minX - 5, minY - 5, canvasWidth - minX + 5, canvasHeight - minY + 5); // 此处可以看到,activiti对图像做了裁剪的操作。  
  21.       }  
  22.       ImageIO.write(imageToSerialize, imageType, out);  
  23.     } catch (IOException e) {  
  24.       throw new ActivitiException("Error while generating process image", e);  
  25.     } finally {  
  26.       IoUtil.closeSilently(out);  
  27.     }  
  28.     return new ByteArrayInputStream(out.toByteArray());  
  29.   }  

    2.3 我们自己的各个节点的信息获取

Java代码   收藏代码
  1. @RequestMapping("/getProcessTrace")  
  2.     @ResponseBody  
  3.     /** 
  4.      * 获取各个节点的具体的信息 
  5.      * @param wfKey 
  6.      *      流程定义的key 
  7.      * @return 
  8.      */  
  9.     public List> getProcessTrace(String wfKey) throws Exception {  
  10.         List> activityInfos = new ArrayList>();  
  11.         RepositoryService repositoryService = processEngine.getRepositoryService();  
  12.         ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey(wfKey).latestVersion().singleResult();  
  13.         ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(pd.getId());  
  14.         List activitiList = processDefinition.getActivities();  
  15.         InputStream xmlIs = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());  
  16.         BpmnModel bm = new BpmnXMLConverter().convertToBpmnModel(new InputStreamSource(xmlIs), falsetrue);  
  17.   
  18.                "color: #ff0000;"> // 下方使用反射获取最小的x和y,仔细看就会发现调用的是上方2.1节的方法  
  19.         "color: #ff0000;">Class clazz = Class.forName("org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator");  
  20.         Method method = clazz.getDeclaredMethod("initProcessDiagramCanvas", BpmnModel.class);  
  21.         method.setAccessible(true);   
  22.         ProcessDiagramCanvas pdc = (ProcessDiagramCanvas) method.invoke(clazz.newInstance(), bm); // 调用方法  
  23.   
  24.         clazz = Class.forName("org.activiti.engine.impl.bpmn.diagram.ProcessDiagramCanvas");  
  25.         Field minXField = clazz.getDeclaredField("minX"); // 得到minX字段  
  26.         Field minYField = clazz.getDeclaredField("minY");  
  27.         minXField.setAccessible(true);  
  28.         minYField.setAccessible(true);  
  29.         int minX = minXField.getInt(pdc);// 最小的x值    
  30.         int minY = minYField.getInt(pdc); // 最小的y的值  
  31.   
  32.   
  33.         minX = minX > 0 ? minX - 5 : 0;   "color: #ff0000;">// 此处为什么需要减5,上方2.2中activiti源码中有  
  34.         minY = minY > 0 ? minY - 5 : 0;  
  35.         for (ActivityImpl activity : activitiList) {  
  36.             Map activityInfo = new HashMap();  
  37.             activityInfo.put("width", activity.getWidth());  
  38.             activityInfo.put("height", activity.getHeight());  
  39.             activityInfo.put("x", activity.getX() - minX);  
  40.             activityInfo.put("y", activity.getY() - minY);  
  41.             activityInfo.put("actId", activity.getId());  
  42.             "color: #ff0000;">activityInfo.put("name", activity.getProperty("name"));  // ActivityImpl 中没有getName方法,所以此处需要这样获取。  
  43.             activityInfos.add(activityInfo);  
  44.         }  
  45.         return activityInfos;  
  46.     }  

   3.在jsp页面上使用绝对定位,给点击的节点加上高亮。

 

Java代码   收藏代码 博文来源:http://www.fhadmin.org/webnewsdetail1.html
  1.   
  2.       
  3.         "Content-Type" content="text/html; charset=UTF-8">  
  4.         Insert title here  
  5.         "text/css">  
  6.             .activity-attr{border-radius: 10px; border: 3px solid red; transition:ease-out 0.5s; box-shadow:0px 0px 9px red;}  
  7.             #processKey{color: red;}  
  8.             #flowImageAndRect{position: relative;overflow: scroll;height:300px; heibackground-image: url('${ctx}/resources/images/workflow/grid_10.png')}  
  9.             body,html{margin: 0px;padding:0px;}  
  10.           
  11.         "text/javascript">  
  12.             $(function(){  
  13.                 var wfKey = '${param.wfKey}'// 流程定义的key  
  14.                 var $flowImageAndRect = $('#flowImageAndRect');  
  15.                 $('#processKey').html('流程定义的key --> ' + wfKey);  
  16.                 // 加载流程图片  
  17.                 loadProcessImage(wfKey,$flowImageAndRect);  
  18.                 // 加载各节点信息,最终实现,在点击图片上的各节点时,出现高亮  
  19.                 setTimeout(function(){  
  20.                     loadProcessTrace(wfKey,$flowImageAndRect);  
  21.                 },200);  
  22.                   
  23.                 var $revClickRect = null// 上次点击的图形  
  24.                 // 绑定click事件,点击实现,只有点击的不是同一个时,才显示红色的边框(如果多次点击同一个,红色的边框只出现一次)  
  25.                 $('#flowImageAndRect').off('click').on('click','.activity-attr',function(e){  
  26.                     var $this = $(this);  
  27.                     var prevFlag = false// 是上一个图形,避免多次点击同一个  
  28.                     if($revClickRect){ // 说明不是第一次点击  
  29.                         prevFlag = ($revClickRect.attr('actId')!=$this.attr('actId')) ? false : true;// 说明2次点击的不是同一个  
  30.                         if(!prevFlag)  
  31.                             $revClickRect.css('opacity','0');  
  32.                     }  
  33.                     if(!prevFlag){ // 此处可以请求后台,加载相关的数据(多次点击同一个,下方可确保只执行一次)  
  34.                         $this.css('opacity','1'); // 显示当前的  
  35.                         $revClickRect = $this// 将当前设置为上次点击的  
  36.                         $('#info').html('节点ID --> ' + $this.attr('actId') + "  |  " + "节点名称 --> " + $this.attr('name'));  
  37.                     }  
  38.                 });  
  39.             });  
  40.                
  41.             /** 
  42.              * 加载图片 
  43.              */  
  44.             function loadProcessImage(wfKey,$flowImageAndRect){  
  45.                 var imageUrl = '${ctx}/workflow/monitor/genericImageByWfKey.do?wfKey='+wfKey;  
  46.                 // 加载图片  
  47.                 $('',{  
  48.                     "src" : imageUrl,  
  49.                     "alt" : ''  
  50.                 }).appendTo($flowImageAndRect);   
  51.             }  
  52.               
  53.             /** 
  54.              * 加载流程中各节点的信息  
  55.              * @param wfKey : 流程定义的key 
  56.              * @param $flowImageAndRect  
  57.              */  
  58.             function loadProcessTrace(wfKey,$flowImageAndRect){  
  59.                 var traceUrl = '${ctx}/workflow/monitor/getProcessTrace.do?wfKey='+wfKey;  
  60.                 $.getJSON(traceUrl,function(infos){  
  61.                     var html = "";  
  62.                     $.each(infos,function(i,v){  
  63.                         // 矩形的div  
  64.                         var $div = $('
    ', {  
  65.                                 'class''activity-attr'  
  66.                         }).css({  
  67.                             position: 'absolute',  
  68.                             left: v.x,  
  69.                             top: v.y,  
  70.                             width: v.width - 3,  
  71.                             height:v.height - 3,  
  72.                             opacity: 0,  
  73.                             zIndex: 100,  
  74.                     cursor : 'pointer'  
  75.                         }).attr({'actId':v.actId,'name':v.name});  
  76.                         html += $div.prop("outerHTML");  
  77.                     });  
  78.                     $('',{'id':'processRect'}).html(html).appendTo($flowImageAndRect);  
  79.                 });  
  80.             }  
  81.           
  82.       
  83.       
  84.         "main">  
  85.             "flowImageAndRect">  
  86.                   
  87.             
  
  •               
  •             "processKey" style="font-size: 52px;text-align: center;margin-bottom: 50px;">  
  •               
  •             
  •   
  •               
  •             "info" style="font-size: 52px;text-align: center;">  
  •                   
  •             
  •   
  •         
  •   
  •       
  •   
  •    到此,已经完成了。

    你可能感兴趣的:(activiti流程图上获取各节点的信息获取)