activiti学习6:启动流程后动态获取流程图

上一篇博客中介绍了activiti如何开启流程和让流程前进,这次来学习下如何动态的获取activiti的流程图

本文中使用的activiti版本是5.22.0

一、绘图原理

activiti中提供了一个可以用来绘制流程图的类DefaultProcessDiagramGenerator,这个类在5.22.0及以上的版本中

是以一个单独jar包的方式提供的,所以还需要引入相应的依赖。

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-image-generator</artifactId>
    <version>5.22.0</version>
</dependency>

使用时先创建这个类的对象,

//这个类在5.22.0往上的版本中才有
DefaultProcessDiagramGenerator diagramGenerator=new DefaultProcessDiagramGenerator();

然后调用画图方法

diagramGenerator.generateDiagram(bpmnModel, imageType, highLightedActivities);

其中的几个参数:

bpmnModel:当前流程对应的流程模型,可以通过repositoryService.getBpmnModel(processDefinitionId)获取

imageType:图片类型,jpg,png等

highLightedActivities:需要高亮显示的节点的id

二、根据流程定义id绘图

根据流程定义表act_re_procdef的主键id绘图,这时可以没有流程,只要流程图成功部署了就会产生act_re_procdef表的记录。所以也就不存在节点高亮的问题,因为这个图和流程实例无关。

	@Test
	public void test1() throws Exception {
		
		//根据流程定义id来获取BpmnModel对象
		String processDefinitionId="process:2:4304";
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
		//这个类在5.22.0往上的版本中才有
		DefaultProcessDiagramGenerator diagramGenerator=new DefaultProcessDiagramGenerator();
		//绘制bpmnModel代表的流程的流程图
		InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", new ArrayList<String>());
		FileOutputStream output=new FileOutputStream(new File("d:/test.png"));
		IOUtils.copy(inputStream, output);
		System.out.println("输出完成");
	}

注意这里generateDiagram()方法的第3个参数传了一个空list,这个list表示要高亮显示的节点的id集合。也就是流程图中每一个任务的id

三、根据流程实例id绘图

3.1 基本原理

上面已经实现了根据processDefinitionId画图。根据processInstanceId画图时,其实是先根据processInstanceId查询到对应的流程实例对象ProcessInstance,

然后通过流程实例对象获取到processDefinitionId,使用其中的get方法processInstance.getProcessDefinitionId()

再想办法获取到需要高亮显示的节点的id:当前节点+走过的节点。

3.2 当前节点的获取

使用runtimeService服务组件的方法来获取

String executionId=processInstance.getId();
List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);

activeActivityIds这个list就是当前节点的id集合,如果是并行流程会有多个,其他情况只有一个。

3.3 走过的节点的获取

走过的节点需要从activiti的历史行为表act_hi_actinst中获取。流程的行为数据记录在该表中,当流程进行到一个节点时,该表中会记录流程节点的信息,包括节点id,名称等。其中有一个ACT_ID_ 就代表流程图上对应节点的id

也就是需要高亮显示的节点id

所以我们要做的就是从这张表中查询到这个数据。activiti已经提供了查询这张表的api,可以通过historyService这个服务组件来获取

//得到已经走过的节点的id集合
		HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
		List<HistoricActivityInstance> historicActivityInstanceList = historicActivityInstanceQuery.processInstanceId(processInstanceId).list();
		for(HistoricActivityInstance hi:historicActivityInstanceList) {
			String taskKey=hi.getActivityId();
			activeActivityIds.add(taskKey);
		}

以上代码先查询出ACT_ID_ ,再把它们添加到需要高亮显示的集合activeActivityIds中

3.4 绘图

DefaultProcessDiagramGenerator defaultProcessDiagramGenerator=new DefaultProcessDiagramGenerator();
//获取流程图的输入流
InputStream inputStream = defaultProcessDiagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds);
//输出图片到指定路径
IOUtils.copy(inputStream, new FileOutputStream(new File("d:/test2.png")));
System.out.println("输出成功");

这样绘制出的流程图上已经走过的节点就会被高亮显示。

如果流程图的名称中含有中文,上边的绘图方法绘制出的流程图上中文会乱码,这是因为没有指定字体,activiti默认使用的字体不支持中文,所以可以使用此类中能指定字体的重载方法。

  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, 
      String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
    
    return generateDiagram(bpmnModel, imageType, Collections.<String>emptyList(), Collections.<String>emptyList(), 
        activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor);
  }

3.5 获取走过的流程连线

上边3.3已经获取到了走过的流程节点,其实还可以使用Bpmnmodel对象进一步获取到走过的流程连线。

原理就是参考上边画图方法的源码找到它获取连接的方法进行模仿。

// Draw activities and their sequence-flows
    for (Process process: bpmnModel.getProcesses()) {
      for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) {
        drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor);
      }
    }

可以看到是通过bpmnModel对象获取到process,然后再获取到FlowNode对象,流程活动的绘制就是基于这个flowNode。FlowNode对象中有两个属性存储了流程活动的出口线和入口线。

public abstract class FlowNode extends FlowElement {
  //省略其余代码
  protected List<SequenceFlow> incomingFlows = new ArrayList<SequenceFlow>();
  protected List<SequenceFlow> outgoingFlows = new ArrayList<SequenceFlow>();
}

四、总结

绘制流程图的原理是使用DefaultProcessDiagramGenerator类中的方法

这个类在一个单独的jar中提供,需要新添加依赖

要高亮显示某些节点,就给画图方法中传入节点id的集合。