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代码 
 
其中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

 
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实现。 

显示已保存模型

  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,分析起来够麻烦。

粗览Activiti Modeler操作和源代码的更多相关文章

  1. Activiti Modeler初探实践

    以下内容对实践activiti很有用,不过我用的不是github下载的源码包编译出来的war包,不知道什么原因我打出来的包会有点问题.不过这不重要,换个地方下载来源就行,下载网址: http://dl ...

  2. 基于Metronic的Bootstrap开发框架经验总结(9)--实现Web页面内容的打印预览和保存操作

    在前面介绍了很多篇相关的<Bootstrap开发框架>的系列文章,这些内容基本上覆盖到了我这个Bootstrap框架的各个主要方面的内容,总体来说基本达到了一个稳定的状态,随着时间的推移可 ...

  3. 集成新版(5.17+)Activiti Modeler与Rest服务

    声明: 此教程适合Activiti 5.17+版本. 本博客所涉及的内容均可在kft-activiti-demo中找到. 在线demo可以访问 http://demo.kafeitu.me:8080/ ...

  4. (转)基于Metronic的Bootstrap开发框架经验总结(9)--实现Web页面内容的打印预览和保存操作

    http://www.cnblogs.com/wuhuacong/p/5147368.html 在前面介绍了很多篇相关的<Bootstrap开发框架>的系列文章,这些内容基本上覆盖到了我这 ...

  5. Entity Framework 实体框架的形成之旅--几种数据库操作的代码介绍(9)

    本篇主要对常规数据操作的处理和实体框架的处理代码进行对比,以便更容易学习理解实体框架里面,对各种数据库处理技巧,本篇介绍几种数据库操作的代码,包括写入中间表操作.联合中间表获取对象集合.递归操作.设置 ...

  6. C#各种文件操作的代码与注释

    C#各种文件操作的代码与注释,具体看下面代码: using System; using System.Collections.Generic; using System.Linq; using Sys ...

  7. [ZZ]计算机视觉、机器学习相关领域论文和源代码大集合

    原文地址:[ZZ]计算机视觉.机器学习相关领域论文和源代码大集合作者:计算机视觉与模式 注:下面有project网站的大部分都有paper和相应的code.Code一般是C/C++或者Matlab代码 ...

  8. activiti基础操作

    package activitiTest; import java.io.InputStream; import java.util.List; import java.util.zip.ZipInp ...

  9. Global.asax中的操作数据库代码无法执行

    本人最近在做一个基于Access数据库的Web应用程序,为了实现一个定时更新数据库的需求,我在Global.asax中的Application_Start函数里写了个计时器, void Applica ...

随机推荐

  1. Python的web服务器

    1.浏览器请求动态页面过程 2.WSGI Python Web Server Gateway Interface (或简称 WSGI,读作“wizgy”). WSGI允许开发者将选择web框架和web ...

  2. Hadoop-MR[会用]MR程序的运行模式

    1.简介 现在很少用到使用MR计算框架来实现功能,通常的做法是使用hive等工具辅助完成.但是对于其底层MR的原理还是有必要做一些了解. 2.MR客户端程序实现套路 这一小节总结归纳编写mr客户端程序 ...

  3. vue页面高度填充,不出现滚动条

    现在的需求是这样:vue单页工程化开发,上面有一个header,左边有一个侧边栏,右边内容展示.要求左边侧边栏的高度,要填充满整个页面(除了header外,header:height:60px)--如 ...

  4. leetcode 136 137 Single Number

    题目描述(面试常考题) 借助了异或的思想 class Solution { public: int singleNumber(vector<int>& nums) { ; ; i ...

  5. 微软企业库5.0 学习之路——第六步、使用Validation模块进行服务器端数据验证

    前端时间花了1个多星期的时间写了使用jQuery.Validate进行客户端验证,但是那仅仅是客户端的验证,在开发项目的过程中,客户端的信息永远是不可信的,所以我们还需要在服务器端进行服务器端的验证已 ...

  6. 【初探移动前端开发04】jQuery Mobile 一

    网格布局 jquery mobile提供一种多列布局功能,由于移动设备的屏幕大小原因,一般情况还是不要使用多列布局啦. jquery mobile提供一种css样式规则来定义多列布局,对应css为ui ...

  7. Java Control Statements

    Java Control Statements Java For Loop public class ForExample1 { public static void main(String[] ar ...

  8. Qt精简编译方法总结

    原文请看:http://blog.csdn.net/loaden/article/details/6061702 Qt如果采取默认编译安装,一般都要占用上G的空间.当初自己不想涉及Qt的一个原因,就是 ...

  9. ZUFEOJ 2147 07染色带谜题

    2147: 07染色带谜题 时间限制: 1 Sec  内存限制: 128 MB提交: 170  解决: 21[提交][状态][讨论版][Edit] [TestData] 题目描述 现在给你一个长为N的 ...

  10. 洛谷P1801 黑匣子

    题目传送门 分析:这题和另外一个题目中位数非常相似,有兴趣可以先看看,比这一题简单.首先暴力模拟还是别想了,估计30%的数据都有点悬.正解应该是用二叉堆.但是如果用一个堆当然不方便,所以建两个堆,一个 ...