返回介绍

7. BPMN 2.0 介绍

发布于 2023-09-17 23:44:12 字数 14137 浏览 0 评论 0 收藏 0

7.1. BPMN 是什么?

BPMN 是一个广泛接受与支持的,展现流程的注记方法。 OMG BPMN 标准

7.2. 定义流程

本篇文档假设你使用 Eclipse IDE 创建与编辑文件。但其实文档中只有少数几处使用了 Eclipse 的特性。你可以使用喜欢的任何其他工具创建 BPMN 2.0 XML 文件。

创建一个新的 XML 文件(在任意项目上右击,选择 New→Other→XML-XML File)并命名。确保该文件名以.bpmn20.xml 或.bpmn 结尾,否则引擎不会在部署时使用这个文件。

new.bpmn.procdef

BPMN 2.0 概要(schema)的根元素(root element)是 definitions 元素。在这个元素中,可以定义多个流程定义(然而我们建议在每个文件中,只有一个流程定义。这样可以简化之后的部署过程)。下面给出的是一个空流程定义。请注意 definitions 元素最少需要包含 xmlnstargetNamespace 声明。 targetNamespace 可以为空,它用于对流程定义进行分类。

<definitions
  xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
  xmlns:flowable="http://flowable.org/bpmn"
  targetNamespace="Examples">

  <process name="My First Process">
  ..
  </process>

</definitions>

除了使用 Eclipse 中的 XML 分类选项,也可以使用在线概要作为 BPMN 2.0 XML 概要。

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: 必填属性,将映射为 Flowable ProcessDefinition 对象的key参数。可以使用 RuntimeService 中的 startProcessInstanceByKey 方法,使用 id 来启动这个流程定义的新流程实例。这个方法总会使用流程定义的最新部署版本
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
  • 请注意这与调用 startProcessInstanceById 方法不同。 startProcessInstanceById 方法的参数为 Flowable 引擎在部署时生成的字符串 ID(可以通过调用 processDefinition.getId() 方法获取)。生成 ID 的格式为key:version,长度限制为 64 字符。请注意限制流程key的长度,否则会抛出 FlowableException 异常,提示生成的 ID 过长。
  • name: 可选属性,将映射为 ProcessDefinitionname参数。引擎本身不会使用这个参数。可以用于在用户界面上显示更友好的名字。

7.3. 开始:十分钟教程

这个章节包含了一个很简单的业务流程,用于介绍一些基本的 Flowable 概念以及 Flowable API。

7.3.1. 必要条件

这个教程需要你已经运行了 Flowable 演示配置,并使用独立的 H2 服务器。编辑 db.properties 并设置 jdbc.url=jdbc:h2:tcp://localhost/flowable ,然后按照 H2 文档 的介绍运行独立服务器。

7.3.2. 目标

这个教程的目标是学习 Flowable 以及 BPMN 2.0 的一些基础概念。最后成果是一个简单的 Java SE 程序,部署了一个流程定义,并可以通过 Flowable 引擎 API 与流程进行交互。当然,在这个教程里学到的东西,也可以按照你的业务流程用于构建你自己的 web 应用程序。

7.3.3. 用例

用例很简单:有一个公司,叫做 BPMCorp。在 BPMCorp 中,由会计部门负责,每月需要为投资人撰写一份报告。在报告完成后,需要高层经理中的一人进行审核,然后才能发给所有投资人。

7.3.4. 流程图

上面描述的业务流程可以使用 Flowable Designer 直接画出。但是在这个教程里我们自己写 XML,这样可以学习更多。这个流程的图形化 BPMN 2.0 注记像是这样:

financial.report.example.diagram

我们看到的是一个空启动事件(左边的圆圈),接下来是两个用户任务:'Write monthly financial report(撰写月度财务报告)''Verify monthly financial report(审核月度财务报告)'。最后是空结束事件(右边的粗线条圆圈)。

7.3.5. XML 格式

这个业务流程的 XML 版本(FinancialReportProcess.bpmn20.xml)在下面展示。很容易认出流程的主要元素(点击链接可以跳转到 BPMN 2.0 结构的详细章节):

  • (空) 开始事件是流程的入口点(entry point)
  • 用户任务表示流程中的人工任务。请注意第一个任务分配给accountancy组,而第二个任务分配给management组。查看用户任务分配章节了解更多关于用户与组如何分配用户任务的信息。
  • 流程在到达空结束事件时结束。
  • 各元素间通过顺序流链接。顺序流用 sourcetarget 定义顺序流的流向(direction)
