粗覽Activiti Modeler操作和源代碼


Activiti Model Editor組件

我的  了解ActivitiExplorer及其Vaadin實現方式博文里提到ActivitiExplorer使用的是Vaadin架構,但是Activiti 模型編輯器組件卻沒用使用Vaadin架構,而是采用Angular.JS的MVC模式。Activiti模型編輯器組件的客戶端代碼位於Activiti\modules\activiti-webapp-explorer2\src\main\webapp\editor-app\。


該目錄下的editor.html是Activiti Modeler Editor的主界面HTML代碼 
粗覽Activiti <wbr />Modeler操作和源代碼 
其中palette區是通過Angular.JS使用stencilsets\bpmn2.0\icons下多個子目錄內的PNG圖像形成的多組列表。其節點層次關系獲取相關代碼為: 

  1. stencil-controller.js
  2. Activiti\modules\activiti-modeler\src\main\java\org\activiti\rest\editor\main\StencilsetRestResource.java
  3. Activiti\modules\activiti-webapp-explorer2\src\main\resources\stencilset.json

粗覽Activiti <wbr />Modeler操作和源代碼 
editor.html中的視圖與兩個控制器進行了綁定: 

  • 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實現。 粗覽Activiti <wbr />Modeler操作和源代碼 

顯示已保存模型

 

  1. 選擇模型,會調用EditorProcessDefinitionPage類的showProcessDefinitionDetail方法
  2. EditorProcessDefinitionDetailPanel類的initUI方法調用initProcessDefinitionInfo方法,它會加入EditorProcessDefinitionInfoComponent實例
  3. 在構造EditorProcessDefinitionInfoComponent實例時,其initImage方法會被調用,通過RepositoryService的getModelEditorSourceExtra方法獲得PNG格式圖像,最終被顯示到瀏覽器界面上。

 

部署已保存模型


EditorProcessDefinitionDetailPanel類的deployModel方法處理部署已保存模型的操作。 

  1. 通過RepositoryService的getModelEditorSource方法獲得模型JSON數據的UTF8字符串
  2. 通過FasterXML/jackson-databind轉換成Java對象樹
  3. 通過Activiti\modules\activiti-json-converter\src\main\java\org\activiti\editor\language\json\converter\BpmnJsonConverter.java將模型JSON數據的Java對象樹轉換成BpmnModel實例
  4. 通過Activiti\modules\activiti-bpmn-converter\src\main\java\org\activiti\bpmn\converter\BpmnXMLConverter.java將BpmnModel實例轉成BPMN XML數據
  5. 通過RepositoryService的createDeployment方法將BPMN XML數據進行部署

 

導出已保存模型


EditorProcessDefinitionDetailPanel類的exportModel方法處理導出已保存模型的操作。 

  1. 通過RepositoryService的getModelEditorSource方法獲得模型數據的JSON字符串
  2. 通過FasterXML/jackson-databind轉換成Java對象樹
  3. 通過Activiti\modules\activiti-json-converter\src\main\java\org\activiti\editor\language\json\converter\BpmnJsonConverter.java將模型JSON數據的Java對象樹轉換成BpmnModel實例
  4. 通過Activiti\modules\activiti-bpmn-converter\src\main\java\org\activiti\bpmn\converter\BpmnXMLConverter.java將BpmnModel實例轉成BPMN XML數據

 

編輯已保存模型


EditorProcessDefinitionDetailPanel類內注冊了EditModelClickListener監聽器用於處理導入BPMN模型操作。 
EditModelClickListener的showModeler會生成訪問模型編輯器組件的URL地址,打開指定的模型。 

  1. Activiti\modules\activiti-webapp-explorer2\src\main\webapp\editor-app\app.js中的監聽器處理$includeContentLoaded事件,調用了fetchModel方法
  2. 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數據。 

  1. 通過Activiti\modules\activiti-bpmn-converter\src\main\java\org\activiti\bpmn\converter\BpmnXMLConverter.java將BPMN XML數據轉換成BpmnModel實例
  2. 通過BpmnModel實例生成模型的元數據,通過RepositoryService的saveModel方法將模型的元數據存入數據庫的ACT_RE_MODEL表
  3. 通過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,分析起來夠麻煩。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM