day#1(11.13)
尝试通过spring boot 集成最新版activiti 7,但是苦于官方的文档基本为空,无法完成spring boot的配置,最终按照activiti 6的文档,手工初始化ProcessEngine以及完成deploy测试。
在eclipse中安装流程模型设计器,并画简单的流程。
day#2(11.14)
想要开启activiti对数据库操作的SQL日志打印,研究了好一番功夫,终于得以实现。实现方式如下:
logback.xml
maven dependency简单的讲,就是resources下放logback.xml,maven添加对logback的依赖即可,然后activiti执行的sql就会被自动打印,无需其他额外设置。
下载activiti 6 全部压缩包(110MB左右),将官方的在线模型设计器运行起来,发现前端使用angularJS做的。对官方demo稍作研究后决定,完全替换官方的rest API,方法就是获取官方的后端API源码,然后一个接口一个接口增加到自建spring mvc项目中。
新建spring mvc空项目,新建简单controller,运行成功。
maven引入activiti engine,复制第一个API代码以及editor前端代码到自己的项目中,发现需要引入另一个jar包(activiti-app-logic)。maven引入之后,编译能通过,但是无法启动,原因是spring 启动时检查引入的jar包冲突。在maven中增加exclusion修复完jar包冲突之后,总算运行起来。
运行起来之后,为了避开身份认证,直接修改JS源码,终于得以直接运行activiti-app/editor/#/editor目录。
day#3(11.15)
开始修复第一个API(GET rest/models),发现需要引用或完全替换activiti-app-logic包中的数据库访问层。考虑了一会,考虑到modeler只涉及3张表,决定用我们之前项目的hibernate框架完全重写modeler的数据库访问层代码。
非常顺利,很快实现获取models,创建model,生成model缩略图,获取model编辑器json数据,保存模型(完成编译)等接口。唯一麻烦的事就是需要从activiti-app-logic包中搬代码,解决各种依赖问题。
day#3(11.16)
先是修复了保存模型的接口,并且进行了大量测试,各种复杂模型数据都可以顺利保存。
接下来体验了modeler的大部分功能,发现非常的复杂,得需要完全理解activiti的基础上才能开发出适用的流程引擎啊。接下来的几天可能是学习activiti引擎了。
day#4(11.19/周一)
周末的时候花了些时间阅读文档,完成了大部分内容的阅读,特别是对BPMN2.0规范有了较深刻的认识。
上午继续花了约2小时完成文档的粗略阅读,接着制定了后面的计划:
- (1)完成流程模型的部署(之前已完成模型创建和保存);
- (2)发起流程;
- (3)查看任务列表;
- (4)完成任务;
- (5)完成流程;
- (6)下一阶段:复杂自定义流程。
接下来首先是研究官方demo,找到并体验发布流程以及任务列表的功能,然后就是从官方的源码中拷贝需要的代码到自建工程里面。遇到了一点问题,就是官方demo中发布流程的业务过于复杂不适合我们项目,但是一开始代码是按照官方demo写的,所以运行起来之后总是报json解析错误,后来慢慢慢慢跟代码,发现可以完全移除官方发布流程中的很多步骤,这样才会更加适合我们的项目。然后就顺利完成了模型的部署。
接下来为了后面的测试更加方便,自己新增了几个rest接口将引擎下面的服务方法通过浏览器暴露,这样便于后期的调试。
为了从全新的简单流程开始测试,就需要把之前创建的错误流程删除,并且正式开发时也需要删除流程的功能,所以接着就重新开发删除流程的接口。
day#5(11.20)
清除之前的数据之后,准备创建一个较为真实的请假流程,流程图如下:

流程图画好之后,发现流程图及相关属性乱码。然后百度,一开始以为很好解决就直接从网上copy了一些代码,最后发现都没有解决问题,然后才开始修改editor_json接口,然后定位到造成问题的原因是因为JsonNode对象在restcontroller返回时序列化造成的乱码问题。尝试将JsonNode替换为普通object,中文乱码消失。但是普通java object有一个动态的model对象,如果使用fasterxml的JsonNode发现无法正常序列化,改换为fastjson的JSONObject对象,居然可以正常序列化!至此,中文乱码问题已解决。
接下来便是发起流程。发起流程之后,获取流程实例,获取taskService,获取当前task,尝试设置task的owner和表单数据(通过流程变量),然后完成任务。
代码虽然简单,但是发现任务的owner根本设置不上去,后来尝试了各种方法,才发现问题所在:taskService.complete方法调用之后,当前Task对象已从数据库删除了,如果再用此task对象的id去数据库查询将查不到该task,这时(complete方法调用之后),其实当前流程实例下面包含的任务已经是新创建的task了(有不同的id),之前那个complete的task已经到history表里面去了(owner也设置成功了的)。
由于我们将要开发方便普通工作人员使用的自定义流程设计器,所以,activiti官方的流程设计器的属性编辑器基本不能用了,因为那个编辑器几乎没有人会用的。要替换这个编辑器,最重要的部分就是选择assignee了,设计的原型图如下:

