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

背景:

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

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

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

解释说明:

     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的进行了特殊处理,因此此处需要重新生成 流程图片。

 

/**
* 根据流程的key生成图片
* 
* @param request
* @param response
* @param wfKey 流程定义的key
*/
@RequestMapping("/genericImageByWfKey")
public void genericImageByWfKey(HttpServletRequest request, HttpServletResponse response, String wfKey) {
    Context.setProcessEngineConfiguration(processEngineConfiguration);
    RepositoryService repositoryService = this.processEngine.getRepositoryService();
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey(wfKey).latestVersion().singleResult();
    BpmnModel bm = repositoryService.getBpmnModel(pd.getId());
    InputStream is = ProcessDiagramGenerator.generatePngDiagram(bm); // 生成图片,获取图片的输入流
    try {
        int size = is.available();
        byte data[] = new byte[size];
        is.read(data);
        response.setContentType("image/png"); // 设置返回的文件类型
        OutputStream os = response.getOutputStream();
        os.write(data);
        os.flush();
        os.close();
    } catch (IOException e) {
        log.error("读写流程图时出现异常!");
    }
        log.info("end....");
}InputStream is = ProcessDiagramGenerator.generatePngDiagram(bm); // 生成图片,获取图片的输入流
    try {
        int size = is.available();
        byte data[] = new byte[size];
        is.read(data);
        response.setContentType("image/png"); // 设置返回的文件类型
        OutputStream os = response.getOutputStream();
        os.write(data);
        os.flush();
        os.close();
    } catch (IOException e) {
        log.error("读写流程图时出现异常!");
    }
        log.info("end....");
}

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

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

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

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

 

protected static ProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel) {
    // We need to calculate maximum values to know how big the image will be in its entirety
    double minX = Double.MAX_VALUE;
    double maxX = 0;
    double minY = Double.MAX_VALUE;
    double maxY = 0;

    for (Pool pool : bpmnModel.getPools()) {
      GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
      minX = graphicInfo.getX();
      maxX = graphicInfo.getX() + graphicInfo.getWidth();
      minY = graphicInfo.getY();
      maxY = graphicInfo.getY() + graphicInfo.getHeight();
    }
    
    List flowNodes = gatherAllFlowNodes(bpmnModel);
    for (FlowNode flowNode : flowNodes) {

      GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
      
      // width
      if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {
        maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();
      }
      if (flowNodeGraphicInfo.getX() < minX) {
        minX = flowNodeGraphicInfo.getX();
      }
      // height
      if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {
        maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();
      }
      if (flowNodeGraphicInfo.getY() < minY) {
        minY = flowNodeGraphicInfo.getY();
      }

      for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
        List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
        for (GraphicInfo graphicInfo : graphicInfoList) {
          // width
          if (graphicInfo.getX() > maxX) {
            maxX = graphicInfo.getX();
          }
          if (graphicInfo.getX() < minX) {
            minX = graphicInfo.getX();
          }
          // height
          if (graphicInfo.getY() > maxY) {
            maxY = graphicInfo.getY();
          }
          if (graphicInfo.getY()< minY) {
            minY = graphicInfo.getY();
          }
        }
      }
    }
    
    int nrOfLanes = 0;
    for (Process process : bpmnModel.getProcesses()) {
      for (Lane l : process.getLanes()) {
        
        nrOfLanes++;
        
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());
        // // width
        if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {
          maxX = graphicInfo.getX() + graphicInfo.getWidth();
        }
        if (graphicInfo.getX() < minX) {
          minX = graphicInfo.getX();
        }
        // height
        if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {
          maxY = graphicInfo.getY() + graphicInfo.getHeight();
        }
        if (graphicInfo.getY() < minY) {
          minY = graphicInfo.getY();
        }
      }
    }
    
    // Special case, see http://jira.codehaus.org/browse/ACT-1431
    if (flowNodes.size() == 0 && bpmnModel.getPools().size() == 0 && nrOfLanes == 0) {
      // Nothing to show
      minX = 0;
      minY = 0;
    }
    
    return new ProcessDiagramCanvas((int) maxX + 10,(int) maxY + 10, (int) minX, (int) minY);
  }new ProcessDiagramCanvas((int) maxX + 10,(int) maxY + 10, (int) minX, (int) minY);
  }

   2.2 图片的裁剪:

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

  

