Activiti Model Editor組件
該目錄下的editor.html是Activiti Modeler Editor的主界面HTML代碼
其中palette區是通過Angular.JS使用stencilsets\bpmn2.0\icons下多個子目錄內的PNG圖像形成的多組列表。其節點層次關系獲取相關代碼為:
- stencil-controller.js
- Activiti\modules\activiti-modeler\src\main\java\org\activiti\rest\editor\main\StencilsetRestResource.java
- Activiti\modules\activiti-webapp-explorer2\src\main\resources\stencilset.json
- stencil-controller.js:處理對canvas中BPMN元素的操作,很多處理是通過editor目錄下的QRYX庫完成的
- toolbar-controller.js:處理對工具欄的操作,很多處理由configuration\toolbar-default-actions.js完成
保存模型操作
保存模型操作,是通過toolbar-default-actions.js中的SaveModel方法完成的,它需要將三部分信息傳給服務器:
- 模型的元數據:例如模型名稱、分類、創建時間、最后一次更新時間等等
- 模型JSON數據:將canvas內的圖像數據轉換成JSON數據UTF8字符串
{
"resourceId": 53,
"properties": {
"process_id": "process",
"name": "",
"documentation": "",
"process_author": "",
"process_version": "",
"process_namespace": "http://www.activiti.org/processdef",
"executionlisteners": "",
"eventlisteners": ""
},
"stencil": {
"id": "BPMNDiagram"
},
"childShapes": [
{
"resourceId": "sid-4F7484B9-11EC-4FCE-8950-FEFFB723D88B",
"properties": {
"overrideid": "",
"name": "",
"documentation": "",
"executionlisteners": "",
"initiator": "",
"formkeydefinition": "",
"formproperties": ""
},
"stencil": {
"id": "StartNoneEvent"
},
"childShapes": [],
"outgoing": [
{
"resourceId": "sid-B589A0D9-FA79-4C12-95B7-253E72480384"
}
],
"bounds": {
"lowerRight": {
"x": 259,
"y": 139
},
"upperLeft": {
"x": 229,
"y": 109
}
},
"dockers": []
},
{
"resourceId": "sid-1A762474-62B9-4F3D-A81C-1ADD46AF7D2F",
"properties": {
"overrideid": "",
"name": "",
"documentation": "",
"asynchronousdefinition": "false",
"exclusivedefinition": "false",
"executionlisteners": "",
"multiinstance_type": "None",
"multiinstance_cardinality": "",
"multiinstance_collection": "",
"multiinstance_variable": "",
"multiinstance_condition": "",
"isforcompensation": "false",
"usertaskassignment": "",
"formkeydefinition": "",
"duedatedefinition": "",
"prioritydefinition": "",
"formproperties": "",
"tasklisteners": ""
},
"stencil": {
"id": "UserTask"
},
"childShapes": [],
"outgoing": [
{
"resourceId": "sid-4134C10E-B589-42FF-AACC-463D35D52016"
}
],
"bounds": {
"lowerRight": {
"x": 746,
"y": 172
},
"upperLeft": {
"x": 646,
"y": 92
}
},
"dockers": []
},
{
"resourceId": "sid-B22A5CAB-94D0-419E-BB1E-E8538C6A7283",
"properties": {
"overrideid": "",
"name": "",
"documentation": "",
"executionlisteners": ""
},
"stencil": {
"id": "EndNoneEvent"
},
"childShapes": [],
"outgoing": [],
"bounds": {
"lowerRight": {
"x": 1089,
"y": 138
},
"upperLeft": {
"x": 1061,
"y": 110
}
},
"dockers": []
},
{
"resourceId": "sid-B589A0D9-FA79-4C12-95B7-253E72480384",
"properties": {
"overrideid": "",
"name": "",
"documentation": "",
"conditionsequenceflow": "",
"executionlisteners": "",
"defaultflow": "false"
},
"stencil": {
"id": "SequenceFlow"
},
"childShapes": [],
"outgoing": [
{
"resourceId": "sid-1A762474-62B9-4F3D-A81C-1ADD46AF7D2F"
}
],
"bounds": {
"lowerRight": {
"x": 645.5626565925471,
"y": 131.10730365650525
},
"upperLeft": {
"x": 259.12484340745283,
"y": 124.26769634349473
}
},
"dockers": [
{
"x": 15,
"y": 15
},
{
"x": 50,
"y": 40
}
],
"target": {
"resourceId": "sid-1A762474-62B9-4F3D-A81C-1ADD46AF7D2F"
}
},
{
"resourceId": "sid-4134C10E-B589-42FF-AACC-463D35D52016",
"properties": {
"overrideid": "",
"name": "",
"documentation": "",
"conditionsequenceflow": "",
"executionlisteners": "",
"defaultflow": "false"
},
"stencil": {
"id": "SequenceFlow"
},
"childShapes": [],
"outgoing": [
{
"resourceId": "sid-B22A5CAB-94D0-419E-BB1E-E8538C6A7283"
}
],
"bounds": {
"lowerRight": {
"x": 1060.676003953202,
"y": 130.93202152143962
},
"upperLeft": {
"x": 746.595480421798,
"y": 124.30235347856038
}
},
"dockers": [
{
"x": 50,
"y": 40
},
{
"x": 14,
"y": 14
}
],
"target": {
"resourceId": "sid-B22A5CAB-94D0-419E-BB1E-E8538C6A7283"
}
}
],
"bounds": {
"lowerRight": {
"x": 1200,
"y": 1050
},
"upperLeft": {
"x": 0,
"y": 0
}
},
"stencilset": {
"url": "stencilsets/bpmn2.0/bpmn2.0.json",
"namespace": "http://b3mn.org/stencilset/bpmn2.0#"
},
"ssextensions": []
} - 模型的SVG圖像數據:將canvas中的SVG圖像數據經過過濾處理而得
服務器側保存模型的代碼位於Activiti\modules\activiti-modeler\src\main\java\org\activiti\rest\editor\model\ModelSaveRestResource.java。
- 通過RepositoryService的saveModel方法將模型的元數據存入數據庫的ACT_RE_MODEL表
- 通過RepositoryService的addModelEditorSource方法將模型JSON數據UTF8字符串存入數據庫的ACT_GE_BYTEARRAY表
- 通過Apache™ BatikSVGToolkit將模型的SVG圖像數據轉換成PNG格式,通過RepositoryService的addModelEditorSourceExtra方法將PNG圖像存入數據庫的ACT_GE_BYTEARRAY表
Activiti Explorer操作已保存模型
對模型的編輯操作是在Activiti Model Editor組件里實現的,對已保存模型的其他操作還是在ActivitiExplorer里基於Vaadin架構實現的。
客戶端代碼位於:Activiti\modules\activiti-explorer\src\main\java\org\activiti\editor\ui\。
下圖的HTML界面由EditorProcessDefinitionDetailPanel.java實現。
顯示已保存模型
- 選擇模型,會調用EditorProcessDefinitionPage類的showProcessDefinitionDetail方法
- EditorProcessDefinitionDetailPanel類的initUI方法調用initProcessDefinitionInfo方法,它會加入EditorProcessDefinitionInfoComponent實例
- 在構造EditorProcessDefinitionInfoComponent實例時,其initImage方法會被調用,通過RepositoryService的getModelEditorSourceExtra方法獲得PNG格式圖像,最終被顯示到瀏覽器界面上。
部署已保存模型
EditorProcessDefinitionDetailPanel類的deployModel方法處理部署已保存模型的操作。
- 通過RepositoryService的getModelEditorSource方法獲得模型JSON數據的UTF8字符串
- 通過FasterXML/jackson-databind轉換成Java對象樹
- 通過Activiti\modules\activiti-json-converter\src\main\java\org\activiti\editor\language\json\converter\BpmnJsonConverter.java將模型JSON數據的Java對象樹轉換成BpmnModel實例
- 通過Activiti\modules\activiti-bpmn-converter\src\main\java\org\activiti\bpmn\converter\BpmnXMLConverter.java將BpmnModel實例轉成BPMN XML數據
- 通過RepositoryService的createDeployment方法將BPMN XML數據進行部署
導出已保存模型
EditorProcessDefinitionDetailPanel類的exportModel方法處理導出已保存模型的操作。
- 通過RepositoryService的getModelEditorSource方法獲得模型數據的JSON字符串
- 通過FasterXML/jackson-databind轉換成Java對象樹
- 通過Activiti\modules\activiti-json-converter\src\main\java\org\activiti\editor\language\json\converter\BpmnJsonConverter.java將模型JSON數據的Java對象樹轉換成BpmnModel實例
- 通過Activiti\modules\activiti-bpmn-converter\src\main\java\org\activiti\bpmn\converter\BpmnXMLConverter.java將BpmnModel實例轉成BPMN XML數據
編輯已保存模型
EditorProcessDefinitionDetailPanel類內注冊了EditModelClickListener監聽器用於處理導入BPMN模型操作。
EditModelClickListener的showModeler會生成訪問模型編輯器組件的URL地址,打開指定的模型。
- Activiti\modules\activiti-webapp-explorer2\src\main\webapp\editor-app\app.js中的監聽器處理$includeContentLoaded事件,調用了fetchModel方法
- Activiti\modules\activiti-modeler\src\main\java\org\activiti\rest\editor\model\ModelEditorJsonRestResource.java處理該REST請求,返回由RepositoryService的getModel和getModelEditorSource方法獲得Activiti模型元數據和JSON數據
導入BPMN模型
EditorProcessDefinitionDetailPanel類內注冊了ImportModelClickListener監聽器用於處理導入BPMN模型操作。
ImportPopupWindow界面完成BPMN模型操作后,ImportUploadReceiver類的deployUploadedFile方法處理上傳的BPMNXML數據。
- 通過Activiti\modules\activiti-bpmn-converter\src\main\java\org\activiti\bpmn\converter\BpmnXMLConverter.java將BPMN XML數據轉換成BpmnModel實例
- 通過BpmnModel實例生成模型的元數據,通過RepositoryService的saveModel方法將模型的元數據存入數據庫的ACT_RE_MODEL表
- 通過Activiti\modules\activiti-json-converter\src\main\java\org\activiti\editor\language\json\converter\BpmnJsonConverter.java將BpmnModel實例轉換成模型JSON數據的Java對象樹,通過RepositoryService的addModelEditorSource方法將模型JSON數據UTF8字符串存入數據庫的ACT_GE_BYTEARRAY表
一些疑惑和想法:
- 這里BpmnXMLConverter和BpmnJsonConverter用的比較頻繁,而且成對出現。為什么不跳過中間的BpmnModel?
- 導入BPMN模型為什么不生成PNG圖像?
- 數據庫存儲的模型數據不采用BPMNXML格式而是采用JSON格式,很靈活,可以隨意添加Activiti擴展內容。但是如果沒有現成的JSONschema,分析起來夠麻煩。

