Activiti7工作流學習筆記四 組任務及網關

組任務及網關

組任務

Candidate-users 候選人

在流程定義中在任務結點的 assignee 固定設置任務負責人,在流程定義時將參與者固定設置在.bpmn文件中,如果臨時任務負責人變更則需要修改流程定義,系統可擴展性差。
針對這種情況可以給任務設置多個候選人,可以從候選人中選擇參與者來完成任務。

設置任務候選人

在流程圖中任務節點的配置中設置 candidate-users(候選人),多個候選人之間用逗號分開。
在這裏插入圖片描述
查看bpmn文件:
在這裏插入圖片描述
我們可以看到部門經理的審覈人已經設置爲 zhangsan,lishi這樣的一組候選人,可以使用activiti:candiateUsers=”用戶 1,用戶 2,用戶 3”的這種方式來實現設置一組候選人。

辦理組任務

  • 第一步:查詢組任務
    指定候選人,查詢該候選人當前的待辦任務。
    候選人不能辦理任務。
  • 第二步:拾取(claim)任務
    該組任務的所有候選人都能拾取。將候選人的組任務,變成個人任務。原來候選人就變成了該任務的負責人。
    • 如果拾取後不想辦理該任務
      需要將已經拾取的個人任務歸還到組裏邊,將個人任務變成了組任務。
  • 第三步:查詢個人任務
    查詢方式同個人任務部分,根據 assignee 查詢用戶負責的個人任務。
  • 第四步:辦理個人任務

用戶查詢組任務

根據候選人查詢組任務

@Test
public void findGroupTaskList() {
	// 流程定義key
	String processDefinitionKey = "holiday4";
	// 任務候選人
	String candidateUser = "zhangsan";
	// 創建TaskService
	TaskService taskService = processEngine.getTaskService();
	//查詢組任務
	List<Task> list = taskService.createTaskQuery()//
	.processDefinitionKey(processDefinitionKey)//
	.taskCandidateUser(candidateUser)//根據候選人查詢
	.list();
	for (Task task : list) {
		System.out.println("----------------------------");
		System.out.println("流程實例id:" + task.getProcessInstanceId());
		System.out.println("任務id:" + task.getId());
		System.out.println("任務負責人:" + task.getAssignee());
		System.out.println("任務名稱:" + task.getName());
	}
}

用戶拾取組任務

候選人員拾取組任務後該任務變爲自己的個人任務。

@Test
public void claimTask(){
	TaskService taskService = processEngine.getTaskService();
	//要拾取的任務id
	String taskId = "6302";
	//任務候選人id
	String userId = "lisi";
	//拾取任務
	//即使該用戶不是候選人也能拾取(建議拾取時校驗是否有資格)
	//校驗該用戶有沒有拾取任務的資格
	Task task = taskService.createTaskQuery()//
	.taskId(taskId)
	.taskCandidateUser(userId)//根據候選人查詢
	.singleResult();
	if(task!=null){
		//第一個參數:拾取的任務id
		//第二個參數:任務候選人id
		taskService.claim(taskId, userId);
		System.out.println("任務拾取成功");
	} 
}

說明:即使該用戶不是候選人也能拾取,建議拾取時校驗是否有資格
組任務拾取後,該任務已有負責人,通過候選人將查詢不到該任務

用戶查詢個人待辦任務

查詢方式同個人任務查詢

@Test
public void findPersonalTaskList() {
	// 流程定義key
	String processDefinitionKey = "holiday4";
	// 任務負責人
	String assignee = "zhangsan";
	// 創建TaskService
	TaskService taskService = processEngine.getTaskService();
	List<Task> list = taskService.createTaskQuery()
	.processDefinitionKey(processDefinitionKey)
	//設置任務執行人
	.taskAssignee(assignee)
	.list();
	for (Task task : list) {
		System.out.println("----------------------------");
		System.out.println(" 流 程 實 例 id : " + 
		task.getProcessInstanceId());
		System.out.println("任務id:" + task.getId());
		System.out.println("任務負責人:" + task.getAssignee());
		System.out.println("任務名稱:" + task.getName());
	} 
}

