Activiti入门文档
Activiti-相關API
本文介紹與Activiti工作流具體操作相關的API。
第一部分 幾個Service相關的API
1.流程定義API--RepostoryService API
activiti.cfg.xml是一個spring依賴注入的xml文件,其具體內容可以參考
Spring集成activiti
測試類
1.1 部署流程定義
和流程部署相關的表
| act_re_deployment | 部署對象信息表 | 存放流程定義的顯示名稱和部署時間,部署一次增加一條記錄,注意:當流程定義的key相同的情況下,使用的是版本升級 |
| act_re_procdef | 流程定義表 | 存放流程定義的屬性信息,部署每一個新的流程定義都會在這張表中增加一條記錄 |
| act_ge_bytearray | 資源文件表 | 存儲流程定義相關的部署信息,即流程定義文檔的存放地。每部署一次就會增加兩條記錄,一條是關于bpmn規則文件的,一條是圖片的(如果部署時只指定了bpmn一個文件,activiti會在部署時解析bpmn文件內容自動生成流程圖),兩個文件不是很大,都是以二進制形式存儲在數據庫中。 |
| act_ge_property | 主鍵生成策略表 | - |
從classpath部署流程
@Test public void deploymentProcessDefinition_classpath() {Deployment deployment = processEngine.getRepositoryService() // 獲取流程定義和部署對象相關的Service.createDeployment() // 創建一個部署對象.name("helloworld入門程序") //添加部署名稱.addClasspathResource("diagrams/helloworld.bpmn") // 從classpath的資源中加載,一次只能加載一個文件.addClasspathResource("diagrams/helloworld.png") // 從classpath的資源中加載,一次只能加載一個文件.deploy(); // 完成部署System.out.println(deployment.getId()); // 1System.out.println(deployment.getName()); // helloworld入門程序 }從zip部署流程
// 從zip部署流程 // 打包helloworld文件,包含helloworld.bpmn, helloworld.png, 存放到classpath目錄下 @Test public void deploymentProcessDefinition_zip() {InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/helloworld.zip")ZipInputStream zipInputStream = new ZipInputStream(in);// 1.部署流程定義-- activitii.cfg.xml已經在classpath目錄下,直接加載默認的流程引擎即可ProcessEngine processEngine = processEngines.getDefaultProcessEngine();Deployment deployment = processEngine.getRepositoryService() // 獲取流程定義和部署對象相關的Service.createDeployment() // 創建一個部署對象.name("helloworld入門程序") //添加部署名稱.addZipInputStream(zipInputStream) // 指定zip格式的文件完成部署.deploy(); // 完成部署System.out.println(deployment.getId()); // 1System.out.println(deployment.getName()); // helloworld入門程序 }inputStream方式部署
// 通過addInputStream 方式部署流程定義實現--此處從絕對路徑,即classpath下查找bpmn和png資源 @Test public void deploymentProcessDefinition_inputstream() {InputStream bmpnInputstream = this.getClass().getResourceAsStream("/diagrams/processVariables.bpmn");InputStream pngInputstream = this.getClass().getResourceAsStream("/diagrams/processVariables.bpmn");Deployment deployment = processEngine.getRepositoryService().createDeployment().name("流程定義").addInputStream("processVariables.bpmn", bmpnInputstream).addInputStream("processVariables.png", pngInputstream).deploy();System.out.println("DEPLOYMENT_ID: " + deployment.getId());System.out.println("DEPLOYMENT_NAME: " + deployment.getName()); }幾種獲取inputStrem的方式及其異同
當testVariables.bpmn文件存在于 /src/main/java/processDefine/helloworld.bpmn目錄下且下面的代碼在helloworld.bpmn的同目錄下的類中時,有以下幾種獲取InputStream的方式
1.2 查詢流程定義
查詢流程定義
// 查詢流程定義 @Test public void findProcessDefinition() {List<ProcessDefinition> list = processEngine.getRepositoryService() // 與部署和流程定義相關的service.createProcessDefinitionQuery() // 創建一個流程定義查詢// 指定查詢條件,where條件// .deploymentId(deploymentId) // 使用部署對象ID查詢// .processDefinitionId(processDefinitionId) // 使用流程定義Id查詢// .processDefinitionKey(processDefinitionKey) // 使用流程定義的key查詢// .processDefinitionNameLike(processDefinitionNameLike) // 使用流程定義的名稱模糊查詢// 排序// .orderByProcessDefinitionVersion().asc() // 按照版本的升序排序.orderByProcessDefinitionName().desc() // 按照流程定義的名稱降序排序// 返回的結果集.list(); // 返回一個集合列表,封裝流程定義// .singleResult(); // 返回唯一結果集// .count(); // 返回結果集數量// .listPage(firstResult, maxResults); // 分頁查詢if (list != null && list.size() > 0) {for (ProcessDefinition pd:list) {System.out.println("流程定義Id: " + pd.getId()); // 流程定義的key + 版本 + 隨機生成樹System.out.println("流程定義名稱: " + pd.getName()); // 對應helloworld.bpmn文件中的name屬性值System.out.println("流程定義的key: " + pd.getKey()); // 對應helloworld.bpmn文件中的id屬性值System.out.println("流程定義的版本: " + pd.getVersion()); // 流程定義key相同時,版本升級System.out.println("資源名稱bpmn文件: " + pd.getResourceName());System.out.println("資源名稱png文件: " + pd.getDaigramResourceName());System.out.println("部署對象ID: " + pd.DeploymentId());}} }查詢所有最新的流程定義
// 查詢所有最新版本的流程定義 @Test public void findLastVersionProcessDefinition() {List<ProcessDefinition> list = ProcessEngine processEngine = processEngines.getDefaultProcessEngine().createProcessDefinitionQuery().orderByProcessDefinitionVersion().asc() // 使用流程定義的升序排列.list();Map<String, ProcessDefinition> map = new LinkedHashMap<>();if (list != null && list.size() > 0) {for (ProcessDefinition pd : list) {map.put(pd.getKey(), pd);}}List<PorcessDefinition> pdList = new ArrayList<>(map.values());if (pdList != null && pdList.size() > 0) {for (ProcessDefinition pd:pdList) {System.out.println("流程定義Id: " + pd.getId()); // 流程定義的key + 版本 + 隨機生成樹System.out.println("流程定義名稱: " + pd.getName()); // 對應helloworld.bpmn文件中的name屬性值System.out.println("流程定義的key: " + pd.getKey()); // 對應helloworld.bpmn文件中的id屬性值System.out.println("流程定義的版本: " + pd.getVersion()); // 流程定義key相同時,版本升級System.out.println("資源名稱bpmn文件: " + pd.getResourceName());System.out.println("資源名稱png文件: " + pd.getDaigramResourceName());System.out.println("部署對象ID: " + pd.DeploymentId());}} }小結
Key和Name的值為:bpmn文件process節點的id和name的屬性值
<process id="LeaveFlow" name="請假流程" isExecutable="true">
1.3 刪除流程定義
刪除流程定義--根據部署ID刪除
// 刪除流程定義 @Test public void deleteProcessDefinition() {String deploymentId = "1";// 不帶級聯的刪除// 只能刪除沒有啟動的流程,如果流程啟動,就會拋出異常// processEngine.getRepositoryService()// .deleteDeployment(deploymentId);// 級聯刪除// 不管流程是否啟動,都可以刪除processEngine.getRepositoryService().deleteDeployment(deploymentId, true);System.out.println("刪除成功!"); }刪除流程定義--刪除key相同的所有不同版本的流程定義
// 刪除流程定義(刪除key相同的所有不同版本的流程定義) @Test public void deleteProcessDefinitionByKey() {String processDefinitionKey = "helloworld";// 先使用流程定義的key查詢流程定義,查詢出所有的版本List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey).list();// 遍歷刪除 if (list != null && list.size() > 0) {for (ProcessDefinition pd:list) {// 獲取部署IDString deploymentId = pd.getDeploymentId();processEngine.getRepositoryService().deleteDeployment(deploymentId, true);}} }小結
1.4 查看流程圖
// 查看流程圖 @Test public void viewPic() throws IOException {// 將生成的圖片放置到文件夾下String deploymentId = "801"; // act_ge_bytearray 表中的deployment_id字段// 獲取圖片資源名稱List<String> list = processEngine.getRepositoryService().getDeploymentResourceNames(deploymentId); // 兩個值,一個是bpmn文件名,一個是png文件名String resourceName = "";if (list != null && list.size() > 0) {for (String name : list) {if (name.indexOf(".png") >= 0) {resourceName = name;}}}InputStream in = processEngine.getRepositoryService().getResourceAsStream(deploymentId, resourceName);// 將圖片生成到D盤的目錄下File file = new File("D://" + resourceName);// 將輸入流的圖片寫到D盤下FileUtils.copyInputStreamToFile(in, file); }2.運行時RuntimeService API
流程實例對象:ProcessInstance代表流程定義的實例。如范冰冰請了一天的假,她就必須發出一個流程實例的申請。一個流程實例包括了所有的運行節點。我們可以利用這個對象來了解當前流程實例的進度等信息。流程實例就表示一個流程從開始到結束的最大的流程分支,即一個流程中流程實例只有一個。
執行對象:Activiti 用這個對象去描述流程執行的每一個節點。在沒有并發的情況下,Execution就是同 ProcessInstance。流程按照流程定義的規則執行一次的過程,就可以表示執行對象Execution。
流程圖依舊接著第一部分的流程圖(helloworld.bpmn)。
在做后面的啟動流程實例和完成任務的過程中,完成以下查詢。
測試類
public class ProcessInstanceTest {// activitii.cfg.xml已經在classpath目錄下,直接加載默認的流程引擎即可private ProcessEngine processEngine = processEngines.getDefaultProcessEngine(); }2.1 啟動流程實例
// 啟動流程實例 // 默認啟動最新版本的流程 @Test public void startProcessInstance() {String processEngine = "helloworld";ProcessInstance pi = processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey) // 使用流程定義的key啟動實例,key對應helloworld.bpmn中Propertes流程的Id屬性值System.out.println(pi.getId()); // 流程實例Id 101System.out.println(pi.getProcessDefinitionId()); // 流程定義Id: 1:4 }做一下如下查詢
select * from act_ru_execution select * from act_hi_procinst會發現,流程實例和執行對象相同。
2.2 查詢流程狀態
查詢運行時是否存在流程實例來判斷流程是正在進行中還是已結束。
// 查詢流程狀態(判斷流程正在執行,還是結束) @Test public void isProcessEnd() {String processInstanceId = "1001";ProcessInstance pi = processEngine.getRuntimeService() // 正在執行的流程實例和執行對象.createProcessInstanceQuery() // 創建流程實例查詢.processInstanceId(processInstanceId) // 根據流程實例ID查詢.singleResult();if (pi == null) {System.out.println("流程已結束");} else {System.out.println("流程沒有結束");} }3.TaskService API
流程圖接著第一部分的流程圖(helloworld.bpmn)。
測試類接著第二部分的測試類。
3.1 查詢指定人(assignee)的用戶的用戶任務
// 查詢當前人的個人任務 @Test public void findMyPersonTask() {String assignee = "張三";List<Task> list = processEngine.getTaskService() // 與正在執行的任務管理相關的service;.createTaskQuery()// 查詢條件,where部分.taskAssignee(assignee) // 指定個人任務查詢,指定辦理人// .taskCandidateUser(candidateUser) // 組任務的辦理人查詢// .processDefinitionId(processDefinitionId) // 使用流程定義ID查詢// .processInstanceId(processInstanceId) // 使用流程實例ID查詢// .executionId(executionId) // 使用執行對象ID查詢// 排序// .orderByTaskDescription().asc() // // .orderByTaskAssignee().asc() // 按處理// .orderByTaskCreateTime().asc() // 按照創建時間排序// 返回結果集// .singleResult(); // 范圍唯一結果集// .count(); // 返回結果集的數量// .listPage(first, max); // 分頁查詢.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());System.out.println("######################################################");}} }3.2 完成任務
// 完成我的任務 @Test public void completeMyPersonTask() {String taskId = "104";processEngine.getTaskService().complete(taskId);System.out.println("完成任務,任務ID: " + taskId); }4.HistoryService API
測試類
public class HistoryQueryTest {ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); }4.1 查詢指定某人的歷史任務
// 根據歷史任務辦理人查詢歷史任務 @Test public void findHistoryTask() {String taskAssignee = "張三";List<HistoricTaskInstance> list = processEngine.getHistoryService() // 與歷史數據(歷史表)相關的service.createHistoricTaskInstanceQuery().taskAssignee(taskAssignee) // 指定歷史任務的辦理人.list();if (list != null && list.size() > 0 ) {for (HistoricTaskInstance hti: list) {System.out.println(hti.getId() + " " + hti.getName() + " " + hti.getProcessInstanceId() + " " + hti.getStartTime() + " " + hti.getEndTime() + " " + hti.getDurationInMillis());System.out.println("####################################################");}} }4.2 流程執行完后,可以根據流程實例ID查詢流程歷史
流程執行完后,歷史流程實例的endTime,durationInMillis將會有數據,在執行完之前,endTime,durationInMillis為空。
// 根據流程實例ID查詢歷史流程實例 @Test public void findHistoryProcessInstance() {String processInstanceId = "1001";HistoricProcessInstance hpi = processEngine.getHistoryService().createHistoricProcessInstanceQuery() // 歷史流程實例查詢.processInstanceId(processInstanceId) // 使用流程實例ID查詢.singleResult();System.out.println(hpi.getId() + ", " + hpi.getProcessDefinitionId() + ", " + hpi.getStartTime() + ", " + hpi.getEndTime() + ", " + hpi.getDurationInMillis()); }4.3 根據流程實例ID查詢歷史流程實例
@Test public void findHistoryProcessInstanceHistory() {String processInstanceId = "";HistoryProcessInstance hpi = processEngine.getHistoryService().createHisotricProcessInstanceQuery().processInstanceId(processInstanceId().singleResult(); }4.4 根據流程實例ID查詢歷史活動
@Test public void findHisotryActiviti() {String processInstanceId=""List<HistoricActivityInstance> list = processEngine.getHistoryService();.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId()).orderByHistoricActivityInstanceStartTime().asc().list();// 遍歷并打印:活動類型,開始時間,結束時間,活動耗時// sysout: list-> hai: activityType, startTime, endTime, durationInMillis }4.5 根據流程實例ID查詢歷史任務
@Test public void findHistoricTask() {String processInstanceId=""List<HistoricTaskInstance> list = processEngine.getHistoryService();.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).orderByHistoricTaskInstanceStartTime().asc().list();// 遍歷并打印:任務ID,任務名稱,流程實例ID,開始時間,結束時間,任務完成耗時// sysout: list-> hai: id, name, processInstanceId, startTime, endTime, durationInMillis }4.6 根據流程實例ID查詢歷史變量
@Test public void findHistoryVariables() {String processInstanceId=""List<HistoricVariableInstance> list = processEngine.getHistoryService();.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).orderByHistoricTaskInstanceStartTime().asc().list();// 遍歷并打印:流程變量ID,流程實例ID,變量名,變量類型名,變量值// sysout: list-> hai: id, processInstanceId, variableName, variableTypeName, value }第二部分 核心知識點
1.流程變量
流程變量的作用:
和流程變量相關的表:
| act_ru_variable | 正在執行的流程變量表 |
| act_hi_varinst | 歷史的流程變量表 |
測試類定義如下
public class ProcessVariablesTest {ProcessEngine processEngine = ProccessEngines.getDefaultProcessEngine();// 部署流程定義,此處建議采用inputStream方式部署,參考流程定義部分代碼// 啟動流程代碼}processVariables.bpmn
流程變量支持的數據類型
string long double serializable binary date short integer1.1 在任務中設置流程變量--taskService
// 設置流程變量 @Test public void setVariables() {// 與任務相關的,正在執行的TaskService taskService = processEngine.getTaskService();String taskId = "1504";// 設置流程變量,使用基本數據類型taskService.setVariableLocal(taskId, "請假天數", 3); // 與任務ID綁定,當任務流轉到下一個任務時,將不能再查詢到這個參數taskService.setVariable(taskId, "請假日期", new Date());taskService.setVariable(taskId, "請假原因", "回家探親");System.out.println("設置流程變量成功!"); }1.2 獲取流程變量
// 獲取流程變量 @Test public void getVariables() {// 與任務相關的,正在執行的TaskService taskService = processEngine.getTaskService();String taskId = "1504";Integer days = (Integer)taskService.getVariable(taskId, "請假天數");Date date = (Date)taskService.getVariable(taskId, "請假日期");String reason = (String)taskService.getVariable(taskId, "請假原因");System.out.println("請假天數:" + days + ", 請假日期: " + date + ", 請假原因: " + reason); }1.3 其它幾種設置流程變量的方式
用HashMap同時設置多個參數--runtimeService和taskService均可設置流程變量
runtimeService.setVariables(executionId, variables) // variables: Map集合,表示使用執行對象ID和Map集合設置流程變量的名稱,map集合的value就是變量的值taskService.setVariable(taskId, variab****les) // variables: Map集合啟動流程實例時設置流程變量
runtimeService.startProcessInstanceByKey(processDefinitionKey, variables) // 表示啟動流程實例的時候可以設置map參數完成任務時設置流程變量
taskService.complete(taskId, variables) // 表示完成實例的時候可以設置map參數設置流程變量僅在當前任務有效--Local
runtimeService.setVariableLocal(executionId, variableName, value) taskService.setVariableLocal(executionId, variableName, value)1.4 其它幾種獲取流程變量的方式
根據variableName獲取值--runtimeService和taskService均可獲取流程變量
runtimeService.getVariable(executionId, variableName) // 使用執行對象Id,和流程變量的名稱,獲取流程變量的值 taskService.getVariable(taskId, variableName) // 使用任務Id,和流程變量的名稱,獲取流程變量的值根據執行對象ID或taskId獲取鍵值的HashMap集合(全部的)
runtimeService.getVariables(executionId) // 使用執行對象Id,將流程變量放置到Map集合中 taskService.getVariables(taskId) // 使用任務Id,將流程變量放置到Map集合中傳入指定的variableNames(HashMap)獲取鍵值的HashMap集合(指定name的)
runtimeService.getVariables(executionId, variableNames) // 使用執行對象ID獲取流程變量的值,通過設置流程變量的名稱存放到一個集合中,獲取指定流程變量名稱的流程變量值的集合 taskService.getVariables(taskId, variableNames) // 使用任務Id獲取流程變量的值,通過設置流程變量的名稱存放到一個集合中,獲取指定流程變量名稱的流程變量值的集合1.5 匯總
// 模擬設置和獲取流程變量的場景 @Test public void setAndGetVariables() {// 與流程實例,執行對象相關的RuntimeService runtimeService = processEngine.getRuntimeService()// 與任務相關的,正在執行的TaskService taskService = processEngine.getTaskService();// runtimeService.setVariable(executionId, variableName, value) // 表示使用執行對象ID,和流程變量的名稱,設置流程變量的值(一次只能設置一個值)// runtimeService.setVariables(executionId, variables) // variables: Map集合,表示使用執行對象ID和Map集合設置流程變量的名稱,map集合的value就是變量的值// taskService.setVariable(taskId, variableName, value) // taskService.setVariable(taskId, variables) // variables: Map集合// runtimeService.startProcessInstanceByKey(processDefinitionKey, variables) // 表示啟動流程實例的時候可以設置map參數// taskService.complete(taskId, variables) // 表示完成實例的時候可以設置map參數// 獲取流程變量// runtimeService.getVariable(executionId, variableName) // 使用執行對象Id,和流程變量的名稱,獲取流程變量的值// runtimeService.getVariables(executionId) // 使用執行對象Id,將流程變量放置到Map集合中// runtimeService.getVariables(executionId, variableNames) // 使用執行對象ID獲取流程變量的值,通過設置流程變量的名稱存放到一個集合中,獲取指定流程變量名稱的流程變量值的集合// taskService.getVariable(taskId, variableName) // 使用任務Id,和流程變量的名稱,獲取流程變量的值// taskService.getVariables(taskId) // 使用任務Id,將流程變量放置到Map集合中// taskService.getVariables(taskId, variableNames) // 使用任務Id獲取流程變量的值,通過設置流程變量的名稱存放到一個集合中,獲取指定流程變量名稱的流程變量值的集合 }1.6 傳參-javabean
定義Person類
public class Person implements Serializable{private Integer id;private String name;// getter ... setter ... }設置流程變量
Person p = new Person(); p.setId(10); p.setName("翠花"); taskService.setVariable(taskId, "人員信息", p);值得注意的是,serializable類型的參數值是二進制類型的,會存放到 act_ge_bytearray 表中,當一個javabean(實現序列化)放置到流程變量中,要求javabean的屬性不能再發生變化,如果發生變化,再獲取的時候,拋出異常(假定你在Person中再加一個education屬性,那么你再獲取先前set的值,則取不出來了),要解決這個問題,需要給Person類添加序列化ID。
publlic static final long serialVersionUID=253678908763728903L;獲取person
@Test public void getVariables() {Person p = (Person) taskService.getVariable(taskId, "人員信息");System.out.println("person.id = " + p.getId() + ", person.name = " + p.getName()); }1.7 查詢歷史的流程變量
@Test public void findHistoryProcessVariables() {List<HistoricVariableInstancce> list = processEngine.getHistoryService().createHistoricVariableInstanceQuery().variableName("請假天數").list();if(list != null and list.size > 0) {for (HistoricVariableInstancce hvi: list) {System.out.println("id = " + hvi.getId() + ", processInstanceId = " + hvi.getProcessInstanceId()+ ", variableName = " + hvi.getVariableName()+ ", variableValue = " + hvi.getVariableValue());System.out.println("######################");}} }2.連線
流程圖
測試類
public class SequenceFlowTest {ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 部署流程// 啟動流程實例 }參數傳入“不重要”,走連線a
// 完成個人任務 @Test public void completePersonProcess() {String taskId = "";Map<String, Object> variables = new HashMap<>();variables.put("message", "不重要");proccessEngine.getTaskService.complete(taskId, variables);System.out.println("taskId = " + taskId); }參數傳入“重要”,走連線b
// 完成個人任務2 -- 會執行到總經理再結束 @Test public void completePersonProcess() {String taskId = "";Map<String, Object> variables = new HashMap<>();variables.put("message", "重要");proccessEngine.getTaskService.complete(taskId, variables);System.out.println("taskId = " + taskId); }3.排他網關
流程圖
測試類
public class ExclusiveGateWayTest {ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 部署流程// 啟動流程實例 }完成任務--money參數分別傳入800,1200,300
// 完成任務completeMyPersonTask() {String taskId = "";Map<String, Object> variables = new HashMap<>();variables.put("money", 800); // 800 -> 部門經理射頻// 1200 -> 總經理// 300 -> 財務proccessEngine.getTaskService.complete(taskId, variables);sysout: taskId}小結
4.并行網關
并行網關可以表示分支和聚合 -- 流程實例和執行對象將不再是同一個
流程圖
測試類
public class ParallelGateWayTest {ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 部署流程// 啟動流程實例 }依次完成任務
// 完成任務 @Test public void completeMyPersonTask() {String taskId = "";proccessEngine.getTaskService().complete(taskId);sysout: taskId }流程執行過程
當啟動流程實例時
select * from act_ru_execution 3條記錄,一個流程實例,兩個執行對象act_hi_procinst 流程實例的歷史表 1條記錄act_ru_task 正在執行的任務 2個,付款和發貨act_hi_taskinst 歷史任務表 2個,付款和發貨act_hi_actinst 歷史活動 4個,付款,發貨,開始和并行網關當所有任務完成后
select * from act_ru_execution 0act_hi_procinst 流程實例的歷史表 1條記錄act_ru_task 正在執行的任務 0act_hi_taskinst 歷史任務表 4個,付款,發貨,收貨,收款act_hi_actinst 歷史活動 9個,付款,發貨,收貨,收款,開始,結束,并行網關1(分支),并行網關2-商家(聚合),并行網關2-廠家(聚合)小結
分支:并行后的所有外出順序流,為每個順序流都創建一個并發分支
聚合:所有到達并行網關,在此等待的進入分支,直到所有進入順序流的分支都到達以后,流程就會通過匯聚網關
5.開始活動
流程圖
開始活動節點流程圖就是從開始節點直接到結束節點,基本上沒多大意義。
代碼
小結
如果有一個出口,則代表是一個單線流程
如果有多個出口,則代表是開啟并發流程
6.接收任務活動
概念
接收任務是一個簡單任務,它會等待對應消息的到達。當前,官方只實現了這個任務的java語義。當流程達到接收任務,流程狀態會保存到數據庫中。
在任務創建后,意味著流程會進入等待狀態直到引擎接收了一個特定的消息,這會觸發流程穿過接收任務繼續執行。
流程圖
代碼
// 啟動流程實例推斷流程是否結束 + 查詢歷史 @Test public void startProcessInstance() {// 流程定義的keyString processDefinitionKey = "receiveTask";ProcessInstance pi = processEngine.getRuntimeService() // 與正在執行的流程實例和執行對象相關的 Service.startProcessInstanceByKey(processDefinitionKey); // 使用 流程定義的key啟動流程實例,key對應helloworld.bpmn文件中id屬性的值System.out.println("流程實例ID:" + pi.getId());System.out.println("流程實例ID:" + pi.getId());// 查詢執行對象IDExecution execution1 = processEngine.getRuntimeService().createExecutionQuery() // 創建執行對象查詢.processInstanceId(pi.getId()) // 使用流程實例ID查詢.activityId("receivetask1") // 當前活動的id,對應receiveTask.bpmn文件中的活動節點id的屬性值.singleResult();// 使用流程變量設置當日銷售額,用來傳遞業務參數processEngine.getRuntimeService().setVariable(execution1.getId(), "匯總當日銷售額", 21000);// 向后執行一步,如果流程處于等待狀態,使得流程繼續執行processEngine.getRuntimeService().signal(execution1.getId());// 查詢執行對象IDExecution execution2 = processEngine.getRuntimeService().createExecutionQuery() // 創建執行對象查詢.processInstanceId(pi.getId()) // 使用流程實例ID查詢.activityId("receivetask2") // 當前活動的id,對應receiveTask.bpmn文件中的活動節點id的屬性值.singleResult();// 向后執行一步,如果流程處于等待狀態,使得流程繼續執行processEngine.getRuntimeService().signal(execution2.getId());// 執行完后,流程結束 }小結:
7.任務分配
任務分配包括個人任務分配和組任務分配,兩者均存在3種任務分配方式:
- 直接指定辦理人--先前的任務分配均是此種,指定具體的人來辦理;
- 使用流程變量動態分配;
- 實現 org.activiti.engine.delegate.TaskListener 接口動態分配任務。
7.1 個人任務分配
Ⅰ 直接指定任務辦理人
略,前面幾節講的都是直接在流程定義中指定Assignee來指定任務辦理人。
Ⅱ 使用流程變量動態分配任務辦理人
如下圖所示,在任務的Properties中指定Assignee為一個變量${userId}
我們可以在流程啟動時,指定流程變量userId
Map<String, Object> variables = new HashMap<>(); variables.put("userId", "周芷若"); processEngine.getRuntimeService().startProcessInstanceByKey(processInstanceKey, variables);當然,你也可以在其它地方指定流程變量userId,譬如,本次任務完成時,指定下一個任務的辦理人,在某個條件下通過taskService.setVariable(taskId, "userId", "王五");來指定任務辦理人。
Ⅲ 實現 org.activiti.engine.delegate.TaskListener 接口動態分配任務。
先設置Main Config下的Assignee的值為空
在Listener下,指定類 TaskListenerImpl ,實現接口org.activiti.engine.delegate.TaskListener
New的內容如下:
Event=create Type=java class 點擊Select Class去選擇TaskListenerImplTaskListenerImpl 類定義如下
public class TaskListenerImpl implements TaskListener {public void notify(DeletegateTask delegateTask) {// 指定個人任務的辦理人,也可以指定組任務的辦理人// 個人任務:通過類去查詢數據庫,將下一個任務的辦理人查詢獲取,然后通過 setAssignee() 方法指定任務的辦理人delegateTask.setAssignee("滅絕師太");} }在啟動流程實例時,會執行回調函數。
當然,你也可以在指定了任務辦理人后再重新分配任務辦理人(認領任務)。
String taskId = "5804"; String userId = "張翠山"; processEngine.getTaskService()setAssignee(taskId, userId);小結
個人任務及三種分配方式:
最后,還可以通過任務ID和辦理人重新指定辦理人:
processEngine.getTaskService().setAssignee(taskId, userId);7.2 組任務分配
流程圖
和組任務相關的表
a.任務表(個人任務,組任務)
b.歷史任務辦理人表
select * from act_hi_identitylink 該表中,個人任務的TYPE_都為participant(參與者) 每一個組任務用戶的TYPE_包含participant和candidate兩條數據做如下操作
1.部署流程 2.啟動流程實例Ⅰ 直接指定任務辦理人
查詢我的組任務
// 查詢我的組任務 findMyGroupTask() {String candidateUser = "小A";List<Task> list = processEngine.getTaskService.createTaskQuery.taskCandidateUser(candidateUser).orderByTaskCreateTime().asc().list() }查詢正在執行的任務辦理人表
// 查詢正在執行的任務辦理人表 findRunPersonTask() {String taskId = "";List<IdenityLink> list = processEngine.getTaskService.getIdentityLinksForTask(taskId)if list != null && list.size > 0for tl:listsysout: tl -> taskId, type, processInstanceId, userId // 小C, 小D, 小B, 小A }查詢歷史任務的辦理人表
// 查詢歷史任務的辦理人表 findHistoryPersonTask() {String processInstanceId = "";List<HistoricIdentityLink> list = processEngine.getHistoryService.getHistoricIdentityLinksForProcessInstance(processInstanceId)if list != null && list.size > 0for hil:listsysout: tl -> taskId, type, processInstanceId, userId }拾取任務,將組任務分配給個人任務,指定任務的辦理人字段
// 拾取任務,將組任務分配給個人任務,指定任務的辦理人字段 claim() {// 將組任務分配給個人任務String taskId = "";// 分配的個人任務(可以是組任務中的成員,也可以是非組任務的成員)String userId = "小C" // 后再改為大F可以測試非組任務成員,指定了大F之后,再用小A查它的組任務結果為空,可以通過下面的方法改回到組任務proccessEngine.getTaskService.claim(taskId, userId); }將個人任務回退到組任務,前提,之前一定是個組任務
// 將個人任務回退到組任務,前提,之前一定是個組任務 setAssignee() {String taskId ="";processEngine.getTaskService.setAssignee(taskId, null); }向組任務中添加成員
// 向組任務中添加成員 addGroupUser() {String taskId = "";String userId = "大H";processEngine.getTaskService.addCadidateUser(taskId, userId); }從組任務中刪除成員
// 從組任務中刪除成員 deleteGroupUser() {String taskId = "";String userId = "小B";processEngine.getTaskService.deleteCandidateUser(taskId, userId); // 刪除后查詢小B的組任務,結果為空。但刪除僅刪除了小B的候選者數據,并沒有刪除參與者數據。 }說明:
區別在于:
如果是個人任務TYPE的類型表示participant(參與者)
如果是組任務TYPE的類型表示candidate(候選者)和participant(參與者)
Ⅱ 通過流程變量指定組任務成員
修改bpmn文件,指定Candidate users
Main Config/Candidate users: #{userIDs}啟動流程實例時指定組成員
// 啟動流程實例時指定組成員 startProcessInstancevariables.put("userIDs", "大大,中中,小小");之后完成下面的步驟
Ⅲ 使用TaskListener來分配組任務
在bpmn文件中指定Listener
Listenerscreate class TaskListenerImpl implements TaskListener編寫TaskListenerImpl 類
public class TaskListenerImpl implements TaskListener {public void notify(DeletegateTask delegateTask) {delegateTask.addCadidateUser("郭靖")delegateTask.addCadidateUser("黃蓉")// delegateTask.addCadidateUsers(Collection)} }后續完成下面的步驟
說明:
通過processEngine.getTaskService().claim(taskId, userId); 將組任務分配給個人任務,也叫認領任務,即指定某個人去辦理這個任務,此時由郭靖辦理任務。
注意:認領任務的時候,可以是組任務成員中的人,也可以不是組任務成員中的人,此時通過TYPE的類型participant來指定任務的辦理人
在開發中,可以將每一個人物的辦理人規定好,例如張三的領導是李四和王五,這樣張三提交任務,由李四或者王五去查詢組任務,可以看到對應張三的申請李四或王五在通過認領任務(claim)的方式,由某個人去完成這個任務。
小結:
組任務及三種分配方式:
使用流程變量指定辦理人的代碼如下
組任務分配給個人任務
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(參與者)
8. 工作流定義的角色組(了解)
流程圖
注:
- bpmn文件中指定角色組
- Main Config/Candidate groups 指定角色組:部門經理
在deploymentprocessDefinition方法的最后
// 添加用戶角色組 IdentityService identityService = processEngine.getIdentityService() // 創建角色 // GroupEntity是Group接口的子類 identityService.saveGroup(new GroupEntity("總經理")) identityService.saveGroup(new GroupEntity("部門經理")) // 創建用戶 // UserEntity是User接口的子類 identityService.saveUser(new UserEntity("張三")/*.set 去嘗試一下這個操作*/); identityService.saveUser(new UserEntity("李四")); identityService.saveUser(new UserEntity("王五")); // 建立用戶和角色的關聯關系 identityService.createMembership("張三", "部門經理"); identityService.createMembership("李四", "部門經理"); identityService.createMembership("王五", "總經理經理");sysout: 添加組織機構成功!- 部署流程
- 查詢表
- 啟動流程實例
查詢act_ru_identitylink表,可以得知“審批”任務是一個組任務,其TYPE_字段值為candidate,其GROUP_ID的值為部門經理
- 查詢張三的組任務,可以查詢到張三擁有“審批”這個組任務。
- 查詢李四的組任務,可以查詢到李四擁有“審批”這個組任務。
試一下王五呢,(已知:Main Config配置了角色)
- 拾取任務給張三
查詢act_ru_task,就可以看到assignee就有值了,其值為張三
完成任務
【小主,覺得有用打賞點哦!多多少少沒關系,一分也是對我的支持和鼓勵。謝謝!】
轉載于:https://www.cnblogs.com/iuie/p/8006068.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Activiti入门文档的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LINUX系统服务与管理(Service
- 下一篇: 使用断点调试代码