目錄
目錄:activiti 目錄
一、啟動流程實例
啟動流程的方法多種,這里詳細介紹啟動流程的整個過程!
1.1 操作流程實例的門面接口
我們已知,流程的部署和流程實例數據的門面接口是:RepositoryService
操作流程實例的門面接口是:RuntimeService。在源碼中這個類上沒有備注,只有些作者名稱,但是我們根據方法可以分析出來,RuntimeService有哪些作用
此接口與流程部署和定義操作的接口RepositoryService一樣;
提供了豐富的操作實例的方式,重點分為:
1)startxxx:以start開頭的啟動流程實例方法。
2)deleteProcessInstance:刪除正在執行的流程
3)getxxx:以get開頭的獲取流程實例(活動中或者等待中)相關信息,id列表,實例列表等等
4)trigger:觸發器形式,可以指定流程ID,和一些參數,指定流程執行。
5)builder:獲取流程實例構造器
6)一些其他操作:流程構造器、參數的獲取,修改,添加等等
1.2 前置知識
-
部署一個流程代碼(隨便選擇一個方式部署)
/** * 部署一個流程並返回部署的ID, * 部署表:act_re_deployment 插入一條數據,並在資源表中記錄對應的資源(圖片文件、bpmn文件),二進制存儲。並將流程的數據插入流程數據表 * 資源表:act_ge_bytearray 插入對應的資源數據,可能多條,看傳入多少文件。 * 流程數據表:act_re_procdef 插入流程對應的定義數據。 * @author caodahuan * @date 2019/8/29 * @return java.lang.String */ private String deployProcess(){ // 1. 獲取到部署新流程的構造器 DeploymentBuilder builder = ProcessEngines.getDefaultProcessEngine().getRepositoryService().createDeployment(); // 2. 選擇部署方式為:通過資源文件進行部署 builder.addClasspathResource("apply.bpmn"); builder.addClasspathResource("apply.png"); // 3. 設置一些需要的參數(非必須) builder.key("key"); // 設置key,可重復但不建議重復,可用來啟動流程 builder.name("報銷流程"); // 設置流程名稱 builder.category("3"); // 流程類型 // 4. 部署流程 Deployment deploy = builder.deploy(); System.out.println(deploy.getId()); return deploy.getId(); }
-
獲取流程定義數據
/** * 獲取到流程定義,返回表中數據 * 流程定義數據在表act_re_procdef表中。 * @author caodahuan * @date 2019/8/29 * @return void */ private ProcessDefinition getDefinition() { // 1. 部署流程並返回流程ID String deploymentId = this.deployProcess(); ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery(); query.orderByDeploymentId(); query.desc(); query.deploymentId(deploymentId); List<ProcessDefinition> list = query.list(); if (!CollectionUtils.isEmpty(list)) { return list.get(0); } return null; }
1.3 啟動已經部署好的流程實例
-
先定義一個獲取實例操作接口的方法
/** * 獲取到操作流程實例的總接口 * @author caodahuan * @date 2019/8/29 * @return void */ public RuntimeService getService(){ // 1. 先獲取流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); /* * 2. 獲取操作實例的接口 * 此接口與流程部署和定義操作的接口RepositoryService一樣; * 提供了對豐富的操作方式,重點分為: * 1)startxxx:以start開頭的啟動流程實例方法。 * 2)deleteProcessInstance:刪除正在執行的流程 * 3)getxxx:以get開頭的獲取流程實例(活動中或者等待中)相關信息,id列表,實例列表等等 * 4)trigger:觸發器形式,可以指定流程ID,和一些參數,指定流程執行。 * 5)builder:獲取流程實例構造器 * 6)一些其他操作:流程構造器、參數的獲取,修改,添加等等 * */ RuntimeService runtimeService = processEngine.getRuntimeService(); return runtimeService; }
-
方法一:根據流程定義表中的ID啟動。此處ID,取流程定義數據表:act_re_procdef表中對應數據ID。
/** * 啟動流程實例: * 方法一:根據流程定義的ID; * 已經知道,在部署流程的時候,我們將流程的數據寫到了表:act_re_prcodef * 通過表act_re_prcodef獲取到流程,然后啟動流程! * @author caodahuan * @date 2019/8/29 * @return void */ @Test public void startMethodOne(){ // 1. 獲取到操作流程數據的接口 RuntimeService service = getService(); /* * 2. 根據ID啟動流程,返回的是啟動流程后的實例 * 部署流程后,流程數據其實存儲在act_re_procdef表中。根據id啟動,即根據act_re_procdef表的id啟動。 * 1)根據流程獲取流程定義數據的ID * 2)根據ID啟動流程 */ // 部署好的流程定義數據 ProcessDefinition definition = this.getDefinition(); System.out.println(definition.getId()); /* * 根據流程定義數據表中的ID啟動流程 * 啟動流程后:操作以下表(可以在整個過程中觀察這些表,看看效果,理解更深入) * 1、正在執行的流程實例表: * act_ru_execution(正在執行的流程實例表):表示執行中的流程,會插入2條數據,一條父數據表示流程, * 一條子數據表示正在執行的流程進展。(完成的實例將被刪除) * act_ru_task(正在執行的任務表):表示正在執行的任務。(完成的任務將被刪除) * 歷史表: * act_hi_taskinst(任務歷史表):插入一條數據,通過execution_id_關聯到流程執行表act_ru_execution; * (此表存儲已經完成的和正在執行的流程節點)如果end_time有值,表示已經結束(歷史);沒值,表示正在執行的節點。 * act_hi_procinst(實例歷史表):插入一條數據,通過proc_def_id_關聯到流程定義表act_re_procdef; * (此表存儲已經完成的和正在執行的實例)如果end_time有值,表示已經結束(歷史);沒值,表示正在執行的實例。 * act_hi_actinst(元素歷史表):插入2條數據,一條startEvent數據,啟動元素完成。一條userTask,正在執行元素。 * (此表存儲已經完成的和正在執行的元素)如果end_time有值,表示已經結束(歷史);沒值,表示正在執行的元素。 */ service.startProcessInstanceById(definition.getId()); }
-
方法二:根據流程定義數據的key啟動:act_re_procdef表中key
/** * 方法二:根據流程定義(act_re_procdef)中的KEY啟動流程實例 * 通過方法一知道了總的流程,此處就不再展示完整的獲取流程。直接從表中獲取KEY值。 * @author caodahuan * @date 2019/8/30 * @return void */ @Test public void startMethodTwo(){ // 1. 獲取流程實例操作接口 RuntimeService service = getService(); // 2. 從表中已經知道了key ProcessInstance apply = service.startProcessInstanceByKey("apply"); }
-
方法三:通過ProcessInstanceBuilder
/** * 方法三:通過ProcessInstanceBuilder來啟動流程 * @author caodahuan * @date 2019/9/3 * @return void */ @Test public void queryInstanceByBuilder(){ // 1.操作接口 RuntimeService service = getService(); // 2.獲取流程構建器(builder就是用來操作實例的構建器) ProcessInstanceBuilder processInstanceBuilder = service.createProcessInstanceBuilder(); // 3.填充參數,通過definitionID或者definitionKey啟動,但是可以設置流程參數! processInstanceBuilder.name("自定義builder啟動"); processInstanceBuilder.businessKey("appxx"); processInstanceBuilder.processDefinitionId("apply:3:115004"); // 4.啟動流程 ProcessInstance instance = processInstanceBuilder.start(); System.out.println(instance.getId()); }
-
方法四:還有多種啟動方法:
1.4 查詢已經啟動的流程實例(ProcessInstance)
-
方法一:根據查詢條件,查詢流程list
/** * 方法一:根據流程實例查詢器:ProcessInstanceQuery得到list * 如果用過mybatis提供的Example查詢接口,大概能很容易理解這種處理方式。 * @author caodahuan * @date 2019/9/3 * @return void */ @Test public void queryInstanceList(){ // 1. 獲取到操作實例的接口 RuntimeService service = getService(); // 2. 構建一個查詢器,它專用來查詢實例 ProcessInstanceQuery processInstanceQuery = service.createProcessInstanceQuery(); // 3. 如果查詢得到list,必須排序; processInstanceQuery = processInstanceQuery.processDefinitionKey("apply"); processInstanceQuery.orderByProcessDefinitionId(); processInstanceQuery.asc(); List<ProcessInstance> list = processInstanceQuery.list(); list.forEach(l -> System.out.println(l.getId())); }
-
方法二:查詢得到唯一記錄singleResult
/** * 方法二:根據流程實例查詢器:ProcessInstanceQuery得到singleResult * 可以通過查詢list的方式,然后判斷list的size == 1,再直接調用singleResult。 * 並不是只有ID才能得到唯一數據,都可以調用singleResult,只不過,如果得到的不是唯一數據,會報異常! * @author caodahuan * @date 2019/9/3 * @return void */ @Test public void queryInstanceSingle(){ // 1. 獲取到操作實例的接口 RuntimeService service = getService(); // 2. 構建一個查詢器,它專用來查詢實例 ProcessInstanceQuery processInstanceQuery = service.createProcessInstanceQuery(); // 3. 如果查詢可得到唯一條目,可使用singleResult()直接得到實例。 // 通過多條件得到唯一數據 processInstanceQuery = processInstanceQuery.processDefinitionKey("apply"); processInstanceQuery.processInstanceBusinessKey("ap"); ProcessInstance processInstance = processInstanceQuery.singleResult(); System.out.println(processInstance.getId()); // 更靠譜的是通過id得到唯一數據 processInstanceQuery.processInstanceId("155005").singleResult(); }
-
完成一個流程后,下列表的情況(更細節的數據變化,需要在完成每一個任務的時候觀察表數據的變化才能有深入體會,依然是這幾張表)
完成任務(會在任務操作中再述)
完成任務方法
- 方法一:直接通過taskId來完成任務
/**
* 完成任務1:通過taskId來完成
* 因為完成通過TaskService。
* @author caodahuan
* @date 2019/8/30
* @return void
*/
@Test
public void complete(){
// 1. 獲取到流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
/*
* 2. 對於任務的操作:TaskService。
* 操作任務表:act_ru_task,此表已經介紹過:存儲正在執行的任務,一旦任務執行完,則從此表中移除。
*/
TaskService taskService = processEngine.getTaskService();
taskService.complete("107502");
}
-
方法二:在實際中通過代碼獲取task任務,再獲取到ID
/** * 完成任務實例:實際操作中都是通過查庫來獲取任務,完成任務。 * @author caodahuan * @date 2019/9/2 * @return void */ @Test public void complete1(){ /* * 啟動流程 */ // 1. 獲取到操作流程數據的接口 RuntimeService service = getService(); /* * 2. 根據ID啟動流程,返回的是啟動流程后的實例 * 部署流程后,流程數據其實存儲在act_re_procdef表中。根據id啟動,即根據act_re_procdef表的id啟動。 * 1)根據流程獲取流程定義數據的ID * 2)根據ID啟動流程 */ // 部署好的流程定義數據(返回流程實例) ProcessDefinition definition = this.getDefinition(); ProcessInstance instance = service.startProcessInstanceById(definition.getId()); // 3. 獲取任務操作接口 TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService(); // 4. 由於complete方法是通過taskId來執行,那么先獲取Task詳情。 // 4.1 獲取任務查詢器(這個已經見過多次了) TaskQuery taskQuery = taskService.createTaskQuery(); // 4.2 查詢任務(通過流程實例來獲取任務,部署流程時,已經得到了流程實例) Task task = taskQuery.processInstanceId(instance.getId()).singleResult(); // 4.3 通過任務ID來執行任務 taskService.complete(task.getId()); }
-
方法三:介紹其他完成任務方法
/** * 其他完成任務方法 * @author caodahuan * @date 2019/9/2 * @return void */ @Test public void completeOther(){ // 1. 獲取任務操作接口 TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService(); // 直接ID完成任務(已經描述) taskService.complete("112509"); // 完成並設置變量:參數1=taskId,參數2=流程變量 Map<String, Object> params = new HashMap<>(); params.put("haha","enlo"); taskService.complete("127503",params); // 完成並設置變量:參數1=taskId,參數2=流程變量,參數3=瞬時變量 // 為啥不能用呢,報錯:java.lang.ClassCastException,待解決! taskService.complete("127503",params,params); // 完成並設置變量:參數1=taskId,參數2=流程變量,參數3=是否為本地變量 //如果為true,通過的變量將會隨着本任務存亡(本任務結束,變量刪除,稱之為任務變量(局部)),默認為false,即為complete(String,Map) // 那么這時候的變量為流程變量(全局) taskService.complete("127503",params,false); }
關於流程變量:(傳遞上下文)
按照作用域可分為:
- 流程變量(全局變量):整個流程都可獲取到。
- 本地變量:本任務節點可獲取,下個任務節點就拿不到了。
按照是否存庫:
- 持久變量:在act_ru_variable和act_hi_varinst中插入變量數據
- 瞬時變量(activiti 6):只有轉成持久變量才會存庫