建立一個新的XML文件併爲其命名,確保文件以.bpmn20.xml或.bpmn結尾,不然引擎將不會選擇該文件進行部署。html
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>
process
元素具備兩個屬性:編程
ProcessDefinition
對象的key屬性,而後,能夠經過RuntimeService
上的startProcessInstanceByKey
方法,使用此id來啓動流程定義的新流程實例,此方法將始終採用流程定義的最新部署版本。ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
startProcessInstanceById
方法不一樣,此方法指望Activiti引擎在部署時生成的字符串id,能夠經過調用processDefinition.getId()
方法進行檢索。生成的id的格式爲key:version,而且長度限制爲64個字符。若是你收到一個ActivitiException聲明生成的ID太長,請限制該流程的鍵字段中的文本。ProcessDefinition
的name屬性,引擎自己不使用此屬性,所以,例如,它可用於在用戶界面中顯示更人性化的名稱。在本節中,咱們將介紹一個(很是簡單的)業務流程,咱們將使用它介紹一些基本的Activiti概念和Activiti API。安全
本教程假定你正在運行Activiti演示安裝程序,而且你正在使用獨立的H2服務器,編輯db.properties
並設置jdbc.url=jdbc:h2:tcp://localhost/activiti
,而後根據H2的文檔運行獨立服務器。服務器
本教程的目的是學習Activiti和一些基本的BPMN 2.0概念,最終結果將是一個簡單的Java SE程序,該程序將部署流程定義,並經過Activiti引擎API與該流程進行交互。還將介紹Activiti周圍的一些工具,固然,在圍繞業務流程構建本身的Web應用程序時,也可使用本教程中學習的內容。tcp
用例很簡單:咱們有一家公司,咱們稱之爲BPMCorp。在BPMCorp中,每個月須要爲公司股東編寫財務報告,這是會計部門的責任,報告完成後,高層管理人員之一須要批准該文件,而後再將其發送給全部股東。工具
可使用Activiti Designer以圖形方式顯示上述業務流程,可是,在本教程中,咱們將本身鍵入XML,由於咱們在這一點上學到的最多,咱們的流程的圖形化BPMN 2.0表示法以下所示:學習
咱們看到的是一個none Start Event(左側的圓圈),後面是兩個用戶任務:「Write monthly financial report」和「Verify monthly financial report」,以none end event(右側帶有粗邊框的圓圈)結尾。ui
該業務流程的XML版本(FinancialReportProcess.bpmn20.xml)以下所示:url
<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>
如今,咱們已經建立了業務流程的流程定義,經過這樣的流程定義,咱們能夠建立流程實例,在這種狀況下,一個流程實例將與特定月份的單個財務報告的建立和驗證相匹配,全部流程實例共享相同的流程定義。
爲了可以根據給定的流程定義建立流程實例,咱們必須首先部署該流程定義,部署流程定義意味着兩件事:
部署能夠經過多種方式進行,一種方法是經過如下API,請注意,與Activiti引擎的全部交互都是經過其服務進行的。
Deployment deployment = repositoryService.createDeployment() .addClasspathResource("FinancialReportProcess.bpmn20.xml") .deploy();
如今,咱們可使用在流程定義中定義的id
(請參閱XML文件中的process元素)來啓動新流程實例,請注意,Activiti術語中的此id
稱爲key。
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("financialReport");
這將建立一個流程實例,該實例將首先經歷啓動事件,啓動事件以後,它遵循全部輸出順序流(在這種狀況下只有一個),而且到達了第一個任務(寫每個月財務報告),Activiti引擎如今將在持久數據庫中存儲任務,此時,將解決任務中附加的用戶或組分配,並將其存儲在數據庫中,重要的是要注意,Activiti引擎將繼續執行流程,直到達到等待狀態(例如用戶任務)爲止。在這種等待狀態下,流程實例的當前狀態存儲在數據庫中,它將保持該狀態,直到用戶決定完成其任務爲止,屆時,引擎將繼續運行直到達到新的等待狀態或流程結束,同時,若是引擎從新啓動或崩潰,則該流程的狀態是安全的,而且在數據庫中也處於良好狀態。
建立任務後,因爲用戶任務活動處於等待狀態,所以startProcessInstanceByKey
方法將返回。在這種狀況下,將任務分配給一個組,這意味着該組中的每一個成員都是執行任務的候選人。
如今,咱們能夠將全部內容放在一塊兒,並建立一個簡單的Java程序,建立一個新的Eclipse項目,並將Activiti JAR和依賴項添加到其類路徑(能夠在Activiti發行版的libs文件夾中找到它們)。在調用Activiti服務以前,咱們必須首先構造一個ProcessEngine
,使咱們可以訪問這些服務。在這裏,咱們使用「standalone」配置,該配置構造一個ProcessEngine
,該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();
會計如今須要申領任務,經過領取任務,特定用戶將成爲任務的受讓人,而且該任務將從accountancy組其餘成員的每一個任務列表中消失,領取任務是經過編程完成的,以下所示:
taskService.claim(task.getId(), "fozzie");
如今,該任務已在領取該任務的我的任務列表中。
List<Task> tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
會計如今能夠開始處理財務報告了,報告完成後,他就能夠完成任務,這意味着該任務的全部工做都已完成。
taskService.complete(task.getId());
對於Activiti引擎,這是一個外部信號,代表必須繼續執行流程實例,任務自己已從運行時數據中刪除,接下來是任務的單個傳出過渡,將執行移至第二個任務(「verification of the report」)。如今將使用與針對第一個任務所述的相同機制來分配第二個任務,所不一樣的只是將任務分配給管理組。
能夠按照與之前徹底相同的方式檢索並領取任務,完成第二個任務會將流程執行移至結束事件,從而結束流程實例,流程實例和全部相關的運行時執行數據將從數據存儲中刪除。
經過編程,你還可使用historyService
驗證該流程是否已結束:
HistoryService historyService = processEngine.getHistoryService(); HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult(); System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
合併以前各節中的全部代碼片斷,你應該具備相似的內容:
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 management 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構造時,你將可以經過如下方式加強業務流程: