應用場景:在企業或事業單位,常常須要把一個任務分派給多條線去處理,每條線能夠由一個或多個步驟構成,多條線的任務完成後須要再彙總一塊兒於某個任務上。以下例子爲一個公文下發流程,這個流程就涉及到任務的兩級分發。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