Activiti 用戶指南(BPMN 2.0介紹)

BPMN 2.0介紹

定義流程

建立一個新的XML文件併爲其命名,確保文件以.bpmn20.xml.bpmn結尾,不然引擎將不會選擇該文件進行部署。html

BPMN 2.0模式的根元素是definitions元素,在此元素內,能夠定義多個流程定義(儘管建議在每一個文件中只有一個流程定義,由於這樣能夠簡化開發流程的後期維護)。空的流程定義以下所示,請注意,最少definitions元素僅須要xmlnstargetNamespace聲明,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元素具備兩個屬性:編程

  • id:此屬性是必需的,而且映射到Activiti ProcessDefinition對象的key屬性,而後,能夠經過RuntimeService上的startProcessInstanceByKey方法,使用此id來啓動流程定義的新流程實例,此方法將始終採用流程定義的最新部署版本。
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
  • 這裏要注意的重要一點是,這與調用startProcessInstanceById方法不一樣,此方法指望Activiti引擎在部署時生成的字符串id,能夠經過調用processDefinition.getId()方法進行檢索。生成的id的格式爲key:version,而且長度限制爲64個字符。若是你收到一個ActivitiException聲明生成的ID太長,請限制該流程的鍵字段中的文本。
  • name:此屬性是可選的,而且映射到ProcessDefinitionname屬性,引擎自己不使用此屬性,所以,例如,它可用於在用戶界面中顯示更人性化的名稱。

入門:10分鐘的教程

在本節中,咱們將介紹一個(很是簡單的)業務流程,咱們將使用它介紹一些基本的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表示法以下所示:學習

financial.report.example.diagram.png

咱們看到的是一個none Start Event(左側的圓圈),後面是兩個用戶任務:「Write monthly financial report」和「Verify monthly financial report」,以none end event(右側帶有粗邊框的圓圈)結尾。ui

XML表示

該業務流程的XML版本(FinancialReportProcess.bpmn20.xml)以下所示:url

  • (none) start event告訴咱們該流程的切入點是什麼。
  • 用戶任務聲明是咱們流程中人工任務的表示,請注意,第一個任務分配給會計組,而第二個任務分配給管理組。
  • 當到達none end event時,該流程結束。
  • 元素經過順序流相互鏈接,這些順序流具備源和目標,它們定義了順序流的方向。
<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引擎的全部交互都是經過其服務進行的。

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構造時,你將可以經過如下方式加強業務流程:

  • 定義充當決策的網關,這樣,經理能夠拒絕財務報告,將爲會計從新建立財務報告的任務。
  • 聲明和使用變量,以便咱們能夠存儲或引用報告,以即可以在表單中將其可視化。
  • 在流程結束時定義服務任務,將報告發送給每一個股東。
相關文章
相關標籤/搜索