应用场景:在企业或事业单位,常常须要把一个任务分派给多条线去处理,每条线能够由一个或多个步骤构成,多条线的任务完成后须要再汇总一块儿于某个任务上。以下例子为一个公文下发流程,这个流程就涉及到任务的两级分发。html
图一 原流程定义图

图二 执行过程当中流程图java

以上黄色的表明任务分发,紫黄表明任务汇总。
解决方法一:
咱们能够把多个任务线用子流程去实现也能够,这样在分发那里会产生多个子流程,子流程完成后,须要汇总。但如有多级分发与汇总,则须要子流程再嵌套子流程。
解决方法二:
把分发的任务线看成普通的任务来实现,该产生多少个任务可由分发任务决定,这些任务的名称是同样的,但任务实例id不同,执行人不同。
在jbpm4或Activiti5上,动态建立子流程及对子流程的处理上,相对要完成的工做多一些,主要是activity或jbpm4上没有提供这块 api。而动态建立任务在jbpm4或activiti5上也是没有提供的,只有activiti5上提供了一个 taskService.newTask,而该方法产生的新任务则跟流程定义无关,则表示该任务完成后,不能产生后续的任务。在此,咱们先提供 activiti5的解决办法。Jbpm4的解决方法能够参照该方式实现,如下为解决方案的步骤:
1. 第二种解决方案的关键点在于如何动态建立任务,在这里,咱们绕过activiti的API直接对activiti5表进行生成处理,让他生成咱们须要流程数据。
以下所示:node
- /**
- * 按任务Id,复制另外一会签任务出来
- * @param orgTaskId
- * @param assignee
- * @return
- */
- public ProcessTask newTask(String orgTaskId,String assignee)
- {
-
- String newExecutionId=UniqueIdUtil.getNextId();
- String newTaskId=UniqueIdUtil.getNextId();
-
- TaskEntity taskEntity=getTask(orgTaskId);
- ExecutionEntity executionEntity=null;
- if(taskEntity.getExecution()!=null){
- executionEntity=taskEntity.getExecution();
- }else{
- executionEntity=getExecution(taskEntity.getExecutionId());
- }
-
-
- ProcessExecution newExecution=new ProcessExecution(executionEntity);
-
- newExecution.setId(newExecutionId);
-
- ProcessTask newTask=new ProcessTask(taskEntity);
- newTask.setId(newTaskId);
- newTask.setExecutionId(newExecutionId);
- newTask.setCreateTime(new Date());
-
- newTask.setAssignee(assignee);
- newTask.setOwner(assignee);
-
- ProcessTaskHistory newTaskHistory=new ProcessTaskHistory(taskEntity);
- newTaskHistory.setAssignee(assignee);
- newTaskHistory.setStartTime(new Date());
- newTaskHistory.setId(newTaskId);
- newTaskHistory.setOwner(assignee);
-
- executionDao.add(newExecution);
- taskDao.insertTask(newTask);
- taskHistoryDao.add(newTaskHistory);
-
- return newTask;
- }
说明:以上代码写在BpmService类里,关键是从原来的任务中复制一份新的数据出来,同时须要复制其Execution的记录以及执行历史的记录。api
2. 须要记录分发与汇总的节点spa

因此在流程节点的设置上,咱们提供了如下的配置实体。.net
- public class BpmNodeSet extends BaseModel
- {
-
- /**
- * 在线表单
- */
- public static Short FORM_TYPE_ONLINE=0;
- /**
- * URL表单
- */
- public static Short FORM_TYPE_URL=1;
-
- /**
- * 普通任务节点
- */
- public static Short NODE_TYPE_NORMAL=0;
- /**
- * 分发任务节点
- */
- public static Short NODE_TYPE_FORK=1;
-
- // setId
- protected Long setId;
- // 流程定义ID
- protected Long defId;
- // 节点名
- protected String nodeName;
- // Activiti流程定义ID
- protected String actDefId;
- // 节点ID
- protected String nodeId;
- // 表单类型(0:在线表单,1:URL表单)
- protected Short formType=-1;
- // 表单URL
- protected String formUrl;
- // 表单定义ID
- protected Long formDefId;
- // 表单名称
- protected String formDefName;
-
- /**
- * 任务类型:
- * 0=普通任务
- * 1=分发任务
- */
- protected Short nodeType;
-
- /**
- * 当任务类型=1时,能够指定汇总任务Key
- */
- protected String joinTaskKey;
- /**
- * 当任务类型=1时,指定的汇总任务名称
- */
- protected String joinTaskName;
- ...
-
- }
而后在任务的建立及完成的事件里加上监听若当前的任务为分发任务,则动态产生分发的任务。若为汇总任务,则只产生最后一个汇总,以避免得由Activiti产生多个汇总任务。
在监听事件建立分发任务(TaskCreateListener.java类)线程
- BpmNodeSet bpmNodeSet=bpmNodeSetService.getByActDefIdNodeId(actDefId, nodeId);
- if(bpmNodeSet!=null && BpmNodeSet.NODE_TYPE_FORK.equals(bpmNodeSet.getNodeType())){//当前任务为分发任务
- Map<String,List<String>> nodeUserMap=taskUserAssignService.getNodeUserMap();
- //若当前的线程里包含了该任务对应的执行人员列表,则任务的分发用户来自于此
- if(nodeUserMap!=null && nodeUserMap.get(nodeId)!=null){
- List<String> userIds=nodeUserMap.get(nodeId);
- bpmService.newForkTasks((TaskEntity)delegateTask, userIds);
- //产生分发记录,以方便后续的任务汇总处理
- taskForkService.newTaskForks(delegateTask,bpmNodeSet.getJoinTaskName(), bpmNodeSet.getJoinTaskKey(), userIds.size());
- }else{
- ForkUser forkUser=taskUserAssignService.getForkUser();
- if(forkUser!=null){
- bpmService.newForkTasks((TaskEntity)delegateTask, forkUser.getForkUserIdsAsList());
-
- }
- }
-
- }
以上代码中,分发任务的建立对应的人员来自表单中指定的人员。
任务汇总时,咱们须要记录完成的状况,若为汇总节点,咱们会根据汇总完成的状况,进行处理,若汇总的任务尚没有所有完成,后续产生的汇总任务咱们则采用删除策略,该方法定义在BpmService类中。orm
- /**
- * 检查及删除重复的汇总任务
- * @param processInstanceId
- */
- public void deleteRepeatJoinTask(String processInstanceId){
- List<TaskEntity> taskList=getTasks(processInstanceId);
- for(TaskEntity task:taskList){
- //判断后续的节点是否为汇总节点,如果,则须要检查是否须要产生后续的任务
- BpmNodeSet joinNodeSet=bpmNodeSetService.getByActDefIdJoinTaskKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
- if(joinNodeSet!=null){
- TaskFork taskFork=taskForkService.getByInstIdJoinTaskKey(task.getProcessInstanceId(), task.getTaskDefinitionKey());
- if(taskFork!=null){
- if(taskFork.getFininshCount()<taskFork.getForkCount()-1){
- taskService.deleteTask(task.getId());
- //更新完成任务的个数
- taskFork.setFininshCount(taskFork.getFininshCount()+1);
- taskForkService.update(taskFork);
- }else{
- taskForkService.delById(taskFork.getTaskForkId());
- }
- }
- }
- }
- }
最终实现的效果能够以下所示:htm


在线演示连接以下:事件
http://www.jee-soft.cn/htsite/html/cpjfw/zxjc/bpmx3/2012/07/04/1341394649218.html