手把手教你通过JSON Schema判断BpmnJS元素属性结构~
前言
在上一篇文章 手把手教你玩转BpmnJS元素属性更新 一文中,跟大家讲解了 如何通过已有的JSON schema 定义与完整 XML 来解析属性结构 和 通过两个官方 API 更新属性的方式及注意事项。
那么假设现在只有一个 JSON Schema 文件,怎么判断属性的构成呢?文本就带大家分析 如何从JSON Schema 判断属性结构。
1. 分析 JSON Schema
该文件的每个字段的具体定义和编写方式,具体请查看 BpmnJS自定义描述文件说明。但是因为平时了解到大家对自定义这一块一般需求比较少,所以这里就用 camunda 团队新出的zeebe引擎来举例吧,这也是讨论群里一个小伙伴问我的问题。
完整的 JSON 文件请查看bpmn-process-designer/packages/moddle-extensions/zeebe.json,这里节选了ioMapping 输入输出配置
{
types: [
{
"name": "ZeebeServiceTask",
"extends": [
"bpmn:ServiceTask",
"bpmn:BusinessRuleTask",
"bpmn:ScriptTask",
"bpmn:SendTask",
"bpmn:EndEvent",
"bpmn:IntermediateThrowEvent"
],
"properties": [
{
"name": "retryCounter",
"type": "String",
"isAttr": true
}
]
},
{
"name": "IoMapping",
"superClass": [
"Element"
],
"properties": [
{
"name": "ioMapping",
"type": "IoMapping"
},
{
"name": "inputParameters",
"isMany": true,
"type": "Input"
},
{
"name": "outputParameters",
"isMany": true,
"type": "Output"
}
],
"meta": {
"allowedIn": [
"bpmn:CallActivity",
"bpmn:Event",
"bpmn:ReceiveTask",
"zeebe:ZeebeServiceTask",
"bpmn:SubProcess"
]
}
},
{
"name": "InputOutputParameter",
"properties": [
{
"name": "source",
"isAttr": true,
"type": "String"
},
{
"name": "target",
"isAttr": true,
"type": "String"
}
]
},
{
"name": "Input",
"superClass": [
"InputOutputParameter"
],
"meta": {
"allowedIn": [
"bpmn:CallActivity",
"zeebe:ZeebeServiceTask",
"bpmn:SubProcess"
]
}
},
{
"name": "Output",
"superClass": [
"InputOutputParameter"
],
"meta": {
"allowedIn": [
"bpmn:CallActivity",
"bpmn:Event",
"bpmn:ReceiveTask",
"zeebe:ZeebeServiceTask",
"bpmn:SubProcess"
]
}
}
]
}
🚀 这里也算是一点小技巧:只要是 types 数组中的某一个定义的properties 属性配置中,如果这个属性的 type 不是 Number、Boolean、String 这几个基础类型,而是 JSON Schema 中定义的类型的话,通常这个属性都是绑定一个 通过 moddle.create 创建的对应类型的实例
1.1 分析 IoMapping
首先查看这个类型的 supperClass 或者 extends 字段,这里定义的是supperClass:[Element],说明这个属性基本上在 XML 文件中都体现为一个标签,并且标签名为zeebe:ioMapping。
然后就是 meta 字段,一般这个字段里面会有一个 allowedIn 的数组格式的字段,表示 该属性或者标签(IoMapping)允许被配置/插入哪些类型的元素/标签中,通过 通配符 * 表示允许插入所有标签/属性中。此时根据配置 IoMapping 标签可以被插入到 SubProcess 子流程、CallActivity 调用任务、zeebe:ZeebeServiceTask Zeebe服务任务中。
而zeebe:ZeebeServiceTask的定义中,则是用extend来 扩展原来的ServiceTas等类型元素的,所以IoMapping 定义里 allowedIn 中的 ZeebeServiceTask 其实就可以理解为 ServiceTask 等元素的替代指示。
最后分析 properties 配置,可以看到IoMapping 接收三个属性配置:
- ioMapping:类型就是IoMapping,表示这个标签内部还可以插入 IoMapping 标签,即支持嵌套
- inputParameters:类型为Input,且isMany 为 true,表示这里是一个 数组形式,在 js 中体现为**
inputParameters: []
** - outputParameters:类型为Output,其他的信息与inputParameters一致
总结:
IoMapping 在 xml 中体现为一个标签形式,内部可以继续插入 IoMapping 标签;并且接收其他两个属性 inputParameters 和 outputParameters。
并且 inputParameters 与 outputParameters 都不是简单的数据类型,而且是数组格式,所以给这两个属性设置属性值时,内部的属性也需要通过 moddle.create 创建实例。
在我们创建一个 IoMapping 实例时,步骤和结果如下:
const moddle = modeler.get('moddle')
const ioMapping = moddle.create('zeebe:IoMapping', {inputParameters: [], outputParameters: []})
// 结果如下:
IoMapping = {
$type: 'zeebe:IoMapping',
inputParameters: [],
outputParameters: []
}
1.2 ZeebeServiceTask 没有 IoMapping
虽然分析了 IoMapping 之后,知道了这个属性在配置时该怎么操作;但是,在zeebe:ZeebeServiceTask的定义中,并没有体现出具有IoMapping属性的配置,此时我们可以查询 zeebeServiceTask 定义中的 extend 中的所有元素类型定义,看看有没有 IoMapping 配置。
当然:结果是没有找到。
那么此时这个 IoMapping 属性该怎么配置到serviceTask节点上呢?
嗯~~~ 经过之前研究了一番他们的属性面板,发现这种情况下默认会挂载到 extensionElements 属性中,所以假设我们为一个ServiceTask节点添加了一个 IoMapping 配置的话,此时该节点的 businessObject 会变成这样:
// 只是提示内容格式,不要真的这么赋值哈
serviceTask.businessObject = {
extensionElements: {
$type: "bpmn:ExtensionElements",
values: [
{
$type: "zeebe:IoMapping",
inputParameters: [],
outputParameters: []
}
]
}
}
在 xml 中体现为:
<bpmn:serviceTask id="Activity_0py009y">
<bpmn:extensionElements>
<zeebe:ioMapping></zeebe:ioMapping>
</bpmn:extensionElements>
</bpmn:serviceTask>
1.3 Input 与 Output
现在我们在回过头来看一下 IoMapping 的两个 properties 属性配置,其参数配置都是自定义类型,一个是Input,一个是Output。
而在上面的 JSON Schema 文件中Input 和 Output 都是继承的 InputOutputParameter 类型,具有两个 字符串格式 的参数 source 与 target。
但是因为在 JSON Schema 文件中已经对 InputOutputParameter 重新定义成了两个类型 Input 与 Output,并且在 IoMapping 的定义中也没有使用 InputOutputParameter,所以我们在编写 js 代码的时候也要注意moddle.create 时传入的参数必须是 properties 配置中定义的那个类型名。
那么此时我们给 IoMapping 的 inputParameters 与 outputParameters 设置值时,可以这么操作:
const moddle = modeler.get('moddle')
const input1 = moddle.create('zeebe:Input', {source: '=xxx1', target: 'target1'})
const input2 = moddle.create('zeebe:Input', {source: '=xxx2', target: 'target2'})
const output1 = moddle.create('zeebe:Output', {source: '=xxx3', target: 'target3'})
const ioMapping = moddle.create('zeebe:IoMapping',
{
inputParameters: [input1, input2],
outputParameters: [output1]
}
)
// 需要根据情况判断 extensionElements 的存在情况,这里只是演示就不判断了,直接更新
modeling.updateModdleProperties(element, extensionElements,
{ values: [...extensionElements.get("values"), ioMapping] }
);
此时我们会得到一个类似这样的 xml
<bpmn:serviceTask id="Activity_0py009y">
<bpmn:extensionElements>
<zeebe:ioMapping>
<zeebe:input source="=xxx1" target="InputVariable_3mqm1gd" />
<zeebe:input source="=xxx2" target="InputVariable_3mqm1gd" />
<zeebe:output source="=xxx3" target="OutputVariable_01h6ldb" />
</zeebe:ioMapping>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0nx7hug</bpmn:incoming>
</bpmn:serviceTask>
这里说明一下, xml 是通过官方的编辑器生成的,所以 target 字段会默认生成一个类似 hashID 的值;在实际项目中也可以参考这部分
最后
到此,通过 JSON Schema 分析元素属性结构的过程就基本结束了。总的来说,虽然可以通过这样的方式去分析出来,但是依旧没有通过到导入一个 xml 直接打印属性结构来的快。只是增加一个这样的分析过程,能加深我们对这个 JSON Schema 配置的理解,在后面需要配置和定义项目特殊的属性的时候,也能更加快速的配置出来。
转载自:https://juejin.cn/post/7157673911084613663