Activiti學習記錄(五)
1.排他網關
說明:
1) 一個排他網關對應一個以上的順序流
2) 由排他網關流出的順序流都有個conditionExpression元素,在內部維護返回boolean類型的決策結果。
3) 決策網關只會返回一條結果。當流程執行到排他網關時,流程引擎會自動檢索網關出口,從上到下檢索如果發現第一條決策結果為true或者沒有設置條件的(默認為成立),則流出。
4) 如果沒有任何一個出口符合條件,則拋出異常
使用流程變量,設置連線的條件,並按照連線的條件執行工作流,如果沒有條件符合的條件,則以默認的連線離開。例如
則執行連線:
如果使用流程變量設置
則執行連線:
2.並行網關
說明:
1) 一個流程中流程實例只有
2) 並行網關的功能是基於進入和外出的順序流的:
分支(fork): 並行後的所有外出順序流,為每個順序流都創建一個並發分支。
匯聚(join): 所有到達並行網關,在此等待的進入分支, 直到所有進入順序流的分支都到達以後, 流程就會通過匯聚網關。
3) 並行網關的進入和外出都是使用相同節點標識
4) 如果同一個並行網關有多個進入和多個外出順序流, 它就同時具有分支和匯聚功能。 這時,網關會先匯聚所有進入的順序流,然後再切分成多個並行分支。
5) 並行網關不會解析條件。 即使順序流中定義了條件,也會被忽略。
6)並行網關不需要是“平衡的”(比如, 對應並行網關的進入和外出節點數目不一定相等)。如圖中標示是合法的:
3.開始活動節點
流程圖:
3.1部署流程定義+啟動流程實例+查詢流程實例+查詢歷史流程實例
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); /** * 部署流程定義 */ @Test public void deployProcessDefinition() { InputStream inputStream = this.getClass().getResourceAsStream("start.bpmn"); InputStream inputStreamPic= this.getClass().getResourceAsStream("start.png"); Deployment deploy = processEngine.getRepositoryService().createDeployment().name("開始節點") .addInputStream("start.bpmn", inputStream) .addInputStream("start.png", inputStreamPic) .deploy(); System.out.println("部署ID:"+deploy.getId()); System.out.println("部署名稱:"+deploy.getName()); } /** * 啟動流程實例 */ @Test public void startProcessInstance() { String processDefinitionKey = "start"; ProcessInstance startProcessInstanceByKey = processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey); System.out.println("流程實例ID:"+startProcessInstanceByKey.getId()); System.out.println("流程定義ID:"+startProcessInstanceByKey.getProcessDefinitionId()); /**判斷流程是否接受,查詢正在執行的執行對象表**/ ProcessInstance pi = processEngine.getRuntimeService() .createProcessInstanceQuery() .processInstanceId(startProcessInstanceByKey.getId()) .singleResult(); //說明流程實例結束了 if (pi == null) { /**查詢歷史,獲取流程的相關信息**/ HistoricProcessInstance hpi = processEngine.getHistoryService() .createHistoricProcessInstanceQuery() .processInstanceId(startProcessInstanceByKey.getId()) .singleResult(); System.out.println(hpi.getId()+" "+hpi.getStartTime()+" "+hpi.getEndTime()); } } }
1):結束節點沒有出口
2):其他節點有一個或多個出口。
如果有一個出口,則代表是一個單線流程;
如果有多個出口,則代表是開啟並發流程。
4.接收任務
接收任務是一個簡單任務,它會等待對應消息的到達。 當前,官方只實現了這個任務的java語義。 當流程達到接收任務,流程狀態會保存到數據庫中。
在任務創建後,意味著流程會進入等待狀態, 直到引擎接收了一個特定的消息, 這會觸發流程穿過接收任務繼續執行。
流程圖:
4.1 部署流程定義+啟動流程實例
/** * ReceiceTask任務,機器自動完成的任務 * 只會在act_ru_execution表中產生一條數據 * @throws Exception */ @Test public void testExecution() throws Exception { // 1 發布流程 InputStream inputStreamBpmn = this.getClass().getResourceAsStream("receiveTask.bpmn"); InputStream inputStreamPng = this.getClass().getResourceAsStream("receiveTask.png"); processEngine.getRepositoryService()// .createDeployment()// .addInputStream("receiveTask.bpmn", inputStreamBpmn)// .addInputStream("receiveTask.png", inputStreamPng)// .deploy(); // 2 啟動流程 ProcessInstance pi = processEngine.getRuntimeService()// .startProcessInstanceByKey("receiveTaskDemo"); System.out.println("pid:" + pi.getId()); String pid = pi.getId(); // 3查詢是否有一個執行對象在描述”匯總當日銷售額“ Execution e1 = processEngine.getRuntimeService()// .createExecutionQuery()// .processInstanceId(pid)// .activityId("匯總當日銷售額")// .singleResult(); // 4執行一堆邏輯,並設置流程變量 Map<String,Object> vars = new HashMap<String, Object>(); vars.put("當日銷售額", 10000); // 5流程向後執行一步:往後推移e1,使用signal給流程引擎信號,告訴他當前任務已經完成了,可以往後執行 processEngine.getRuntimeService() .signal(e1.getId(),vars); // 6判斷當前流程是否在”給老板發短信“節點 Execution e2 = processEngine.getRuntimeService()// .createExecutionQuery()// .processInstanceId(pid)// .activityId("給總經理發短信")// .singleResult(); // 7獲取流程變量 Integer money = (Integer) processEngine.getRuntimeService()// .getVariable(e2.getId(), "當日銷售額"); System.out.println("老板,今天賺了" +money); // 8向後執行一步:任務完成,往後推移”給老板發短信“任務 processEngine.getRuntimeService()// .signal(e2.getId()); // 9查詢流程狀態 pi = processEngine.getRuntimeService()// .createProcessInstanceQuery()// .processInstanceId(pid)// .singleResult(); if(pi==null){ System.out.println("流程正常執行!!!,已經結束了"); } }
說明:
1) 當前任務(一般指機器自動完成,但需要耗費一定時間的工作)完成後,向後推移流程,可以調用runtimeService.signal(executionId),傳遞接收執行對象的id。
5. 用戶任務(userTask,即用戶操作的任務)
5.1 個人任務
5.1.1 流程圖
5.1.2 分配個人任務方式一(直接指定辦理人)
流程圖中任務節點的配置
測試代碼:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); /** * 部署流程定義 */ @Test public void deployProcessDefinition() { InputStream inputStream = this.getClass().getResourceAsStream("personalTask.bpmn"); InputStream inputStreamPic = this.getClass().getResourceAsStream("personalTask.png"); Deployment deploy = processEngine.getRepositoryService().createDeployment().name("個人任務") .addInputStream("personalTask.bpmn", inputStream) .addInputStream("personalTask.png", inputStreamPic) .deploy(); System.out.println("部署ID:"+deploy.getId()); System.out.println("部署名稱:"+deploy.getName()); } /** * 啟動流程實例,設置流程變量+獲取流程變量+向後執行一步 */ @Test public void startProcessInstance() { String processDefinitionKey = "personTask"; ProcessInstance startProcessInstanceByKey = processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey); System.out.println("流程實例ID:"+startProcessInstanceByKey.getId()); System.out.println("流程定義ID:"+startProcessInstanceByKey.getProcessDefinitionId()); } /** * 查詢個人任務 */ @Test public void findMyProcess() { String assignee = "張三豐"; List<Task> list = processEngine.getTaskService().createTaskQuery().taskAssignee(assignee).list(); if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任務ID:"+task.getId()); System.out.println("任務名稱:"+task.getName()); System.out.println("任務創建時間:"+task.getCreateTime()); System.out.println("任務辦理人:"+task.getAssignee()); System.out.println("流程實例ID:"+task.getProcessInstanceId()); System.out.println("執行對象ID:"+task.getExecutionId()); System.out.println("流程定義ID:"+task.getProcessDefinitionId()); } } } /** * 完成個人任務 */ @Test public void completMyProcess() { String taskId = "5304"; Map<String, Object> map = new HashMap<>(); processEngine.getTaskService().complete(taskId); } }
5.1.3 分配個人任務方式二(使用流程變量)
流程圖中任務節點的配置
測試代碼
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); /** * 部署流程定義 */ @Test public void deployProcessDefinition() { InputStream inputStream = this.getClass().getResourceAsStream("personalTask.bpmn"); InputStream inputStreamPic = this.getClass().getResourceAsStream("personalTask.png"); Deployment deploy = processEngine.getRepositoryService().createDeployment().name("個人任務") .addInputStream("personalTask.bpmn", inputStream) .addInputStream("personalTask.png", inputStreamPic) .deploy(); System.out.println("部署ID:"+deploy.getId()); System.out.println("部署名稱:"+deploy.getName()); } /** * 啟動流程實例,設置流程變量+獲取流程變量+向後執行一步 */ @Test public void startProcessInstance() { String processDefinitionKey = "personTask"; Map<String, Object> variables = new HashMap<>(); variables.put("userId", "周芷若"); ProcessInstance startProcessInstanceByKey = processEngine.getRuntimeService() .startProcessInstanceByKey(processDefinitionKey,variables);//在啟動實例時,設置流程變量 System.out.println("流程實例ID:"+startProcessInstanceByKey.getId()); System.out.println("流程定義ID:"+startProcessInstanceByKey.getProcessDefinitionId()); } /** * 查詢個人任務 */ @Test public void findMyProcess() { String assignee = "張三豐"; List<Task> list = processEngine.getTaskService().createTaskQuery().taskAssignee(assignee).list(); if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任務ID:"+task.getId()); System.out.println("任務名稱:"+task.getName()); System.out.println("任務創建時間:"+task.getCreateTime()); System.out.println("任務辦理人:"+task.getAssignee()); System.out.println("流程實例ID:"+task.getProcessInstanceId()); System.out.println("執行對象ID:"+task.getExecutionId()); System.out.println("流程定義ID:"+task.getProcessDefinitionId()); } } } /** * 完成個人任務 */ @Test public void completMyProcess() { String taskId = "5605"; Map<String, Object> map = new HashMap<>(); processEngine.getTaskService().complete(taskId); }
5.1.4 分配個人任務方式三(使用類)
1.流程圖中任務節點的配置
2.TaskListenerImpl類,用來設置任務的辦理人
/** * 用來指定任務的辦理人 */ @Override public void notify(DelegateTask delegateTask) { // TODO Auto-generated method stub //指定個人任務的辦理人,也可以指定組任務的辦理人 //個人任務通過類去查詢數據庫,將下一個任務的辦理人查詢獲取,然後通過setAssignee()方法指定任務的辦理人 delegateTask.setAssignee("滅絕師太"); }
3.測試代碼
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); /** * 部署流程定義 */ @Test public void deployProcessDefinition() { InputStream inputStream = this.getClass().getResourceAsStream("personalTask.bpmn"); InputStream inputStreamPic = this.getClass().getResourceAsStream("personalTask.png"); Deployment deploy = processEngine.getRepositoryService().createDeployment().name("個人任務") .addInputStream("personalTask.bpmn", inputStream) .addInputStream("personalTask.png", inputStreamPic) .deploy(); System.out.println("部署ID:"+deploy.getId()); System.out.println("部署名稱:"+deploy.getName()); } /** * 啟動流程實例,設置流程變量+獲取流程變量+向後執行一步 */ @Test public void startProcessInstance() { String processDefinitionKey = "personTask"; /*Map<String, Object> variables = new HashMap<>(); variables.put("userId", "周芷若");*/ ProcessInstance startProcessInstanceByKey = processEngine.getRuntimeService() .startProcessInstanceByKey(processDefinitionKey);//在啟動實例時,設置流程變量 System.out.println("流程實例ID:"+startProcessInstanceByKey.getId()); System.out.println("流程定義ID:"+startProcessInstanceByKey.getProcessDefinitionId()); }
/**可以分配個人任務從一個人到另一個人(認領任務)**/
@Test
public void setAssigneeTask() {
//任務ID
String taskId = "6104";
//指定的辦理人
String userId = "張翠山";
processEngine.getTaskService()
.setAssignee(taskId, userId);
}
說明:
1) 在類中使用delegateTask.setAssignee(assignee);的方式分配個人任務的辦理人,此時張無忌是下一個任務的辦理人
2) 通過processEngine.getTaskService().setAssignee(taskId, userId);將個人任務從一個人分配給另一個人,此時張無忌不再是下一個任務的辦理人,而換成了周芷若
3) 在開發中,可以將每一個任務的辦理人規定好,例如張三的領導是李四,李四的領導是王五,這樣張三提交任務,就可以查詢出張三的領導是李四,通過類的方式設置下一個任務的辦理人
5.1.5 總結
個人任務及三種分配方式:
1:在taskProcess.bpmn中直接寫 assignee=“張三豐"
2:在taskProcess.bpmn中寫 assignee=“#{userID}”,變量的值要是String的。
使用流程變量指定辦理人
3,使用TaskListener接口,要使類實現該接口,在類中定義:
delegateTask.setAssignee(assignee);// 指定個人任務的辦理人
使用任務ID和辦理人重新指定辦理人:
processEngine.getTaskService()//
.setAssignee(taskId, userId);
6 組任務
6.1 流程圖
6.2 分配組任務方式一(直接指定辦理人)
1.流程圖中任務節點的配置
2.測試代碼:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); /** * 部署流程定義 */ @Test public void deployProcessDefinition() { InputStream inputStream = this.getClass().getResourceAsStream("groupTask.bpmn"); InputStream inputStream2 = this.getClass().getResourceAsStream("groupTask.png"); Deployment deploy = processEngine.getRepositoryService().createDeployment().name("組任務") .addInputStream("groupTask.bpmn", inputStream) .addInputStream("groupTask.png", inputStream2) .deploy(); System.out.println("部署ID:"+deploy.getId()); System.out.println("部署名稱:"+deploy.getName()); } /** * 啟動流程實例 */ @Test public void startProcessInstance() { String processDefinitionKey = "groupTask"; ProcessInstance startProcessInstanceByKey = processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey); System.out.println("流程實例ID:"+startProcessInstanceByKey.getId()); System.out.println("流程定義ID:"+startProcessInstanceByKey.getProcessDefinitionId()); } /** * 查詢當前人的組任務 */ @Test public void findMyGroupProcess() { String candidateUser = "小A"; List<Task> list = processEngine.getTaskService().createTaskQuery() .taskCandidateUser(candidateUser) .orderByTaskCreateTime().desc().list(); if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任務ID:"+task.getId()); System.out.println("任務名稱:"+task.getName()); System.out.println("任務創建時間:"+task.getCreateTime()); System.out.println("任務辦理人:"+task.getAssignee()); System.out.println("流程實例ID:"+task.getProcessInstanceId()); System.out.println("執行對象ID:"+task.getExecutionId()); System.out.println("流程定義ID:"+task.getProcessDefinitionId()); } } } /** * 查詢正在執行的組任務辦理人表 */ @Test public void findRunPersonTask() { String taskId = "7104"; List<IdentityLink> list = processEngine.getTaskService() .getIdentityLinksForTask(taskId); if (list != null && list.size() > 0) { for (IdentityLink identityLink : list) { System.out.println(identityLink.getTaskId()+" "+identityLink.getType()+" "+identityLink.getUserId()+" "+identityLink.getProcessInstanceId()); } } } /** * 查詢歷史的組任務辦理人表 */ @Test public void findHistoryPersonTask() { String processInstanceId = "7101"; List<HistoricIdentityLink> list = processEngine.getHistoryService() .getHistoricIdentityLinksForProcessInstance(processInstanceId); if (list != null && list.size() > 0) { for (HistoricIdentityLink hil : list) { System.out.println(hil.getTaskId()+" "+hil.getType()+" "+hil.getUserId()+" "+hil.getProcessInstanceId()); } } } /** * 拾取任務,將組任務分給個人任務,指定任務的辦理人字段 */ @Test public void claim() { String taskId = "7104"; String userId = "小A"; //分配個人任務(可以是組任務中的成員,也可以是非組任務的成員) processEngine.getTaskService().claim(taskId, userId); } /** * 拾取任務,將個人任務回退到組任務,數據執勤一定是個組任務 */ @Test public void setAssginee() { String taskId = "7104"; String userId = "大F"; //分配個人任務(可以是組任務中的成員,也可以是非組任務的成員) processEngine.getTaskService().setAssignee(taskId, null); } /** * 向組任務添加成員 */ @Test public void addGroupUser() { String taskId = "7104"; String userId = "大H"; processEngine.getTaskService().addCandidateUser(taskId, userId); } /** * 向組任務刪除成員 */ @Test public void delGroupUser() { String taskId = "7104"; String userId = "大H"; processEngine.getTaskService().deleteCandidateUser(taskId, userId); } /** * 完成任務 */ @Test public void completProcessTask() { String taskId = "7104"; processEngine.getTaskService().complete(taskId); }
說明:
1) 小A,小B,小C,小D是組任務的辦理人
2) 但是這樣分配組任務的辦理人不夠靈活,因為項目開發中任務的辦理人不要放置XML文件中。
3) act_ru_identitylink表存放任務的辦理人,包括個人任務和組任務,表示正在執行的任務
4) act_hi_identitylink表存放任務的辦理人,包括個人任務和組任務,表示歷史任務
區別在於:如果是個人任務TYPE的類型表示participant(參與者)
如果是組任務TYPE的類型表示candidate(候選者)和participant(參與者)
6.2 分配個人任務方式二(使用流程變量)
1.流程圖中任務節點的配置
2.測試代碼
/** * 部署流程定義 */ @Test public void deployProcessDefinition() { InputStream inputStream = this.getClass().getResourceAsStream("groupTask.bpmn"); InputStream inputStream2 = this.getClass().getResourceAsStream("groupTask.png"); Deployment deploy = processEngine.getRepositoryService().createDeployment().name("組任務") .addInputStream("groupTask.bpmn", inputStream) .addInputStream("groupTask.png", inputStream2) .deploy(); System.out.println("部署ID:"+deploy.getId()); System.out.println("部署名稱:"+deploy.getName()); } /** * 啟動流程實例 */ @Test public void startProcessInstance() { String processDefinitionKey = "groupTask"; Map<String, Object> variables = new HashMap<>(); variables.put("userIds", "大大,中中,小小"); ProcessInstance startProcessInstanceByKey = processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey,variables); System.out.println("流程實例ID:"+startProcessInstanceByKey.getId()); System.out.println("流程定義ID:"+startProcessInstanceByKey.getProcessDefinitionId()); } /** * 拾取任務,將組任務分給個人任務,指定任務的辦理人字段 */ @Test public void claim() { String taskId = "7805"; String userId = "大大"; //分配個人任務(可以是組任務中的成員,也可以是非組任務的成員) processEngine.getTaskService().claim(taskId, userId); } /** * 完成任務 */ @Test public void completProcessTask() { String taskId = "7805"; processEngine.getTaskService().complete(taskId); }
說明:
1) 大大,中中,小小是組任務的辦理人
在開發中,可以在頁面中指定下一個組任務的辦理人,通過流程變量設置下一個任務的辦理人
6.2 分配個人任務方式三(使用類)
1.流程圖中任務節點的配置
2.TaskListenerImpl類,用來設置任務的辦理人
@Override public void notify(DelegateTask delegateTask) { // TODO Auto-generated method stub //組任務: delegateTask.addCandidateUser("郭靖"); delegateTask.addCandidateUser("黃蓉"); }
3.測試代碼
/** * 部署流程定義 */ @Test public void deployProcessDefinition() { InputStream inputStream = this.getClass().getResourceAsStream("groupTask.bpmn"); InputStream inputStream2 = this.getClass().getResourceAsStream("groupTask.png"); Deployment deploy = processEngine.getRepositoryService().createDeployment().name("組任務") .addInputStream("groupTask.bpmn", inputStream) .addInputStream("groupTask.png", inputStream2) .deploy(); System.out.println("部署ID:"+deploy.getId()); System.out.println("部署名稱:"+deploy.getName()); } /** * 啟動流程實例 */ @Test public void startProcessInstance() { String processDefinitionKey = "groupTask"; /*Map<String, Object> variables = new HashMap<>(); variables.put("userIds", "大大,中中,小小");*/ ProcessInstance startProcessInstanceByKey = processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey); System.out.println("流程實例ID:"+startProcessInstanceByKey.getId()); System.out.println("流程定義ID:"+startProcessInstanceByKey.getProcessDefinitionId()); } /** * 查詢當前人的組任務 */ @Test public void findMyGroupProcess() { String candidateUser = "郭靖"; List<Task> list = processEngine.getTaskService().createTaskQuery() .taskCandidateUser(candidateUser) .orderByTaskCreateTime().desc().list(); if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任務ID:"+task.getId()); System.out.println("任務名稱:"+task.getName()); System.out.println("任務創建時間:"+task.getCreateTime()); System.out.println("任務辦理人:"+task.getAssignee()); System.out.println("流程實例ID:"+task.getProcessInstanceId()); System.out.println("執行對象ID:"+task.getExecutionId()); System.out.println("流程定義ID:"+task.getProcessDefinitionId()); } } } /** * 拾取任務,將組任務分給個人任務,指定任務的辦理人字段 */ @Test public void claim() { String taskId = "8104"; String userId = "郭靖"; //分配個人任務(可以是組任務中的成員,也可以是非組任務的成員) processEngine.getTaskService().claim(taskId, userId); } /** * 完成任務 */ @Test public void completProcessTask() { String taskId = "8104"; processEngine.getTaskService().complete(taskId); }
說明:
1) 在類中使用delegateTask.addCandidateUser (userId);的方式分配組任務的辦理人,此時孫悟空和豬八戒是下一個任務的辦理人。
2) 通過processEngine.getTaskService().claim (taskId, userId);將組任務分配給個人任務,也叫認領任務,即指定某個人去辦理這個任務,此時由如來去辦理任務。
註意:認領任務的時候,可以是組任務成員中的人,也可以不是組任務成員的人,此時通過Type的類型為participant來指定任務的辦理人
3) addCandidateUser()即向組任務添加成員,deleteCandidateUser()即刪除組任務的成員。
4) 在開發中,可以將每一個任務的辦理人規定好,例如張三的領導是李四和王五,這樣張三提交任務,由李四或者王五去查詢組任務,可以看到對應張三的申請,李四或王五再通過認領任務(claim)的方式,由某個人去完成這個任務。
6.2 總結
組任務及三種分配方式:
1:在taskProcess.bpmn中直接寫 candidate-users=“小A,小B,小C,小D"
2:在taskProcess.bpmn中寫 candidate-users =“#{userIDs}”,變量的值要是String的。
使用流程變量指定辦理人
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("userIDs", "大大,小小,中中");
3,使用TaskListener接口,使用類實現該接口,在類中定義:
//添加組任務的用戶
delegateTask.addCandidateUser(userId1);
delegateTask.addCandidateUser(userId2);
組任務分配給個人任務(認領任務):
processEngine.getTaskService().claim(taskId, userId);
個人任務分配給組任務:
processEngine.getTaskService(). setAssignee(taskId, null);
向組任務添加人員:
processEngine.getTaskService().addCandidateUser(taskId, userId);
向組任務刪除人員:
processEngine.getTaskService().deleteCandidateUser(taskId, userId);
個人任務和組任務存放辦理人對應的表:
act_ru_identitylink表存放任務的辦理人,包括個人任務和組任務,表示正在執行的任務
act_hi_identitylink表存放任務的辦理人,包括個人任務和組任務,表示歷史任務
區別在於:如果是個人任務TYPE的類型表示participant(參與者)
如果是組任務TYPE的類型表示candidate(候選者)和participant(參與者)
Activiti學習記錄(五)