应用场景:
多个部门发起资金计划,最后统一到财务部审批,每个部门发起资金计划是一个子流程,财务部审批是多个部门的计划同时审批,审批完成后,再提交上级领导审批。
流程如下:
要解决以上问题,需要实现多个子流程并行处理的功能。在Activiti5有一个比较强的节点属性就是多实例,它可以支持多实例的子流程,多实例任务,多实体脚本等。目前支持多实例的节点类型有:
多实例还有并行、串行区分。以下解释一下什么是并行与串行
并行代表同时进行,如把任务分给5个人来处理,这5个人同时会收到任务,并且可以同时处理,不受各自的影响。
串行代表工作或任务由一个人完成后,再由另一个人去处理,直至全部完成,每个任务依赖于前一个任务完成。
会签任务即可以由activiti多实例任务节点来实现,(上一博客有介绍如何开发设计会签任务)
在Activiti的定义中,生成多实例的定义很简单,只需要如下类似去生成以下标签,则可以完成多实例的声明,如下所示,我们要支持并行节点的多实例的定义
多实例人工任务
<userTask activiti:assignee="${assignee}" id="SignTask2" name="财务主管会签"> <extensionElements> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskSignCreateListener" event="create" /> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment" /> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete" /> </extensionElements> <multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}"> <completionCondition>${signComplete.isComplete(execution) } </completionCondition> </multiInstanceLoopCharacteristics> </userTask>
多实例子流程
<subProcess activiti:assignee="${assignee}" id="SubProcess1" name="部门资金计划流程"> <startEvent activiti:initiator="startUser" id="startEvent2" name="开始" /> <endEvent id="endEvent1" name="结束1" /> <userTask id="task3" name="助理填写"> <documentation /> <extensionElements> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCreateListener" event="create" /> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment" /> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete" /> </extensionElements> </userTask> <userTask id="task4" name="部门领导审查"> <documentation /> <extensionElements> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCreateListener" event="create" /> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment" /> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete" /> </extensionElements> </userTask> <sequenceFlow sourceRef="startEvent2" targetRef="task3" id="sequenceFlow1" name="" /> <sequenceFlow sourceRef="task3" targetRef="task4" id="sequenceFlow2" name="" /> <sequenceFlow sourceRef="task4" targetRef="endEvent1" id="sequenceFlow3" name="" /> <extensionElements> <activiti:executionListener event="start" class="com.hotent.platform.service.bpm.listener.StartEventListener" /> <activiti:executionListener event="end" class="com.hotent.platform.service.bpm.listener.EndEventListener" /> </extensionElements> <multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getMultipleUser(execution)}" /> </subProcess>
所以关键的配置属性:
<multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}"> <completionCondition>${signComplete.isComplete(execution) } </completionCondition> </multiInstanceLoopCharacteristics>
我们在控制多实例的个数或人数时,是通过taskUserAssignService的getSignUser获取或getMultipleUser(execution)其集合的个数,从而决定产生多少个实体任务或子流程。
如实现子流程多实例的获取人数,则来自:
/** * 获取多实体子流程的执行用户集合 * @param execution * @return * @throws Execption */ public List<String> getMultipleUser(ActivityExecution execution) throws Exception{ String nodeId=execution.getActivity().getId(); ExecutionEntity executionEnt=(ExecutionEntity) execution; List<String> userIds=(List<String>)execution.getVariable(BpmConst.SUBPRO_MULTI_USERIDS); if(userIds!=null) return userIds; Map<String,FlowNode> nodeMap= NodeCache.getByActDefId(executionEnt.getProcessDefinitionId()); FlowNode subProcessNode=nodeMap.get(nodeId); FlowNode firstNode=subProcessNode.getSubFirstNode(); FlowNode secodeNode=firstNode.getNextFlowNodes().get(0); List<String> userList=nodeUserMapLocal.get().get(secodeNode.getNodeId()); logger.debug("userList size:" + userList.size()); execution.setVariable(BpmConst.SUBPRO_MULTI_USERIDS, userList); return userList; }
因为该方法会被调用多次,所以其实现的思路是第一次其集合是来自用户的界面选择的人员列表,第一次之后,放到流程变量中去,在后续的获取中,直接从流程变量中获取。
然后在任务的创建的监听器中,从流程变量assignee中获取当前任务的执行人。以上的实现还有一细节就是要解决如何查找到子流程中的第一个任务节点,并且把对应的任务人员授给这任务节点。
最终实现的效果如下所示:
http://www.jee-soft.cn/htsite/html/cpjfw/zxjc/bpmx3/2012/08/27/1346037096478.html