likes
comments
collection
share

手把手教你通过JSON Schema判断BpmnJS元素属性结构~

作者站长头像
站长
· 阅读数 54

前言

在上一篇文章 手把手教你玩转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
评论
请登录