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构造时,你将可以经过如下方式加强业务流程:

  • 定义充当决策的网关,这样,经理能够拒绝财务报告,将为会计从新建立财务报告的任务。
  • 声明和使用变量,以便咱们能够存储或引用报告,以即可以在表单中将其可视化。
  • 在流程结束时定义服务任务,将报告发送给每一个股东。
相关文章
相关标签/搜索