用戶辦理個人任務

同個人任務辦理

/**完成任務*/
@Test
public void completeTask(){
	//任務ID
	String taskId = "12304";
	processEngine.getTaskService()//
				.complete(taskId);
	System.out.println("完成任務:"+taskId);
}

說明:建議完成任務前校驗該用戶是否是該任務的負責人

歸還組任務

如果個人不想辦理該組任務,可以歸還組任務,歸還後該用戶不再是該任務的負責人

// 歸還組任務,由個人任務變爲組任務,還可以進行任務交接
@Test
public void setAssigneeToGroupTask() {
	// 查詢任務使用TaskService
	TaskService taskService = processEngine.getTaskService();
	// 當前待辦任務
	String taskId = "6004";
	// 任務負責人
	String userId = "zhangsan2";
	// 校驗userId是否是taskId的負責人,如果是負責人纔可以歸還組任務
	Task task = taskService.createTaskQuery().taskId(taskId)
	.taskAssignee(userId).singleResult();
	if (task != null) {
		// 如果設置爲null,歸還組任務,該 任務沒有負責人
		taskService.setAssignee(taskId, null);
	} 
}

說明:建議歸還任務前校驗該用戶是否是該任務的負責人
也可以通過 setAssignee方法將任務委託給其它用戶負責,注意被委託的用戶可以不是候選人(建議不要這樣使用

任務交接

任務交接,任務負責人將任務交給其它候選人辦理該任務

@Test
public void setAssigneeToCandidateUser() {
	// 查詢任務使用TaskService
	TaskService taskService = processEngine.getTaskService();
	// 當前待辦任務
	String taskId = "6004";
	// 任務負責人
	String userId = "zhangsan";
	// 將此任務交給其它候選人辦理該 任務
	String candidateuser = "lisi";
	// 校驗userId是否是taskId的負責人,如果是負責人纔可以歸還組任務
	Task task = taskService.createTaskQuery().taskId(taskId)
	.taskAssignee(userId).singleResult();
	if (task != null) {
	    //交接任務
		taskService.setAssignee(taskId, candidateuser);
	} 
}

在這裏插入圖片描述
在這裏插入圖片描述

數據庫表操作

  • 任務執行表
    SELECT * FROM act_ru_task記錄當前執行的任務,由於該任務當前是組任務,所有assignee爲空,當拾取任務後該字段就是拾取用戶的 id
    在這裏插入圖片描述
  • 任務參與者
    SELECT * FROM act_ru_identitylink記錄當前參考任務用戶或組,當前任務如果設置了候選人,會向該表插入候選人記錄,有幾個候選就插入幾個
    在這裏插入圖片描述
    若不是候選人顯示爲,參與者
    在這裏插入圖片描述

act_ru_identitylink 對應的還有一張歷史表 act_hi_identitylink,向 act_ru_identitylink 插入記錄的同時也會向歷史表插入記錄。任務完成
在這裏插入圖片描述

網關

排他網關

排他網關(也叫異或(XOR)網關,或叫基於數據的排他網關),用來在流程中實現決策。 當流程執行到這個網關,所有分支都會判斷條件是否爲true,如果爲 true 則執行該分支。

注意,排他網關只會選擇一個爲 true 的分支執行。(即使有兩個分支條件都爲 true,排他網關也會只選擇一條分支去執行)

爲什麼要用排他網關?
不用排他網關也可以實現分支,如下圖:
在這裏插入圖片描述
上圖中,在連線的 condition 條件上設置分支條件。

缺點:

  • 如果條件都不滿足,不使用排他網關,流程就結束了(是異常結束)。
  • condition設置爲總經理holiday.num > 3 ,人事存檔holiday.num >=1時且流程變量設置爲holiday.num = 5,所有條件有成立時,兩個分支會同時執行,流程邏輯出錯。
    在這裏插入圖片描述

如果使用排他網關決定分支的走向,如下:
在這裏插入圖片描述
如果從網關出去的線所有條件都不滿足則系統拋出異常。

org.activiti.engine.ActivitiException: No outgoing sequence flow of the 
exclusive gateway 'exclusivegateway1' could be selected for continuing 
the process
at org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehav
ior.leave(ExclusiveGatewayActivityBehavior.java:85)

說明 :經過排他網關必須要有一條且只有一條分支走。且選擇bpmn文件中Id較小的路徑執行
在這裏插入圖片描述
所有總經理執行。
在這裏插入圖片描述
最終看到整個執行流程如下:
在這裏插入圖片描述

流程定義

在這裏插入圖片描述
在這裏插入圖片描述

測試

在部門經理審覈後,走排他網關,從排他網關出來的分支有兩條,一條是判斷請假天數是否大於 3天,另一條是判斷請假天數是否小於等於 3 天。
設置分支條件時,如果所有分支條件都不是 true,報錯:

org.activiti.engine.ActivitiException: No outgoing sequence flow of the exclusive gateway 
'exclusivegateway1' could be selected for continuing the process
at 
org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior.leave(ExclusiveGatewayActivit
yBehavior.java:85)

並行網關

並行網關允許將流程分成多條分支,也可以把多條分支匯聚到一起,並行網關的功能是基於進入和外出順序流的

  • fork 分支:
    並行後的所有外出順序流,爲每個順序流都創建一個併發分支。
  • join 匯聚:
    所有到達並行網關,在此等待的進入分支, 直到所有進入順序流的分支都到達以後, 流程就會通過匯聚網關。

注意,如果同一個並行網關有多個進入和多個外出順序流, 它就同時具有分支和匯聚功能。 這時,網關會先匯聚所有進入的順序流,然後再切分成多個並行分支。

與其他網關的主要區別是,並行網關不會解析條件。 即使順序流中定義了條件,也會被忽略。(設置條件失效)
在這裏插入圖片描述
說明:

  • 財務結算和入庫是兩個execution分支,在act_ru_execution 表有兩條記錄分別是財務會計和行政考勤,act_ru_execution還有一條記錄表示該流程實例。
  • 待財務會計和行政考勤任務全部完成,在匯聚點匯聚,通過 parallelGateway並行網關。
  • 並行網關在業務應用中常用於會籤任務,會籤任務即多個參與者共同辦理的任務。

流程定義

在這裏插入圖片描述

在這裏插入圖片描述

測試

當執行到並行網關數據庫跟蹤如下

  • 當前任務表:SELECT * FROM act_ru_task
    在這裏插入圖片描述
    上圖中:有兩個(多個)任務當前執行。

  • 流程實例執行表:SELECT * FROM act_ru_execution
    在這裏插入圖片描述
    上圖中,說明當前流程實例有多個分支(兩個)在運行。

  • 對並行任務的執行:
    並行任務執行不分前後,由任務的負責人去執行即可。
    當完成並任務中一個任務後:已完成的任務在當前任務表 act_ru_task已被刪除。

  • 在流程實例執行表:SELECT * FROM act_ru_execution有中多個分支存在且有並行網關的匯聚結點。
    在這裏插入圖片描述
    有並行網關的匯聚結點:說明有一個分支已經到匯聚,等待其它的分支到達。

  • 當所有分支任務都完成,都到達匯聚結點後:
    流程實例執行表:SELECT * FROM act_ru_execution執行流程實例不存在,說明流程執行結束

整個流程完成 act_hi_actinst表中記錄整個過程
在這裏插入圖片描述

包含網關

包含網關可以看做是排他網關和並行網關的結合體。 和排他網關一樣,你可以在外出順序流上定義條件,包含網關會解析它們。 但是主要的區別是包含網關可以選擇多於一條順序流,這和並行
網關一樣。
包含網關的功能是基於進入和外出順序流的。

  • 分支:
    所有外出順序流的條件都會被解析,結果爲 true 的順序流會以並行方式繼續執行, 會爲每個順序流創建一個分支。
  • 匯聚:
    所有並行分支到達包含網關,會進入等待狀態, 直到每個包含流程 token 的進入順序流的分支都到達。 這是與並行網關的最大不同。換句話說,包含網關只會等待被選中執行了的進入順序流。 在匯聚之後,流程會穿過包含網關繼續執行。

流程定義

在這裏插入圖片描述
員工類型:
通過流程變量 userType 來表示,如果等於 1 表示普通員工,如果等於 2 表示領導
在這裏插入圖片描述
注意:通過包含網關的每個分支的連線上設置condition 條件。

測試

如果包含網關設置的條件中,流程變量不存在,報錯;

org.activiti.engine.ActivitiException: Unknown property used in expression: ${userType=='1' || 
userType=='2'}

需要在流程啓動時設置流程變量userType

  • 當執行到包含網關:
    流程實例執行表:SELECT * FROM act_ru_execution
    在這裏插入圖片描述
  1. 第一條記錄:包含網關分支。
  2. 後兩條記錄:兩個分支:常規項體檢,抽血化驗
  • 當前任務表:ACT_RU_TASK_
    在這裏插入圖片描述
    上圖中,常規項體檢,抽血化驗都是當前的任務,在並行執行。

如果有一個分支執行到匯聚:
在這裏插入圖片描述
先走到匯聚結點的分支,要等待其它分支走到匯聚。
等所有分支走到匯聚,包含網關就執行完成。
包含網關執行完成,分支和匯聚就從 act_ru_execution刪除。

小結:在分支時,需要判斷條件,符合條件的分支,將會執行,符合條件的分支最終才進行匯聚。

總結activiti 開發流程

  • 第一步:部署 activiti的環境。
    環境包括:jar包和數據庫(25 張表)
    業務系統通過 springactiviti整合進行開發。
  • 第二步:使用 activiti提供流程設計器(和 ideaeclipse 集成的 designer)工具進行流程定義
    流程定義生成兩個文件:.bpmn.png(不是必須的)。
  • 第三步;將流程定義文件部署到activiti 的數據庫
    1. SELECT * FROM act_re_deployment #流程定義部署表
      一次部署插入一條記錄,記錄流程定義的部署信息
    2. SELECT * FROM act_re_procdef #流程定義表
      一次部署流程定義信息,如果一次部署兩個流程定義,插入兩條記錄
    3. 建議:一次部署只部署一個流程定義,這樣 act_re_deploymentact_re_procdef一對一關係
    4. 常用兩個方法:單個文件部署和 zip 文件部署。
      建議單個文件部署。
  • 第四步: 啓動一個流程實例
    業務系統就可以按照流程定義去執行業務流程,執行前需要啓動一個流程實例
    根據流程定義來啓動一個流程實例。
    指定一個流程定義的key 啓動一個流程實例,activiti根據 key 找最新版本的流程定義。
    指定一個流程定義的 id啓動一個流程實例。
    啓動一個實例需要指定 businesskey(業務標識),businessKeyactiviti和業務系統整合時橋樑。
    比如:請假流程,businessKey就是請假單 id。
    啓動一個實例還可以指定流程變量,流程變量是全局變量(生命期是整個流程實例,流程實例結束,變量就消失)
  • 第五步:查詢待辦任務
    查詢個人任務:使用 taskService,根據 assignee 查詢該用戶當前的待辦任務。
    查詢組任務:使用 taskService,根據 candidateuser 查詢候選用戶當前的待辦組任務。
  • 第六步:辦理任務
    辦理個人任務:調用 taskServicecomplete 方法完成任務。
    如果是組任務,需要先拾取任務,調用 taskServiceclaim 方法拾取任務,拾取任務之後組任務就變成了個人任務(該任務就有負責人)。
  • 網關:
    1. 排他網關:任務執行之後的分支,經過排他網關分支只有一條有效。
    2. 並行網關:任務執行後,可以多條分支,多條分支總會匯聚,匯聚完成,並行網關結束。
    3. 包含網關:是排他網關和並行網關結合體。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章