/**
   * Generates an image of what currently is drawn on the canvas.
   * 
   * Throws an {@link ActivitiException} when {@link #close()} is already
   * called.
   */
  public InputStream generateImage(String imageType) {
    if (closed) {
      throw new ActivitiException("ProcessDiagramGenerator already closed");
    }

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
      // Try to remove white space
      minX = (minX <= 5) ? 5 : minX;
      minY = (minY <= 5) ? 5 : minY;
      BufferedImage imageToSerialize = processDiagram;
      if (minX >= 0 && minY >= 0) {
        // 此处的最小x和最小y减去了5
        imageToSerialize = processDiagram.getSubimage(minX - 5, minY - 5, canvasWidth - minX + 5, canvasHeight - minY + 5); // 此处可以看到,activiti对图像做了裁剪的操作。
      }
      ImageIO.write(imageToSerialize, imageType, out);
    } catch (IOException e) {
      throw new ActivitiException("Error while generating process image", e);
    } finally {
      IoUtil.closeSilently(out);
    }
    return new ByteArrayInputStream(out.toByteArray());
  }       // 此处的最小x和最小y减去了5
        imageToSerialize = processDiagram.getSubimage(minX - 5, minY - 5, canvasWidth - minX + 5, canvasHeight - minY + 5); // 此处可以看到,activiti对图像做了裁剪的操作。
      }
      ImageIO.write(imageToSerialize, imageType, out);
    } catch (IOException e) {
      throw new ActivitiException("Error while generating process image", e);
    } finally {
      IoUtil.closeSilently(out);
    }
    return new ByteArrayInputStream(out.toByteArray());
  }

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

@RequestMapping("/getProcessTrace")
	@ResponseBody
	/**
	 * 获取各个节点的具体的信息
	 * @param wfKey
	 * 		流程定义的key
	 * @return
	 */
	public List> getProcessTrace(String wfKey) throws Exception {
		List> activityInfos = new ArrayList>();
		RepositoryService repositoryService = processEngine.getRepositoryService();
		ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey(wfKey).latestVersion().singleResult();
		ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(pd.getId());
		List activitiList = processDefinition.getActivities();
		InputStream xmlIs = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
		BpmnModel bm = new BpmnXMLConverter().convertToBpmnModel(new InputStreamSource(xmlIs), false, true);

                // 下方使用反射获取最小的x和y,仔细看就会发现调用的是上方2.1节的方法
		Class clazz = Class.forName("org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator");
		Method method = clazz.getDeclaredMethod("initProcessDiagramCanvas", BpmnModel.class);
		method.setAccessible(true); 
		ProcessDiagramCanvas pdc = (ProcessDiagramCanvas) method.invoke(clazz.newInstance(), bm); // 调用方法

		clazz = Class.forName("org.activiti.engine.impl.bpmn.diagram.ProcessDiagramCanvas");
		Field minXField = clazz.getDeclaredField("minX"); // 得到minX字段
		Field minYField = clazz.getDeclaredField("minY");
		minXField.setAccessible(true);
		minYField.setAccessible(true);
		int minX = minXField.getInt(pdc);// 最小的x值  
		int minY = minYField.getInt(pdc); // 最小的y的值


		minX = minX > 0 ? minX - 5 : 0;   // 此处为什么需要减5,上方2.2中activiti源码中有
		minY = minY > 0 ? minY - 5 : 0;
		for (ActivityImpl activity : activitiList) {
			Map activityInfo = new HashMap();
			activityInfo.put("width", activity.getWidth());
			activityInfo.put("height", activity.getHeight());
			activityInfo.put("x", activity.getX() - minX);
			activityInfo.put("y", activity.getY() - minY);
			activityInfo.put("actId", activity.getId());
			activityInfo.put("name", activity.getProperty("name"));  // ActivityImpl 中没有getName方法,所以此处需要这样获取。
			activityInfos.add(activityInfo);
		}
		return activityInfos;
	} // 下方使用反射获取最小的x和y,仔细看就会发现调用的是上方2.1节的方法
		Class clazz = Class.forName("org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator");
		Method method = clazz.getDeclaredMethod("initProcessDiagramCanvas", BpmnModel.class);
		method.setAccessible(true); 
		ProcessDiagramCanvas pdc = (ProcessDiagramCanvas) method.invoke(clazz.newInstance(), bm); // 调用方法

		clazz = Class.forName("org.activiti.engine.impl.bpmn.diagram.ProcessDiagramCanvas");
		Field minXField = clazz.getDeclaredField("minX"); // 得到minX字段
		Field minYField = clazz.getDeclaredField("minY");
		minXField.setAccessible(true);
		minYField.setAccessible(true);
		int minX = minXField.getInt(pdc);// 最小的x值  
		int minY = minYField.getInt(pdc); // 最小的y的值


		minX = minX > 0 ? minX - 5 : 0;   // 此处为什么需要减5,上方2.2中activiti源码中有
		minY = minY > 0 ? minY - 5 : 0;
		for (ActivityImpl activity : activitiList) {
			Map activityInfo = new HashMap();
			activityInfo.put("width", activity.getWidth());
			activityInfo.put("height", activity.getHeight());
			activityInfo.put("x", activity.getX() - minX);
			activityInfo.put("y", activity.getY() - minY);
			activityInfo.put("actId", activity.getId());
			activityInfo.put("name", activity.getProperty("name"));  // ActivityImpl 中没有getName方法,所以此处需要这样获取。
			activityInfos.add(activityInfo);
		}
		return activityInfos;
	}

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

 


	
		
		Insert title here
		
		
	
	
		

   到此,已经完成了。

你可能感兴趣的:(activiti工作流学习)