<definitions
  targetNamespace="http://flowable.org/bpmn20"
  xmlns:flowable="http://flowable.org/bpmn"
  xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL">

  <process name="Monthly financial report reminder process">

    <startEvent />

    <sequenceFlow sourceRef="theStart" targetRef="writeReportTask" />

    <userTask name="Write monthly financial report" >
    <documentation>
      Write monthly financial report for publication to shareholders.
    </documentation>
    <potentialOwner>
      <resourceAssignmentExpression>
      <formalExpression>accountancy</formalExpression>
      </resourceAssignmentExpression>
    </potentialOwner>
    </userTask>

    <sequenceFlow sourceRef="writeReportTask" targetRef="verifyReportTask" />

    <userTask 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 sourceRef="verifyReportTask" targetRef="theEnd" />

    <endEvent />

  </process>

</definitions>

7.3.6. 启动流程实例

现在我们已经创建了业务流程的流程定义。使用这样的流程定义,可以创建流程实例。在这个例子中,一个流程实例将对应某一月份的财经报告创建与审核工作。所有月份的流程实例共享相同的流程定义。

要用给定的流程定义创建流程实例,需要首先部署(deploy)流程定义。部署流程定义意味着两件事:

  • 流程定义将会存储在 Flowable 引擎配置的持久化数据库中。因此部署业务流程保证了引擎在重启后也能找到流程定义。
  • BPMN 2.0 流程 XML 会解析为内存中的对象模型,供 Flowable API 使用。

更多关于部署的信息可以在部署章节中找到。

与该章节的描述一样,部署有很多种方式。其中一种是通过下面展示的 API。请注意所有与 Flowable 引擎的交互都要通过它的服务(services)进行。

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

现在可以使用在流程定义中定义的 id (参见 XML 中的 process 元素)启动新流程实例。请注意这个 id 在 Flowable 术语中被称作key

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

这会创建流程实例,并首先通过开始事件。在开始事件后,会沿着所有出口顺序流(在这个例子中只有一个)继续执行,并到达第一个任务(write monthly financial report 撰写月度财务报告)。这时,Flowable 引擎会在持久化数据库中存储一个任务。同时也会解析并保存这个任务附加的分配用户或组。请注意,Flowable 引擎会持续执行流程,直到到达等待状态(wait state),例如用户任务。在等待状态,流程实例的当前状态会存储在数据库中并保持,直到用户决定完成任务。这时,引擎会继续执行,直到遇到新的等待状态,或者流程结束。如果在这期间引擎重启或崩溃,流程的状态也仍在数据库中安全的保存。

用户任务活动是一个等待状态,因此 startProcessInstanceByKey 方法会在任务创建后返回。在这个例子里,这个任务分配给一个组。这意味着这个组的每一个成员都是处理这个任务的候选人(candidate)

现在可以将前面这些东西整合起来,构造一个简单的 Java 程序。创建一个新的 Eclipse 项目,在它的 classpath 中添加 Flowable JAR 与依赖(可以在 Flowable 发行版的libs目录下找到)。在调用 Flowable 服务前,需要首先构建 ProcessEngine ,用于访问服务。这里我们使用'独立(standalone)'配置,这个配置会构建 ProcessEngine ,并使用与演示配置中相同的数据库。

可以从这里下载流程定义 XML。这个文件包含了上面展示的 XML,同时包含了必要的 BPMN 图形交互信息,用于在 Flowable 的工具中可视化地展示流程。

public static void main(String[] args) {

  // 创建 Flowable 流程引擎
  ProcessEngine processEngine = ProcessEngineConfiguration
  .createStandaloneProcessEngineConfiguration()
  .buildProcessEngine();

  // 获取 Flowable 服务
  RepositoryService repositoryService = processEngine.getRepositoryService();
  RuntimeService runtimeService = processEngine.getRuntimeService();

  // 部署流程定义
  repositoryService.createDeployment()
  .addClasspathResource("FinancialReportProcess.bpmn20.xml")
  .deploy();

  // 启动流程实例
  runtimeService.startProcessInstanceByKey("financialReport");
}

7.3.7. 任务列表

现在可以通过如下代码获取这个任务:

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 ,因此可以直接登录 Flowable IDM 。使用 admin/test 登录,创建两个新用户kermitfozzie,并将Access the workflow application(访问工作流应用)权限授予他们。然后创建两个组,命名为accountancymanagement,并将 fozzie 添加至 accountancy 组,将 kermit 添加至 management 组。 然后以 fozzie 登录 Flowable task 应用。选择 Task 应用,再选择其Processes页面,选择'Monthly financial report (月度财务报告)',这样就可以启动我们的业务流程。

