一.简介
通过代码绘制一张流程图,并设置成高亮。
首先先来看一下绘制出来的效果图,截图如下:
已经执行的节点和连线用红色标记出来,大致上就是这么一个效果。
二.怎么实现
将一个流程图绘制成图片,相关的 API 在 flowable 中其实都是有提供的,流程图片的绘制,是根据流程的定义来绘制的,所以只需要提供一个流程定义的 ID 即可,代码如下:
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey("ExclusiveGatewayDemo01").latestVersion().singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(pd.getId());
DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
InputStream inputStream = generator.generatePngDiagram(bpmnModel, 1.0, true);
FileUtils.copyInputStreamToFile(inputStream, new File("/Users/hx/Downloads/test.png"));
来看下这段代码的释义:
- 查找到流程定义对象。
- 根据流程定义对象,获取到一个 BpmnModel 对象。
- 创建一个图片生成器对象 DefaultProcessDiagramGenerator。
- 调用 generatePngDiagram 方法生成这个流程定义所对应的图片,参数有三个,分别是:前面查询到的 bpmnModel 对象;缩放因子以及是否在绘制流程图的时候,在连线上加上描述文字,generatePngDiagram 方法的返回值则是一个输入流。
- 将这个输入流打印出来,就是一张图片了。
根据上面这段代码,执行结果如下:
可以看到,这就是普通的流程图,没有高亮。
如果希望已经执行的节点变成高亮的,那么可以使用如下方法:
来看下这段代码的释义:
- 流程的 bpmnModel 对象。
- 生成的图片类型。
- 高亮的活动节点。
- 高亮的连线。
- 缩放因子。
- 是否在绘制连线的时候添加文字描述。
这里的关键就是第三个和第四个参数。这个流程图中哪些节点哪些连线需要高亮,我们将之列出来即可。
三.扩展
根据之前文章中的介绍,一个流程在执行过程中的活动信息,都是保存在 ACT_RU_ACTINST 表中,所以只需要根据流程实例的 ID 在ACT_RU_ACTINST 表中查询到即可,代码如下:
@Test
void test01() throws IOException {
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey("ExclusiveGatewayDemo01").latestVersion().singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(pd.getId());
ProcessInstance pi = runtimeService.createProcessInstanceQuery().singleResult();
List<String> highLightedActivities = new ArrayList<>();
List<String> hightLightedFlows = new ArrayList<>();
double scaleFactor = 1.0;
boolean drawSqquenceFlowNameWithNoLabelDI = true;
if (pi == null) {
return;
}
List<ActivityInstance> list = runtimeService.createActivityInstanceQuery().list();
for (ActivityInstance ai : list) {
if (ai.getActivityType().equals("sequenceFlow")) {
hightLightedFlows.add(ai.getActivityId());
} else {
highLightedActivities.add(ai.getActivityId());
}
}
DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
InputStream inputStream = generator.generateDiagram(bpmnModel, "PNG", highLightedActivities, hightLightedFlows, scaleFactor, drawSqquenceFlowNameWithNoLabelDI);
FileUtils.copyInputStreamToFile(inputStream, new File("/Users/sang/Downloads/1.png"));
}
这里使用 highLightedActivities 和 hightLightedFlows 两个集合,分别存一个流程已经执行的活动 ID 和连线的 ID。
通过 runtimeService.createActivityInstanceQuery().list(); 来查询到所有已经执行的活动,然后遍历,遍历的时候注意区分是不是 sequenceFlow,如果是 sequenceFlow 则将之添加到 hightLightedFlows 集合中,否则将之添加到 highLightedActivities 结合中。
最终,执行生成的图片就是本文最开始大家看到的图片。
但是呢。按照上面这种方式,对于一个已经执行完毕的流程来说,就画不出来流程图了,因为当一个流程执行完毕之后,ACT_RU_ACTINST 表中的数据就会自动清空。
不过根据前面文章的介绍,执行完毕的活动信息还可以去 ACT_HI_ACTINST 表中进行查询,因此,这个流程图还可以这样画,代码如下:
@Test
void test05() throws IOException {
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey("ExclusiveGatewayDemo01").latestVersion().singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(pd.getId());
HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().singleResult();
if (hpi == null) {
return;
}
List<String> highLightedActivities = new ArrayList<>();
List<String> hightLightedFlows = new ArrayList<>();
double scaleFactor = 1.0;
boolean drawSqquenceFlowNameWithNoLabelDI = true;
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processInstanceId(hpi.getId()).list();
for (HistoricActivityInstance hai : list) {
if (hai.getActivityType().equals("sequenceFlow")) {
hightLightedFlows.add(hai.getActivityId());
} else {
highLightedActivities.add(hai.getActivityId());
}
}
DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
InputStream inputStream = generator.generateDiagram(bpmnModel, "PNG", highLightedActivities, hightLightedFlows, scaleFactor, drawSqquenceFlowNameWithNoLabelDI);
FileUtils.copyInputStreamToFile(inputStream, new File("/Users/sang/Downloads/1.png"));
}
可以看到,当一个流程实例执行完毕的时候,我们可以去历史表中查询这个流程实例,同时也去历史表中查询这个流程实例所执行过的活动 ID,找到之后,还是按照之前的办法,填充给 hightLightedFlows 和 highLightedActivities 两个变量。最终绘制出来的流程图如下图:
《肖申克的救赎》
生命可以归结为一种简单的选择:要么忙于生存,要么赶着去死。
懦怯囚禁人的灵魂,希望可以感受自由。强者自救,圣者渡人。
希望是件美丽的东西,也许是最好的东西。美好的东西是永远不会死的。
每个人都是自己的上帝。如果你自己都放弃自己了,还有谁会救你?
《熔炉》
我们一路奋战,不是为了能改变世界,而是为了不让世界改变我们。
现实如水母,看似美好无害实质总是致命伤人。
我们来到世界上,都是孤独的旅行,即使身边有人相伴,最终也会各奔东西!
世界上最美丽最珍贵的,反而是听不见且看不清的,只有用心才能感受得到。
《教父》
人可以不断犯错,但绝不能犯要命的错。
不要憎恨你的敌人,那会影响你的判断力。
人并非生来就伟大,而是越活越伟大。
《活着》
人是为了活着本身而活着,而不是为了活着之外的任何事物而活着。
以笑的方式哭,在死亡的伴随下活着。
没有什么比时间更具有说服力了,因为时间无需通知我们就可以改变一切。
你的命是爹娘给的,你不要命了也得先去问问他们。
《我不是药神》
世界上只有一种病,穷病,这种病你没法治,你也治不过来。
人间最高贵的是善良,是对生命的致敬。
《指环王》
把手握紧,里面什么也没有;把手放开,你得到的是一切。
我宁愿和你共度凡人短暂的一生,也不愿一个人看尽这世界的沧海桑田。
20.幸福的家庭都是相似的,不幸的家庭各有各的不幸。
或许有一天,人类变得萎缩懦弱,舍弃朋友,断绝友谊,但今天决不会这样。
《饮食男女》
22.人生不能像做菜,把所有的材料都准备好了才下锅。
什么叫做“可惜”啊,要心中有个“惜”字儿,才知道可惜。
其实一家人,住在一个屋檐下,照样可以各过各的日子,可是从心里产生的那种顾忌,才是一个家之所以为家的意义。
《让子弹飞》
世界上本没有路,有了腿便有了路。
如果你活着,早晚都会死;如果你死了,你就永远活着。
赚钱嘛,不寒碜