张超 王萌 任女尔
摘要:近年来,工作流技术日益成熟,会签在流程系统中的出现也越来越频繁。各大流程引擎也对会签做了默认支持。Activiti作为现今十分流行的开源流程引擎,通过多实例任务节点也对会签做了支持,但是对多实例的回退却没做支持。为解决上述问题,该文通过Activiti提供的服务接口,并结合一定的算法,实现多实例任务的回退。
关键词:工作流;Activiti;多实例;回退
中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2018)19-0113-03
伴随着信息化技术的高速发展,企业信息化也得以逐渐深入,普通的办公自动化系统已经无法满足日渐增多的企业流程需求。会签作为工作流程中的一种常见的场景,可以让多个人相互协同,共同完成某一个任务,因而在流程的信息传递上更加自动化,在流程的信息处理上更加高效,在任务的完成上更加直观。所以会签使用的时间成本更低,安全性、封闭性更高,相应的,效率也就更高。
Activiti通过使用多实例任务节点,在业务流程中定义重复环节,从而实现对会签的支持。多实例任务节点通过给定的集合,对集合中的每一个元素执行一次任务,既可以顺序同步执行,也可以并发同时执行这些任务。然后通过设置完成多实例任务的条件,决定会签的后续走向。但是对于某些业务场景,多实例任务节点并不能满足需求。比如:会签中的某个参与者发现自己没有参与会签的资格,造成该现象的原因可能是在选择会签人员时的疏忽。
针对该业务场景,本文对Activiti的多实例任务进行了扩展和延伸,使得会签任务中的某一个子任务得以有修正的机会,从而降低出错率,避免整个会签任务的失败。
1 技术简介
1.1 Workflow
1993年工作流管理联盟(Workflow Management Coalition,WfMC)成立,作为工作流管理的标准化组织,对工作流给出了定义:工作流是指一类能够完全自动执行的经营过程,根据一系列过程规则,将文档、信息或任务在不同的执行者之间进行传递与执行。通俗点将,工作流是将一组任务以及任务相关的人组织起来以共同完成某一个业务过程。它定义了任务的顺序以及后续任务的出发条件,每个任务可以由一个人来完成,也可以由多个人协同完成。
工作流引擎指的是Workflow应该作为应用系统的一部分,并为之提供解决方案,这些方案包括:根据分工和条件的不同以及角色来决定信息传递路由、内容等级等核心解决方案。工作流引擎包含了流程图的绘制、流程节点的管理、流程流向的控制以及流程实例的管理等。目前市面上常见的流程引擎主要包含:JBPM、Activiti、SWF等。
1.2 Activiti
Activiti项目是一个开源的BPM平台,提供了对BPMN2.0标准的支持。Activiti是一种BPM引擎,它轻量,并且可嵌入。为了可以被广泛使用,Activiti提供了宽松的Apache许可2.0。同时,为了促进和BPMN2.0标准的匹配,该项目由OMG通过标准审定。
Activiti项目的创始人之一Tom Baeyens,原先是JBoss jBPM的项目架构师,因此,Activiti是基于JBPM4开发的,同时支持流程虚拟机技术,并且对外提供了清洗的服务接口,可以很好地集成外部服务。关于Activiti的優势,Tom Baeyens曾说:“Activiti有非常大的影响力来改变目前BPM的生态。Activiti的Apache授权,完整的功能,将使Activiti到达一个新的水平。Activiti将推动业界的创新,因为BPM技术可以广泛而自由地被应用。通过实现这些想法以及开源社区的努力,也让Activiti成为事实上的 BPM和BPMN标准执行”。SpringSource的首席技术官Adrian Coyler也说道:“这是一个对Spring开发人员和Java社区总体的发展非常令人兴奋的事情,长期以来一直需要一个Apache许可的流程引擎,这对许多应用系统非常实用的需求。我们认为,Activiti作为新的应用领域扩展到的Java和开源的发展,特别是在云架构上”。
2 系统架构
本课题涉及项目的软件技术架构使用JAVA语言,采用B/S架构,综合SpringBoot、Hibernate、Shiro等框架进行业务逻辑开发,采用Activiti工作流引擎处理业务流程,页面则采用Html、Bootstrap、Ajax开发。整体系统架构如下所示:
本系统底层操作系统支持Windows、linux、Solaris等操作系统,数据库采用Oracle;在此基础之上,通过JDBC与数据库交互,通过XML和properties文件进行缓存、日志等的配置;上层数据层采用Hibernate和Spring提供的方法设计数据库相关操作;业务层在数据库操作的基础之上对业务逻辑进行处理;控制层通过SpringMVC使得业务逻辑与前端UI系统进行交互,前端UI系统由html和jQuery, bootstrap,进行表现层的展示。系统严格按照MVC架构模式进行设计和开发,如下图所示:
2.1 多实例任务回退的设计与实现
2.1.1 设计思想
多实例任务回退的设计思想是当多实例任务中的某个子任务要回退时,首先将该任务的处理人置空,这样要回退的任务就不会出现在待办列表里,也就不会被某个人完成,流程就会停留在多实例节点处,再通过利用Activiti提供的服务接口TaskService中的两个方法:TaskService.newTask()和TaskService.saveTask()来创建回退的任务并保存到数据库,由于创建的新任务不能关联到某个具体的流程,所以这里采用一种折中的办法:在任务的本地变量里设置相关的信息,同时添加两个变量:MULTI_INSTANCE_ROLLBACK_和INSTANCE_ROLLBACK_ID_,分别表示新任务是一个多实例的回退任务以及原始任务ID,这样,新任务就和原始任务有了关联,完成任务时,就可以重新指定子任务的处理人了。
2.1.2 具体实现过程及相关代码
1) 流程设计图
在IDEA开发工具中,使用流程绘制插件按照BPMN2.0规范绘制流程图,流程图中包含一个多实例任务节点,流程文件部分代码如下:
2) 将设计好的流程部署,因为使用的springboot,将流程定义文件放置到src/main/resources/processes目录下,项目启动时会自动部署。
3) 部署后就可以使用流程了。首先要发起一个流程实例,并设置流程发起人,代码如下:
ProcessInstance processInstance = null;
try {
identityService.setAuthenticatedUserId("user1");
processInstance = runtimeService.startProcessInstanceByKey("MyMultiInstanceRollbackProcess");
}finally {
identityService.setAuthenticatedUserId(null);
}
發起流程后,就可以获取相应的待办,并完成任务。首先,我们获取用户user1的待办任务,并完成,在完成的时候指定下一个多实例任务的集合,代码如下:
Task user1Task = taskService.createTaskQuery().taskAssignee("user1").singleResult();
Map
String[] assignees = {"user21","user22","user23"};
variables.put("assigneeCollection",Arrays.asList(assignees));
taskService.complete(user1Task.getId(),variables);
4) 签收并完成任务。先让use22和user23完成任务,代码如下:
Task user22Task = taskService.createTaskQuery().taskAssignee("user22").singleResult();
taskService.complete(user22Task.getId());
Task user23Task = taskService.createTaskQuery().taskAssignee("user23").singleResult();
taskService.complete(user23Task.getId());
5) 回退多实例任务。user21查看到待办任务后,发现该任务不应该是自己处理的,于是回退给user1,代码如下:
Task user21Task = taskService.createTaskQuery().taskAssignee("user21").singleResult();
taskService.setAssignee(user21Task.getId(),null);
Task rollbackTask = taskService.newTask();
rollbackTask.setAssignee("user1");
Map
rollbackTaskVariablesLocal.put("MULTI_INSTANCE_ROLLBACK_",true);
rollbackTaskVariablesLocal.put("INSTANCE_ROLLBACK_ID_",user21Task.getId());
taskService.saveTask(rollbackTask);
taskService.setVariablesLocal(rollbackTask.getId(),rollbackTaskVariablesLocal);
6) user1重新分配任务
user1Task = taskService.createTaskQuery().taskAssignee("user1").singleResult();
Map
if(user1TaskVariablesLocal.containsKey("MULTI_INSTANCE_ROLLBACK_")){
boolean isRollbackTask = (boolean)user1TaskVariablesLocal.get("MULTI_INSTANCE_ROLLBACK_");
if(isRollbackTask){
String originalTaskId = (String)user1TaskVariablesLocal.get("INSTANCE_ROLLBACK_ID_");
if(StringUtils.isEmpty(originalTaskId)){
throw new Exception("the multi instance rollback task has no original task");}
taskService.setAssignee(originalTaskId,"user24"); }}
7) 新分配的用户查看待办并完成任务,代码如下:
Task user24Task = taskService.createTaskQuery().taskAssignee("user24").singleResult();
taskService.complete(originalTaskId);
historyService.deleteHistoricTaskInstance(originalTaskId);
8) 会签任务结束,流程继续
3 结论
本文利用Activiti技术并结合一定的算法实现了多实例会签任务的回退,为多实例任务分发错误的情况提供了解决方案。这个方案通过使用Activiti自身提供的API,并结合任务的本地变量,从而扩展了Activiti的多实例任务,让分发错误的子实例得以修正,同时还不影响其他正确的子实例。但是由于时间、精力、知识水平的制约,本设计也有需要提高的地方,例如由于使用了变量,导致变量表的快速增加,对查询性能存在影响。后续可以考虑将这些变量的内容单独存在一张表中。
参考文献:
[1] 范玉顺.工作流管理技术基础[M].北京:清华大学出版社,2001.
[2] 闫洪磊.Activiti实战[M].北京:机械工业出版社,2014.
[3] 顾大明.基于JBPM的工作流会签设计[J].民营科技,2010(12).
[4] 罗海滨,范玉顺,吴澄.工作流技术综述[J].软件学报,2000,11(7):899-907.
[5] 梅峰,于洋,卫青延,等.基于开源工作流 Activiti的企业协同信息平台研究[J].福建电脑,2012(11):125-127.
[6] 张利君,马骏,杨涛,等.基于工作流的动态任务调度研究与实现[J].计算机工程与设计,2009(10):2533-2537.
[7] 王安慧,孙长银.管理信息系统会签管理模块的设计与应用[J].三峡大学学报,2001,23(5):454-457.
[8] 冯天佑,梁立宇,李成华,等.基于Activiti工作流引擎技术的电力行业业务流程管理系统[J].信息通信,2013(8):57-59.
[9] Chen W.Enterprise information management system basedon J2EE and MVC mode[C]//Proceedings of the 9th In-ternational Symposium on Linear Drives for Industry Appli-cations.2014,3:427-433.
[10] 薛華成.管理信息系统[M].北京:清华大学出版社,1993.
[11] WFMC-TC-1025,工作流过程定义接口———XML 过程定义语言[S].
[12] 阿斯特.作流管理:模型、方法和系统[M].王建民,译.北京:清华大学出版社,2004.
[13] 叶小路,钱真坤.基于 Activiti5 的水司OA系统设计与实现[J].软件导刊,2013,12(6):93-95.
[14] Alexander Grosskopf,Gero Decker,Mathias Weske. The Process Business Process Modeling Using BPMN[M].Meghan-Kiffer Press,2009.