bpmn.financial.report.example.start.process

前面已经解释过,流程会执行直到第一个用户任务。因为登录为 fozzie,所以可以看到在启动流程实例后,他有一个新的候选任务(candidate task)。选择Task页面来查看这个新任务。请注意即使流程是由其他人启动的,accountancy 组中的每一个人仍然都能看到这个候选任务。

bpmn.financial.report.example.task.assigned

7.3.8. 申领任务

会计师(accountancy 组的成员)现在需要申领任务(claim)。申领任务后,这个用户会成为任务的执行人(assignee),这个任务也会从 accountancy 组的其他成员的任务列表中消失。可以通过如下代码实现申领任务:

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

这个任务现在在申领任务者的个人任务列表中

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

在 Flowable Task 应用中,点击claim按钮会执行相同操作。这个任务会转移到登录用户的个人任务列表中。也可以看到任务执行人变更为当前登录用户。

bpmn.financial.report.example.claim.task

7.3.9. 完成任务

会计师(accountancy 组的成员)现在需要开始撰写财务报告了。完成报告后,他就可以完成任务(complete),代表任务的所有工作都已完成。

taskService.complete(task.getId());

对于 Flowable 引擎来说,这是个外部信号,指示流程实例可以继续执行。Flowable 会从运行时数据中移除任务,并沿着这个任务唯一的出口转移线(outgoing transition),将执行移至第二个任务('verification of the report 审核报告')。为第二个任务分配执行人的机制,与上面介绍的第一个任务使用的机制相同。唯一的区别是这个任务会分配给management组。

在演示设置中,完成任务可以通过点击任务列表中的complete按钮。因为 Fozzie 不是经理,我们需要登出 Flowable Task 应用,并用kermit(他是经理)登录。这样就可以在未分配任务列表中看到第二个任务。

7.3.10. 结束流程

可以使用与之前完全相同的方式获取并申领审核任务。完成这个第二个任务会将流程执行移至结束事件,并结束流程实例。这个流程实例,及所有相关的运行时执行数据都会从数据库中移除。

也可以通过编程方式,使用 historyService 验证流程已经结束

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

7.3.11. 代码总结

将之前章节的所有代码片段整合起来,会得到类似这样的代码。这段代码考虑到了你可能已经使用 Flowable UI 应用启动了一些流程实例。代码中总是获取任务列表而不是一个任务,因此可以正确执行:

public class TenMinuteTutorial {

  public static void main(String[] args) {

  // 创建 Flowable 流程引擎
  ProcessEngine processEngine = ProcessEngineConfiguration
    .createStandaloneProcessEngineConfiguration()
    .buildProcessEngine();

  // 获取 Flowable 服务
  RepositoryService repositoryService = processEngine.getRepositoryService();
  RuntimeService runtimeService = processEngine.getRuntimeService();

  // 部署流程定义
  repositoryService.createDeployment()
    .addClasspathResource("FinancialReportProcess.bpmn20.xml")
    .deploy();

  // 启动流程实例
  String procId = runtimeService.startProcessInstanceByKey("financialReport").getId();

  // 获取第一个任务
  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());

    // 申领任务
    taskService.claim(task.getId(), "fozzie");
  }

  // 验证 Fozzie 获取了任务
  tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
  for (Task task : tasks) {
    System.out.println("Task for fozzie: " + task.getName());

    // 完成任务
    taskService.complete(task.getId());
  }

  System.out.println("Number of tasks for fozzie: "
      + taskService.createTaskQuery().taskAssignee("fozzie").count());

  // 获取并申领第二个任务
  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");
  }

  // 完成第二个任务并结束流程
  for (Task task : tasks) {
    taskService.complete(task.getId());
  }

  // 验证流程已经结束
  HistoryService historyService = processEngine.getHistoryService();
  HistoricProcessInstance historicProcessInstance =
    historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
  System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
  }

}

7.3.12. 后续增强

可以看出这个业务流程太简单了,不能实际使用。但只要继续学习 Flowable 中可用的 BPMN 2.0 结构,就可以通过以下元素增强业务流程:

  • 定义网关(gateway)使经理可以选择:驳回财务报告,并重新为会计师创建任务;或者接受报告。
  • 定义并使用变量(variables)存储或引用报告,并可以在表单中显示它。
  • 在流程结束处定义服务任务(service task),将报告发送给每一个投资人。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文