平台使用Activit工作流引擎,其中流程图的绘制使用BPMN2.0规范,BPMN2.0是一个工作流业界标准,规范了大型厂商和开源工作流产品的实现,Activiti5实现了该标准的大部分图元定义和执行语义解释,功能强大,Activiti5可以与IBM、Oracle等大型商用工作流产品流程引擎节点的核心功能媲美,并且为了简化应用、扩充原有功能,Activiti5又自定义了6个扩展元素和15个扩展属性,这些元素和属性能够与BPMN规范相互组合可以实现更多、更实用的业务功能。
BPMN2.0对流程执行语义定义了三类基本要素,它们是日常业务流程的“三板斧”:
Activities(活动)——在工作流中所有具备生命周期状态的都可以称之为“活动”,如原子级的任务(Task)、流向(Sequence Flow),以及子流程(Sub-Process)等
Gateways(网关)——顾名思义,所谓“网关”就是用来决定流程流转指向的,可能会被用作条件分支或聚合,也可以被用作并行执行或基于事件的排它性条件判断
Events(事件)——在BPMN2.0执行语义中也是一个非常重要的概念,像启动、结束、边界条件以及每个活动的创建、开始、流转等都是流程事件,利用事件机制,可以通过事件控制器为系统增加辅助功能,如其它业务系统集成、活动预警等
这三类执行语义的定义涵盖了业务流程常用的Sequence Flow(流程转向)、Task(任务)、Sub-Process(子流程)、Parallel Gateway(并行执行网关)、ExclusiveGateway(排它型网关)、InclusiveGateway(包容型网关)等常用图元
现实业务所有的业务环节都离不开Activities、Gateways和Events,无论是简单的条件审批还是复杂的父子流程循环处理,在一个流程定义描述中,所有的业务环节都离不开Task、Sequence Flow、Exclusive Gateway、Inclusive Gateway,其中Task是一个极具威力的元素,它能描述业务过程中所有能发生工时的行为,它包括User Task、Manual Task、Service Task、Script Task等,可以被用来描述人机交互任务、线下操作任务、服务调用、脚本计算任务等常规功能。
User Task:生成人机交互任务,主要被用来描述需要人为在软件系统中进行诸如任务明细查阅、填写审批意见等业务行为的操作,流程引擎流转到此类节点时,系统会自动生成被动触发任务,须人工响应后才能继续向下流转。常用于审批任务的定义。
Manual Task:线下人为操作任务,常用于为了满足流程图对实际业务定义的完整性而进行的与流程驱动无关的线下任务,即此类任务不参与实际工作流流转。常用于诸如物流系统中的装货、运输等任务的描述。
Service Task:服务任务,通常工作流流转过程中会涉及到与自身系统服务API调用或与外部服务相互调用的情况,此类任务往往由一个具有特定业务服务功能的Java类承担,与User Task不同,流程引擎流经此节点会自动调用Java类中定义的方法,方法执行完毕自动向下一流程节点流转。另外,此类任务还可充当“条件路由”的功能对流程流转可选分支进行自动判断。常用于业务逻辑API的调用。
Script Task:脚本任务,在流程流转期间以“脚本”的声明或语法参与流程变量的计算,目前支持的脚本类型有三种:juel(即JSP EL)、groovy和javascript。在Activiti5.9中新增了Shell Task,可以处理系统外部定义的Shell脚本文件,也与Script Task有类似的功能。常用于流程变量的处理。
1.Activiti中文文档
关于Activiti数据库引擎,请查阅中文文档:
http://www.mossle.com/docs/activiti/index.html
2.Activiti5 API应用
ProcessEngine是Activiti系统的核心接口,七类基础服务接口通过ProcessEngine获取,均采用链式API方式,直观明了,易于使用:
RepositoryService:
流程资源服务的接口,主要用于对流程定义的部署、查询和删除操。新流程的部署使用createDeployment().addResourceXXX().deploy()方法;已部署流程的查询使用createDeploymentQuery()附加查询条件的方式获取;另外可以使用deleteDeployment和deleteDeploymentCascade方法进行流程的删除或级联删除。
TaskService:
任务服务接口,该接口暴露了管理人机交互任务的操作,如任务领取(claiming)、任务完成(completing)和任务指派(assigning),还包括对任务的创建、查询、保存、删除等。
RuntimeService:
运行时服务主要用于启动或查询流程实例,以及流程变量、当前激活状态活动的查询、流程实例的删除等。流程在运行过程中所产生的东西都可以使用该接口进行相关处理。
HistoryService:
流程历史的服务接口。提供对历史流程实例、历史任务的查询和删除操作,从提供的API来看,历史流程的查询其提供了finished和unfinished流程的查询,即是说,HistoryService提供了对已完成和当前正在执行流程的活动/任务查询,这一点似乎与runtimeService提供的查询有些冲突,但其实是有差别的,运行时的信息仅包含任意时刻活动的实际运行状态信息(是从流程运行执行性能上考虑的),而历史信息是对已经固化的信息做简单查询而优化的,其所持有的对象是不同的。
IdentityService:
用户、组管理服务接口,用于管理Group、User的增删改查,并维护Membership,涉及到的API有newUser、newGroup、saveUser、saveGroup、createMembership以及相关的deleteXXX方法。
FormService:
表单服务用于访问表单数据以及在启动新的流程实例时或完成任务时所需的渲染后的表单,提供UI界面辅助用户填写相关值以保存至流程变量。该服务在实际业务应用中并不常用,属于引擎的非核心服务。
ManagementService:
提供流程管理和控制操作的接口服务,和业务流程的运行没有关联关系,比如查询数据库本身的内容、Activiti的版本及序列生成ID规则等,属于引擎的非核心服务。
工作流配置
1.任务节点配置
工作流人刷节点配置提供了一下配置选项:
一、当前节点与流程启动人:
同部门:dept_id相同
同公司:suborg_id相同
属于上级部门:可选支持级别
二、当前节点与上一节点审批人:同部门:dept_id相同
同公司:suborg_id相同
属于上级部门:可选支持级别
三、根据当前单据Bean判断根据bean.FieldValue指定部门
四、根据当前单据Bean判断根据bean.FieldValue指定人
五、自定义:提供接口适配器,实现完成后注册到系统可自动扫描带出来显示为列表,用户可打钩配置,可选一个
2.流程线配置
3.消息抄送
消息抄送实现了在流程节点审批完成时,自动发送消息给指定的人员或用户组,更多详细的消息发送机制可以查阅平台的消息处理模块文档
站内消息
站内消息通过平台内置的websocket消息发送
邮件抄送
邮件消息通过平台内置的邮件服务器配置接口发送消息
APP消息推送
APP消息当前实现了Jpush的消息发送,详细文档资料可以查阅http://www.jpush.cn
短信
平台支持实现与短信网关之间的接口,可以通过自定义一个API完成短信消息的发送
4.定时任务
通用流程场景
1.流程会签
在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任务,这种任务我们称之为会签任务。
这种业务需求也很常见,如一个请款单,领导审批环节中,就需要多个部门领导签字。在流程业务中,我们可以把每
个领导签字的环节都定义为任务,但若这样,这个流程业务有一点是固定的,就是签批人是固定的。而任务是由一个
领导签完再到另一领导,当然也可以由多个领导同时签字。
图:串行会签
传统的用流程业务来解决可以采用以下的做法:
前者在流程业务中,叫串行会签,也即是由一个领导签完再至另一领导签。后者我们称之为并行会签,表示几个领导
同时进行签发,而不清楚最终是谁先签。
图:并行会签
以上的解决方式有两大业务需求下是不能满足的,若会签的领导不是固定的,即可以由上一任务审批人提交前随意进
行选择,另一种是对于会签业务中,要求若其中一部分领导审批通过,即直接往下走,不需要全部领导进行审批。另
外,对于这种情况下,统计最终领导会签的结果也是比较困难的,即对审批单的意见是同意还是否决没有办法清楚。
以上两种业务需求也是很常见的日常需求,但我们若采用了固定的流程节点,则不能实现。在这里,可以采用Activiti
的节点多实例来处理,以上流程则可以简化为下:
图:Activiti的多节点实例会签
图:activiti工作流的配置
如上图所示,该流程实现了从配置的会签节点,结合表单数据动态筛选会签的用户功能。
配置多实例类型为并行,指定流程用户信息来自于一个自定义的表达式,多实例变量名为assignee,同时在多实例节点上可以配置一个用户角色或
多个用户,与普通的节点配置类似。编写代码,其中flowHelper为一个声明的bean
//按用户部门分组生成会签需要的collection数据public List<String> getAssignGroupList(String usersValue) throws Exception { if (!StrTool.isValid(usersValue)) { log.warn("没有找到对应的流程分配人:" + usersValue); return null; } HashMap<String, String> ht = new HashMap<>(); List<String> uids = new ArrayList<>(); String[] users = usersValue.split(","); for (String user : users) { List<IUserDept> list = OrgUtil.getUserDeptList(user); IUserDept dept = list.get(0); String deptid = dept.getDeptId(); String userDeptId = dept.getUserDeptId(); if (ht.containsKey(deptid)) { String data = ht.get(deptid) + "," + userDeptId; ht.put(deptid, data); } else ht.put(deptid, userDeptId); } Iterator iter = ht.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<String, String> entry = (Map.Entry) iter.next(); uids.add(entry.getValue()); } return uids; }
2.模块内的已办待办功能
平台提供了一个统一的已办待办入口,如果在工作流内部需要实现一个下拉的已办待办功能,在永新巡视平台项目中,采用了通过SQL构造出查询结果的方式实现高性能的已办待办功能
<div class="btn-group"> <i class="fa fa-filter" style="color: #7e7f93"></i> <a aria-expanded="false" aria-haspopup="true" role="button" data-toggle="dropdown" class="dropdown-toggle" href="#" id="filterRangertag"> <judp:i18n key="@fliterTable" text="我的待办"/> <span class="caret"></span> </a> <ul class="dropdown-menu" id="filterRanger"> <li><a href="${url}/pageQueryTodoListForWorkType?workflowType=safeckplan&format=json&queryName=queryList&filterQuery=true&queryType=page">我的待办</a></li> <li><a href="${url}/query?format=json&queryName=queryList&filterQuery=true&queryType=page">所有记录 </a></li> </ul></div>