设计思路:
(1)在填写表单环节,增加自定义环节属性:是否需要用户指定下一环节的审批人。如果下一环节只有一个,并且业务需求确实是需要指定审批人,那么在用户提交表单之前,需要选择下一环节审批人。数据传到服务器端之后,服务器首先保存任务的表单数据,然后完成任务,然后获取下一个环节任务,然后设置下一环节的审批人(来自参数);
(2)如果下一环节审批人不需要流程发起人指定,那么提交表单后,服务器端处理逻辑:开始流程 -> 获取第一个任务 -> 设置owner和表单数据 -> 完成任务。在下一环节的create event listener代码中早已设置好assignee的计算逻辑。只要进入listener,就会根据环节定义的审批人进行计算得到当前任务的指派者。
(3)下一环节的assignee已设置好,只要该用户打开任务并进行审批就可以让流程运转起来了。
day#6(11.21)
开始改造模型设计器:
(1)简化工具箱,只保留空开始事件、用户任务、并行网关、排他网关、空结束任务、文本备注;
(2)简化流程属性编辑器;
(3)简化其他控件属性编辑器;
(4)用户任务控件增加自定义角色配置;
通过跟踪分析js代码,发现工具箱数据源来自stencilset_bpmn.json,然后备份好后删除不需要的控件,运行,成功。
继续通过跟踪分析js代码,发现属性编辑器的数据源同样来自stencilset_bpmn.json,然后修改英文为中文,运行,乱码,同样是fasterxml的JsonNode对象造成,替换为fastjson的JSONObject,顺利解决中文乱码问题。
首先修改User Task控件,将额外属性移除,运行,发现设计图上面多了两个图标,然后一个属性一个属性移除,终于发现"multiinstance_typepackage","isforcompensationpackage"这两个属性不能移除,说白了这就是activiti的这两个属性的默认值的bug。但是这两个属性不移除的话,编辑器上面就会显示,这显然是不符合需求的。于是开始找代码看哪里用到这两个属性了。尝试修改多个地方的代码之后,虽然可以实现但终觉不妥,后来突然发现属性object有个popular属性,将其修改为false,编辑器上就直接隐藏了,甚是方便。
后来有个员工要离职,工作交接花了3小时左右。
接着完成稍微复杂一点的流程设计,如图:

先从简单的控件开始吧。首先需要改造的就是排他网关出去的两个条件顺序流。思路:
(1)为每个顺序流增加flowtype字段,如果该字段有值,那么在保存模型的时候,就将该字段的值获取出来并按照格式填充到conditionsequenceflow属性中,并删除模型的flowtype属性;
(2)设置条件的表达式大致为:$(APPROVAL_RESULT=='"+flowtype+"'),这样在上一环节完成审批时,会添加一个名称为APPROVAL_RESULT的流程变量,从而实现条件的跳转;
(3)后期再将flowtype的编辑器改为下拉列表,这样用户只需要选择:“审批同意”、“审批拒绝”、“无条件”、“其他表单条件。。。”就可以完成条件的设置,无需输入表达式了。
修改代码之后运行,直接成功。下班了,第二天可以测试环节是否可以自动跳转了。
day#7(11.22)
由于找了很久的文档没有找到UEL表达式如何判断字符串相等,所以索性改成判断bool相等,因为有demo嘛。然后更新流程模型,更新代码。最终修复editor_json的代码如下:
View Code开始测试:
(1)填写请假表单,complete流程开始后的默认任务(将流程推进到经理审核环节),返回流程实例ID;
(2)查询该流程实例下面的全部活跃任务;
(3)找到经理审核的任务(只有这一个任务);
(4)根据经理审核任务ID对请假进行审核(approved=true/false),complete任务时传入APPROVED流程变量(值来自于controller方法参数);
(5)再次根据流程实例ID查询活跃任务,发现流程已经根据approved参数自动选择分支进行流转了。
(6)至此,顺序流条件控制测试成功。
接下来开始扩展UserTask的自定义属性了。
首先在stencilset_bpmn.json中增加一个complexassigneepackage,然后将此package添加到UserTask的属性列表中,然后在properties.js中增加响应配置,以及创建相应的html模板代码和angularJS的controller。
下图则是这个自定义属性(复杂指派者属性)的编辑器原型:

对应到服务器端的数据结构为:
