Activiti中工作流的生命周期詳細解析!一個BPMN流程示例帶你認識項目中流程的生命周期

      網友投稿 1370 2025-03-31

      BPMN 2.0介紹

      業務流程模型注解(BusinessProcess Modeling Notation - BPMN)是業務流程模型的一種標準圖形注解.這個標準是由對象管理組(Object Management Group - OMG)維護的

      BPMN規范的2.0版本允許添加精確的技術細節在BPMN的圖形和元素中,同時制定BPMN元素的執行語法.通過使用XML語言來指定業務流程的可執行語法,BPMN規范已經演變為業務流程的語言,可以執行在任何兼容BPMN2的流程引擎中,同時依然可以使用強大的圖形注解

      簡單來說,BPMN即圖標與標簽的結合

      定義一個流程

      創建一個新的XML文件并命名,確認文件后綴為 .bpmn20.xml或 .bpmn, 否則引擎無法發布

      BPMN 2.0根節點是definitions節點. 這個元素中,可以定義多個流程定義(不過建議每個文件只包含一個流程定義, 可以簡化開發過程中的維護難度)

      一個空的流程定義如下所示:注意definitions元素最少也要包含xmlns和 targetNamespace的聲明

      targetNamespace可以是任意值,它用來對流程實例進行分類

      ..

      可以選擇添加線上的BPMN 2.0格式位置:

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd

      ==process元素有兩個屬性:==

      id: 這個屬性是必須的,對應著Activiti ProcessDefinition對象的key屬性.id可以用來啟動流程定義的流程實例,通過RuntimeService的startProcessInstanceByKey方法

      ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");

      ==注意:== 它和startProcessInstanceById方法不同:這個方法期望使用Activiti引擎在發布時自動生成的id.可以通過調用processDefinition.getId() 方法獲得這個值,生成的id的格式為 key:version, 最大長度限制為64個字符, 如果在啟動時拋出了一個ActivitiException: 說明生成的id太長了,需要限制流程的key的長度

      name: 這個屬性是可選的, 對應ProcessDefinition的name屬性.引擎自己不會使用這個屬性,是用來在用戶接口顯示便于閱讀的名稱

      BPMN流程示例前提

      已經安裝Activiti并且能夠運行Activiti Demo

      使用了獨立運行的H2服務器

      修改db.properties,設置其中的jdbc.url=jdbc:h2:tcp://localhost/activiti,然后啟動獨立服務器

      目標

      學習Activiti和一些基本的BPMN 2.0概念

      最終結果是一個簡單的Java SE程序可以發布流程定義,通過Activiti引擎API操作流程

      使用一些Activiti相關的工具,構建自己的業務流程web應用

      用例

      每個月都要給公司領導一個金融報表,由會計部門負責

      當報表完成時,一個上級領導需要審批文檔,然后才能發給所有領導

      流程圖

      流程的圖形化BPMN 2.0標記:

      空開始事件(左側圓圈),后面是兩個用戶任務:制作月度財報和驗證月度財報,最后是空結束事件(右側粗線圓圈)

      XML內容

      在業務流程的XML中很容易找到流程的主要元素:

      (空)開始事件是流程的入口

      第一個任務分配給accountancy組

      Activiti中工作流的生命周期詳細解析!一個BPMN流程示例帶你認識項目中流程的生命周期

      第二個任務分配給management組

      當流程達到空結束事件就會結束

      這些元素都使用連線連接,這些連線擁有source和target屬性,定義了連線的方向

      Write monthly financial report for publication to shareholders. accountancy Verify monthly financial report composed by the accountancy department. This financial report is going to be sent to all the company shareholders. management

      啟動一個流程實例

      創建好業務流程的流程定義,就可以創建流程實例

      一個流程實例對應了特定月度財報的創建和審批,所有流程實例都共享同一個流程定義

      為了使用流程定義創建流程實例,首先要發布業務流程:

      流程定義會保存到持久化的數據存儲里,是為Activiti引擎特別配置的.所以部署好業務流程,在引擎重啟后還能找到流程定義

      BPMN 2.0流程文件會解析成內存對象模型, 可以通過Activiti API操作

      通過下面的API發布流程,所有與Activiti引擎的交互都是通過services

      Deployment deployment = repositoryService.createDeployment() .addClasspathResource("FinancialReportProcess.bpmn20.xml") .deploy();

      啟動一個新流程實例,使用我們定義在流程定義里的id(對應XML文件中的process元素).==注意這里的id對于Activiti來說,應該叫做key==,一般在流程模型中使用的ID,在Activiti中都是Key:比如任務ID

      ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("financialReport");

      這樣創建一個流程實例:

      首先進入開始事件

      開始事件之后,它會沿著所有的外出連線執行,到達第一個任務(“制作月度財報”)

      Activiti會把一個任務保存到數據庫里.這時,分配到這個任務的用戶或群組會被解析,也會保存到數據庫里

      需要注意,Activiti引擎會繼續執行流程的環節,除非遇到一個 等待狀態:比如用戶任務

      在等待狀態下,當前的流程實例的狀態會保存到數據庫中.直到用戶決定完成任務才能改變這個狀態

      這時,引擎會繼續執行,直到遇到下一個等待狀態,或流程結束

      如果中間引擎重啟或崩潰,流程狀態也會安全的保存在數據庫里

      任務創建之后,startProcessInstanceByKey會在到達用戶任務這個等待狀態之后才會返回.這時,任務分配給了一個組,這意味著這個組是執行這個任務的候選組

      現在將所有東西都放在一起,來創建一個簡單的java程序:

      創建一個Java項目,把Activiti的jar和依賴放到classpath下:這些都可以在Activiti發布包的libs目錄下找到

      在調用Activiti服務之前,我們必須構造一個ProcessEngine,可以讓我們訪問服務

      這里我們使用[單獨運行]的配置,這會使用demo安裝時的數據庫來構建ProcessEngine

      public static void main(String[] args) { // Create Activiti process engine ProcessEngine processEngine = ProcessEngineConfiguration .createStandaloneProcessEngineConfiguration() .buildProcessEngine(); // Get Activiti services RepositoryService repositoryService = processEngine.getRepositoryService(); RuntimeService runtimeService = processEngine.getRuntimeService(); // Deploy the process definition repositoryService.createDeployment() .addClasspathResource("FinancialReportProcess.bpmn20.xml") .deploy(); // Start a process instance runtimeService.startProcessInstanceByKey("financialReport"); }

      任務列表

      可以通過TaskService來獲得任務,添加以下邏輯:

      List tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list();

      注意傳入的用戶必須是accountancy組的一個成員,要和流程定義中相對應:

      accountancy

      也可以使用群組名稱,通過任務查詢API來獲得相關的結果.在代碼中添加如下邏輯:

      TaskService taskService = processEngine.getTaskService(); List tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();

      因為配置的ProcessEngine使用了與demo相同的數據,可以登錄到Activiti Explorer.默認,accountancy(會計)組里沒有任何人:

      登錄

      點擊組

      創建一個新組

      點擊用戶

      把組分配給fozzie

      使用fozzie/fozzie登錄

      就可以啟動我們的業務流程了,選擇Processes頁,在[月度財報]的[操作]列點擊[啟動流程]

      流程會執行到第一個用戶任務.因為我們以kermit登錄,在啟動流程實例之后,就可以看到有了一個新的待領任務.選擇任務頁來查看這條新任務.注意即使流程被其他人啟動,任務還是會被會計組里的所有人作為一個候選任務看到

      領取任務

      現在一個會計要認領這個任務

      認領以后,這個用戶就會成為任務的執行人,任務會從會計組的其他成員的任務列表中消失.認領任務的代碼:

      taskService.claim(task.getId(), "fozzie");

      任務會進入認領任務人的個人任務列表:

      List tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();

      在Activiti Explorer UI中,點擊認領按鈕,會執行相同的操作.任務會移動到登錄用戶的個人任務列表.你也會看到任務的執行人已經變成當前登陸的用戶:

      完成任務

      現在會計可以開始進行財報的工作

      報告完成后,他可以完成任務,意味著任務所需的所有工作都完成

      taskService.complete(task.getId());

      對于Activiti引擎:

      需要一個外部信息來讓流程實例繼續執行

      任務會把自己從運行庫中刪除

      流程會沿著單獨一個外出連線執行,移動到第二個任務(審批報告)

      與第一個任務相同的機制會使用到第二個任務上,不同的是任務是分配給management組

      在demo中:

      完成任務是通過點擊任務列表中的完成按鈕

      因為Fozzie不是會計,我們先從Activiti Explorer注銷

      然后使用kermit登陸(經理),第二個任務會進入未分配任務列表

      結束流程

      審批任務像之前一樣查詢和領取.

      完成第二個任務會讓流程執行到結束事件,就會結束流程實例

      流程實例和所有相關的運行數據都會從數據庫中刪除

      登錄Activiti Explorer就可以進行驗證,可以看到保存流程運行數據的表中已經沒有數據:

      可以使用historyService判斷流程是否已經結束:

      HistoryService historyService = processEngine.getHistoryService(); HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult(); System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());

      源碼

      考慮到你可能會在Activiti Explorer UI中啟動一些流程實例,這樣,它會獲得多個任務,而不是一個,所以代碼可以一直正常運行:

      public class TenMinuteTutorial { public static void main(String[] args) { // Create Activiti process engine ProcessEngine processEngine = ProcessEngineConfiguration .createStandaloneProcessEngineConfiguration() .buildProcessEngine(); // Get Activiti services RepositoryService repositoryService = processEngine.getRepositoryService(); RuntimeService runtimeService = processEngine.getRuntimeService(); // Deploy the process definition repositoryService.createDeployment() .addClasspathResource("FinancialReportProcess.bpmn20.xml") .deploy(); // Start a process instance String procId = runtimeService.startProcessInstanceByKey("financialReport").getId(); // Get the first task TaskService taskService = processEngine.getTaskService(); List tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list(); for (Task task : tasks) { System.out.println("Following task is available for accountancy group: " + task.getName()); // claim it taskService.claim(task.getId(), "fozzie"); } // Verify Fozzie can now retrieve the task tasks = taskService.createTaskQuery().taskAssignee("fozzie").list(); for (Task task : tasks) { System.out.println("Task for fozzie: " + task.getName()); // Complete the task taskService.complete(task.getId()); } System.out.println("Number of tasks for fozzie: " + taskService.createTaskQuery().taskAssignee("fozzie").count()); // Retrieve and claim the second task tasks = taskService.createTaskQuery().taskCandidateGroup("management").list(); for (Task task : tasks) { System.out.println("Following task is available for accountancy group: " + task.getName()); taskService.claim(task.getId(), "kermit"); } // Completing the second task ends the process for (Task task : tasks) { taskService.complete(task.getId()); } // verify that the process is actually finished HistoryService historyService = processEngine.getHistoryService(); HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult(); System.out.println("Process instance end time: " + historicProcessInstance.getEndTime()); } }

      總結

      可以通過Activiti中的BPMN 2.0結構,對業務流程進行以下方面的:

      定義網關來實現決策環節: 經理可以駁回財報,重新給會計創建一個任務

      考慮使用變量: 可以保存或引用報告,把它顯示到表單中

      在流程最后加入服務任務: 把報告發給每個領導

      XML 數據庫

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:自動甘特圖模板
      下一篇:表格軟件excel版本低(excel版本太低怎么辦)
      相關文章
      亚洲精品乱码久久久久久按摩 | 亚洲av无码国产精品夜色午夜| 精品国产亚洲一区二区三区在线观看| 久久亚洲精品无码AV红樱桃| 亚洲阿v天堂在线| 亚洲精品偷拍视频免费观看| 亚洲精品成人久久久| 亚洲国产精品13p| 亚洲国产精品人人做人人爱| 亚洲av区一区二区三| 男人的天堂av亚洲一区2区| 亚洲AV噜噜一区二区三区| 日韩国产精品亚洲а∨天堂免| 亚洲乱理伦片在线观看中字| 亚洲欧美日韩综合久久久久| 亚洲丁香婷婷综合久久| 久久亚洲精品无码网站| 亚洲av无码成人精品区| 亚洲日本中文字幕天堂网| 国产性爱在线观看亚洲黄色一级片| 久久亚洲2019中文字幕| 亚洲精品无码专区在线在线播放| 国产V亚洲V天堂A无码| 亚洲成熟xxxxx电影| 久久亚洲AV成人无码| 亚洲短视频在线观看| 久久精品国产亚洲av麻豆图片| 亚洲人精品亚洲人成在线| 亚洲高清毛片一区二区| 亚洲精品老司机在线观看| 亚洲欧洲∨国产一区二区三区| 亚洲va久久久噜噜噜久久| 色播亚洲视频在线观看| 亚洲国产高清美女在线观看| 亚洲91精品麻豆国产系列在线| 亚洲色大情网站www| 国产亚洲精品2021自在线| 亚洲伊人成无码综合网 | 亚洲视屏在线观看| 亚洲一区在线视频观看| 亚洲人片在线观看天堂无码|