BPMN 2.0 BPMN 2.0介紹 定義一個流程 BPMN流程示例前提 目标 用例 流程圖 XML内容 啟動一個流程執行個體 任務清單 領取任務 完成任務 結束流程 源碼 總結 BPMN 2.0介紹 業務流程模型注解(BusinessProcess Modeling Notation - BPMN)是業務流程模型的一種标準圖形注解.這個标準是由對象管理組(Object Management Group - OMG)維護的 BPMN規範的2.0版本允許添加精确的技術細節在BPMN的圖形和元素中,同時制定BPMN元素的執行文法.通過使用XML語言來指定業務流程的可執行文法,BPMN規範已經演變為業務流程的語言,可以執行在任何相容BPMN2的流程引擎中,同時依然可以使用強大的圖形注解 簡單來說,BPMN即圖示與标簽的結合 Activiti工作流Day07-BPMN 2.0流程使用示例 Activiti工作流Day07-BPMN 2.0流程使用示例 Activiti工作流Day07-BPMN 2.0流程使用示例 Activiti工作流Day07-BPMN 2.0流程使用示例 定義一個流程 建立一個新的XML檔案并命名,确認檔案字尾為 .bpmn20.xml或 .bpmn, 否則引擎無法釋出 BPMN 2.0根節點是definitions節點. 這個元素中,可以定義多個流程定義(不過建議每個檔案隻包含一個流程定義, 可以簡化開發過程中的維護難度) 一個空的流程定義如下所示:注意definitions元素最少也要包含xmlns和 targetNamespace的聲明 targetNamespace可以是任意值,它用來對流程執行個體進行分類 <definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="Examples">
<process id="myProcess" name="My First Process">
..
</process>
</definitions>
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");
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标記: Activiti工作流Day07-BPMN 2.0流程使用示例 空開始事件(左側圓圈),後面是兩個使用者任務:制作月度财報和驗證月度财報,最後是空結束事件(右側粗線圓圈) XML内容 在業務流程的XML中很容易找到流程的主要元素: (空)開始事件是流程的入口 使用者任務是流程中與操作者相關的任務聲明: 第一個任務配置設定給accountancy組 第二個任務配置設定給management組 當流程達到空結束事件就會結束 這些元素都使用連線連接配接,這些連線擁有source和target屬性,定義了連線的方向 <definitions id="definitions"
targetNamespace="http://activiti.org/bpmn20"
xmlns:activiti="http://activiti.org/bpmn"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL">
<process id="financialReport" name="Monthly financial report reminder process">
<startEvent id="theStart" />
<sequenceFlow id='flow1' sourceRef='theStart' targetRef='writeReportTask' />
<userTask id="writeReportTask" name="Write monthly financial report" >
<documentation>
Write monthly financial report for publication to shareholders.
</documentation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>accountancy</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id='flow2' sourceRef='writeReportTask' targetRef='verifyReportTask' />
<userTask id="verifyReportTask" name="Verify monthly financial report" >
<documentation>
Verify monthly financial report composed by the accountancy department.
This financial report is going to be sent to all the company shareholders.
</documentation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>management</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id='flow3' sourceRef='verifyReportTask' targetRef='theEnd' />
<endEvent id="theEnd" />
</process>
</definitions>
啟動一個流程執行個體 建立好業務流程的流程定義,就可以建立流程執行個體 一個流程執行個體對應了特定月度财報的建立和審批,所有流程執行個體都共享同一個流程定義 為了使用流程定義建立流程執行個體,首先要釋出業務流程: 流程定義會儲存到持久化的資料存儲裡,是為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<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list();
注意傳入的使用者必須是accountancy組的一個成員,要和流程定義中相對應: <potentialOwner>
<resourceAssignmentExpression>
<formalExpression>accountancy</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
也可以使用群組名稱,通過任務查詢API來獲得相關的結果.在代碼中添加如下邏輯: TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
因為配置的ProcessEngine使用了與demo相同的資料,可以登入到Activiti Explorer.預設,accountancy(會計)組裡沒有任何人: 登入 點選組 建立一個新組 點選使用者 把組配置設定給fozzie 使用fozzie/fozzie登入 就可以啟動我們的業務流程了,選擇Processes頁,在[月度财報]的[操作]列點選[啟動流程] Activiti工作流Day07-BPMN 2.0流程使用示例 流程會執行到第一個使用者任務.因為我們以kermit登入,在啟動流程執行個體之後,就可以看到有了一個新的待領任務.選擇任務頁來檢視這條新任務.注意即使流程被其他人啟動,任務還是會被會計組裡的所有人作為一個候選任務看到 Activiti工作流Day07-BPMN 2.0流程使用示例 領取任務 現在一個會計要認領這個任務 認領以後,這個使用者就會成為任務的執行人,任務會從會計組的其他成員的任務清單中消失.認領任務的代碼: taskService.claim(task.getId(), "fozzie");
List<Task> tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
在Activiti Explorer UI中,點選認領按鈕,會執行相同的操作.任務會移動到登入使用者的個人任務清單.你也會看到任務的執行人已經變成目前登陸的使用者: Activiti工作流Day07-BPMN 2.0流程使用示例 完成任務 現在會計可以開始進行财報的工作 報告完成後,他可以完成任務,意味着任務所需的所有工作都完成 taskService.complete(task.getId());
需要一個外部資訊來讓流程執行個體繼續執行 任務會把自己從運作庫中删除 流程會沿着單獨一個外出連線執行,移動到第二個任務(審批報告) 與第一個任務相同的機制會使用到第二個任務上,不同的是任務是配置設定給management組 完成任務是通過點選任務清單中的完成按鈕 因為Fozzie不是會計,我們先從Activiti Explorer登出 然後使用kermit登陸(經理),第二個任務會進入未配置設定任務清單 結束流程 審批任務像之前一樣查詢和領取. 完成第二個任務會讓流程執行到結束事件,就會結束流程執行個體 流程執行個體和所有相關的運作資料都會從資料庫中删除 登入Activiti Explorer就可以進行驗證,可以看到儲存流程運作資料的表中已經沒有資料: Activiti工作流Day07-BPMN 2.0流程使用示例 可以使用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<Task> 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結構,對業務流程進行以下方面的: 定義網關來實作決策環節: 經理可以駁回财報,重新給會計建立一個任務 考慮使用變量: 可以儲存或引用報告,把它顯示到表單中 在流程最後加入服務任務: 把報告發給每個上司