bpmn转换器
bpmn转换器
本章节为开源版用户自行适配后端提供思路以及为pro用户介绍原理
wflow 流程设计器的数据格式是嵌套结构的json
,后端使用了基于bpmn2.0
的流程引擎 flowable
,数据格式不一致,所以我们需要对流程设计器的json进行转换成flowable
可以接受的格式,这个转换器实现类为 WFlowToBpmnCreator
,内容细节大家可以参考pro实现。
实现原理
首先我们来看一个bpmn.xml 的数据
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_Process_1686014563526" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1686014563526" name="业务流程_1686014563526" isExecutable="true">
<bpmn:startEvent id="Event_1jquky6" name="开始">
<bpmn:outgoing>Flow_1sjxic8</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:userTask id="Activity_1eko0k5" name="审批人1">
<bpmn:incoming>Flow_1sjxic8</bpmn:incoming>
<bpmn:outgoing>Flow_0z7rg7c</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_1gkys96" name="审批人2">
<bpmn:incoming>Flow_0z7rg7c</bpmn:incoming>
<bpmn:outgoing>Flow_1yoq9zl</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_1mun3j2" name="流程结束">
<bpmn:incoming>Flow_1yoq9zl</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1sjxic8" sourceRef="Event_1jquky6" targetRef="Activity_1eko0k5" />
<bpmn:sequenceFlow id="Flow_0z7rg7c" sourceRef="Activity_1eko0k5" targetRef="Activity_1gkys96" />
<bpmn:sequenceFlow id="Flow_1yoq9zl" sourceRef="Activity_1gkys96" targetRef="Event_1mun3j2" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
流程节点布局
</bpmndi:BPMNDiagram>
</bpmn:definitions>
对应上方xml的流程图与wflow流程图为:

对应wflow的json为:
{
"id": "root",
"desc": "任何人",
"name": "发起人",
"type": "ROOT",
"props": {},
"children": {
"id": "node_151977794862",
"parentId": "root",
"props": {},
"type": "APPROVAL",
"name": "审批人1",
"children": {
"id": "node_152038799603",
"parentId": "node_151977794862",
"props": {},
"type": "APPROVAL",
"name": "审批人2",
"children": {}
}
},
"parentId": null
}
那么如何去建立一个对应关系这是最重要的,我们的目的是通过json将其构造成xml,flowable 流程引擎是由java实现的,那么每个xml节点在flowable中都应该有一个java类与之对应,我们就是根据构造出这些节点,去构造xml流程图。
案例教程
我们可以在先后端引入 flowable 的maven依赖,再在IDEA里面尝试打出如下名称:
可以发现,在 org.flowable.bpmn.model
包下都有对应的类与bpmn里面的节点一一对应,那么好办了,我们梳理下刚才用到的这几个节点。
- StartEvent:开始事件
- EndEvent:结束事件
- SequenceFlow:流程连接线
- UserTask:用户任务节点
暂且以这几个节点为例,我们来根据上述分析尝试构造一个流程图对应的 model
//开始节点
StartEvent start = new StartEvent();
start.setId("start");
//发起人
UserTask task1 = new UserTask();
task1.setId("root");
//审批1
UserTask task1 = new UserTask();
task1.setId("node_151977794862");
//审批2
UserTask task2 = new UserTask();
task2.setId("node_152038799603");
//结束节点
EndEvent end = new EndEvent();
end.setId("end");
//构造连接线连接各个节点
SequenceFlow line1 = new SequenceFlow();
line1.setId("start_root");
line1.setSourceRef("start"); //从哪个节点
line1.setTargetRef("root"); //连接到哪个节点
// ....后续的几个节点连接都以这种方式做,不做赘述了
//构建process节点
Process process = new Process();
process.setId("process_id");
process.setName("流程图");
//把之前new出来的节点和连接线都添加到process节点内
process.addFlowElement(start);
process.addFlowElement(task1);
// ...... 其他节点
//构建Bpmn模型
BpmnModel bpmnModel = new BpmnModel();
bpmnModel.addProcess(process);
// Bpmn xml自动生成布局及布局节点位置
new BpmnAutoLayout(bpmnModel).execute();
//转换成bpmn.xml格式字符串并打印
System.out.println(new BpmnXMLConverter().convertToXML(bpmnModel));
为了将上述的节点找出来,我们肯定是要和 wflow 的 json对应,json是嵌套的结构,也就是说下级节点是上级节点内部 children
字段的子项,那么我们就需要遍历所有的节点,使用递归即可,简单示例如下:
public static void main(String[] args) {
String json = "流程json";
forEachNode(JSONObject.parseObject(json), node -> {
//在这里进行每个节点的处理,去new出那些节点,然后连线
});
}
private static void forEachNode(JSONObject node, Consumer<? super JSONObject> action){
JSONObject childNode = node.getJSONObject("children");
action.accept(childNode);
forEachNode(childNode, action);
}
进阶
按照上述方法我们生成了一个bpmn的流程图xml,但是仅仅是xml,无法创建用户任务,因为没有给节点设置审批人等属性,那么我们可以进行设置,这里演示一个静态的设置
//审批1
UserTask task = new UserTask();
task.setName("审批人1");
task.setId("node_151977794862");
task.setAssignee("审批人ID"); //指定审批人ID
这样就构造好了,为适配节点指定了一个审批人,当然,这里还可以指定为UEL表达式,参考: flowable文档-用户任务
这样我们就完成了一个简单的串行无分支流程的转换,当然实际流程是比较复杂的,但是原理过程就是这么简单,我们需要去由简入深,不要一上来就去构造带分支的
带分支的构造方式也是递归,主要是并行网关和条件网关,带分支的话连线就比较复杂了,大家自行琢磨😘
调试技巧
我们再调试的时候,将生成的流程 xml 输出到一个文件内,将该xml
导入到 bpmn.js
的 设计器内,看下回显出来的流程图对不对,还缺少哪些东西。
自己找一个在线的那种或者自己部署一个,这里有个在线的Vite Vue Process Designer (miyuesc.github.io)
在生成流程图 new BpmnAutoLayout(bpmnModel).execute();
这一步时会执行一个基本校验,如果流程图构造连接关系不对,就会抛异常,这时候要检查下各个节点是不是正确进行连接了,debug 查看 process对象里面添加的节点关系,如果节点都有,那么就是查看连接关系。