跳到主要内容

快速入门

Doubao 中英对照 Getting Started

什么是 Flowable?​

Flowable 是一个用 Java 编写的轻量级业务流程引擎。Flowable 流程引擎允许你部署 BPMN 2.0 流程定义(一种用于定义流程的行业 XML 标准)、为这些流程定义创建流程实例、运行查询、访问活动或历史流程实例及相关数据,以及更多其他功能。本节将通过你可以在自己开发机上动手实践的示例,逐步介绍各种概念和 API。

Flowable 在接入你的应用/服务/架构方面极其灵活。你可以通过引入 Flowable 库(以 JAR 形式提供)把引擎嵌入你的应用或服务。由于它是一个 JAR,你可以轻松地把它添加到任何 Java 环境:Java SE;servlet 容器(如 Tomcat 或 Jetty)、Spring;Java EE 服务器(如 JBoss 或 WebSphere)等等。
另外,你也可以使用 Flowable REST API 通过 HTTP 进行通信。此外还有若干 Flowable 应用(Flowable Modeler、Flowable Admin、Flowable IDM 和 Flowable Task),它们提供开箱即用的示例 UI,用于处理流程和任务。

所有 Flowable 搭建方式的共同点是核心引擎,它可以看作一组暴露 API 以管理和执行业务流程的服务。
下面的各个教程先从介绍如何搭建和使用这个核心引擎开始。之后的章节都建立在前面章节所获得的知识之上。

  • 第一节展示了以最简单方式运行 Flowable:只使用 Java SE 的普通 Java main 方法。许多核心概念和 API 都会在这里讲解。
  • Flowable REST API 一节展示了如何通过 REST 运行并使用同一套 API。
  • Flowable REST 应用一节将带你了解使用开箱即用的示例 Flowable REST 应用的基础知识。

Flowable 与 Activiti​

Flowable 是 Activiti(Alfresco 的注册商标)的一个分支。在接下来的所有章节中,你会注意到包名、配置文件等都使用 flowable。

构建一个命令行应用​

创建流程引擎​

在这第一个教程中,我们将构建一个简单示例,展示如何创建 Flowable 流程引擎、介绍一些核心概念,并演示如何使用 API。
截图使用的是 Eclipse,但任何 IDE 都可以。我们将使用 Maven 来获取 Flowable 依赖并管理构建,但同样地,任何替代方案也都行(Gradle、Ivy 等等)。

我们将要构建的示例是一个简单的请假申请流程:

  • 员工申请若干天假期
  • 经理批准或拒绝该申请
  • 我们将模拟在某个外部系统中登记该申请,并向员工发送一封告知结果的邮件

首先,我们通过 File → New → Other → Maven Project 创建一个新的 Maven 项目。

getting.started.new.maven

在下一个界面中,勾选 'create a simple project (skip archetype selection)'。

getting.started.new.maven2

然后填写一些 'Group Id' 和 'Artifact id':

getting.started.new.maven3

现在我们有了一个空的 Maven 项目,接下来要向其中添加两个依赖:

  • Flowable 流程引擎,它将允许我们创建 ProcessEngine 对象并访问 Flowable API。
  • 一个内存数据库,本例使用 H2,因为 Flowable 引擎在运行流程实例时需要数据库来存储执行和历史数据。
    请注意,H2 依赖同时包含数据库和驱动。如果你使用其他数据库(例如 PostgresQL、MySQL 等),则需要添加特定的数据库驱动依赖。

将以下内容添加到你的 pom.xml 文件中:

<dependencies>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
</dependencies>

如果由于某种原因没有自动获取依赖 JAR,你可以右键点击项目并选择 'Maven → Update Project' 以强制手动刷新(但通常情况下不需要这样做)。
在项目的 'Maven Dependencies' 下,你现在应该能看到 flowable-engine 以及各种其他(传递)依赖。

创建一个新的 Java 类,并添加一个普通的 Java main 方法:

package org.flowable;

public class HolidayRequest {

public static void main(String[] args) {

}

}

我们要做的第一件事是实例化一个 ProcessEngine 实例。这是一个线程安全对象,通常在一个应用中只需要实例化一次。
ProcessEngine 由一个 ProcessEngineConfiguration 实例创建,后者允许你配置和调整流程引擎的各项设置。通常,ProcessEngineConfiguration 通过配置 XML 文件创建,但(正如我们这里所做的)你也可以以编程方式创建它。ProcessEngineConfiguration 所需的最小配置
是到某个数据库的 JDBC 连接:

package org.flowable;

import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;

public class HolidayRequest {

public static void main(String[] args) {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1")
.setJdbcUsername("sa")
.setJdbcPassword("")
.setJdbcDriver("org.h2.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

ProcessEngine processEngine = cfg.buildProcessEngine();
}

}

在上面的代码中,第 10 行创建了一个standalone(独立)配置对象。这里的 'standalone' 指的是引擎完全由自身创建和使用(而不是在 Spring 环境中——在那种环境下你会改用 SpringProcessEngineConfiguration 类)。在第 11 到 14 行,传入了到内存 H2 数据库实例的 JDBC 连接参数。
重要提示:请注意这样的数据库不会在 JVM 重启后保留。如果你希望数据持久化,就需要切换到持久化数据库,并相应地修改连接参数。
在第 15 行,我们将一个标志设置为 true,以确保数据库模式在 JDBC 参数所指向的数据库中不存在时被创建。
另外,Flowable 还附带了一组 SQL 文件,可用于手动创建包含所有表的数据库模式。

然后使用该配置创建 ProcessEngine 对象(第 17 行)。

现在你可以运行它了。在 Eclipse 中最简单的方式是右键点击类文件并选择 Run As → Java Application:

getting.started.run.main

应用运行没有问题,但除了一条提示日志未正确配置的消息之外,控制台中没有显示任何有用信息:

getting.started.console.logging

Flowable 内部使用 SLF4J 作为日志框架。在本示例中,我们将通过 SLF4j 使用 log4j 日志器,因此向 pom.xml 文件添加以下依赖:

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
<version>2.0.7</version>
</dependency>

Log4j 需要一个属性文件来配置。在 src/main/resources 文件夹中添加一个内容如下的 log4j.properties 文件:

log4j.rootLogger=DEBUG, CA

log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n

重新运行应用。你现在应该能看到关于引擎启动和在数据库中创建数据库模式的信息性日志:

getting.started.console.logging2

现在我们已经有了一个启动就绪的流程引擎。是时候给它喂一个流程了!

部署流程定义​

我们要构建的流程是一个非常简单的请假申请流程。Flowable 引擎要求流程以 BPMN 2.0 格式定义,这是一个被业界广泛接受的 XML 标准。
在 Flowable 术语中,我们称之为流程定义。从一个流程定义出发,可以启动许多个流程实例。可以把流程定义想象为流程多次执行的蓝图。在这个具体例子中,流程定义定义了请假申请涉及的各个步骤,而一个流程实例则对应某一位特定员工的一次请假申请。

BPMN 2.0 以 XML 形式存储,但它也有可视化部分:它以标准化方式定义了每种不同步骤类型(人工任务、自动服务调用等)如何表示,以及如何把这些不同步骤相互连接起来。借此,BPMN 2.0 标准让技术人员和业务人员能够以双方都能理解的方式交流业务流程。

我们将使用的流程定义如下:

getting.started.bpmn.process

该流程应该相当不言自明,但为清晰起见,我们还是来描述一下各个部分:

  • 我们假设流程通过提供一些信息来启动,例如员工姓名、申请的假期天数以及一段描述。当然,这也可以建模为流程中独立的第一步。
    然而,把它作为流程的'输入数据',只有真正提出申请时才会实际创建流程实例。在另一种方案下,用户可能在提交前改变主意并取消,但此时流程实例却已经存在了。
    在某些场景下这可能是有价值的信息(例如,申请被启动了多少次但没有完成),取决于业务目标。
  • 左侧的圆圈称为开始事件。它是流程实例的起点。
  • 第一个矩形是一个用户任务。这是流程中需要由人工用户执行的一步。在本例中,经理需要批准或拒绝该申请。
  • 根据经理的决定,排他网关(带叉号的菱形)会把流程实例路由到批准路径或拒绝路径。
  • 如果批准,我们必须在某个外部系统中登记该申请,之后再次出现一个用户任务,通知最初的员工这一决定。
    当然,这一步也可以换成一封邮件。
  • 如果拒绝,则向员工发送一封邮件告知此事。

通常,这样的流程定义是用可视化建模工具建模的,例如 Flowable Designer(Eclipse)或 Flowable Modeler(Web 应用)。

但在这里,我们将直接编写 XML,以便熟悉 BPMN 2.0 及其概念。

上图对应的 BPMN 2.0 XML 如下所示。请注意,这只是'流程部分'。如果你使用图形化建模工具,底层 XML 文件还会包含'可视化'部分,用于描述图形信息,例如流程定义中各元素的坐标(所有图形信息都包含在 XML 的 BPMNDiagram 标签中,它是 definitions 标签的子元素)。

将以下 XML 保存到 src/main/resources 文件夹中一个名为 holiday-request.bpmn20.xml 的文件中。

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">

<process id="holidayRequest" name="Holiday Request" isExecutable="true">

<startEvent id="startEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>

<userTask id="approveTask" name="Approve or reject request"/>
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>

<exclusiveGateway id="decision"/>
<sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${approved}
]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="sendRejectionMail">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${!approved}
]]>
</conditionExpression>
</sequenceFlow>

<serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="org.flowable.CallExternalSystemDelegate"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>

<userTask id="holidayApprovedTask" name="Holiday approved"/>
<sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>

<serviceTask id="sendRejectionMail" name="Send out rejection email"
flowable:class="org.flowable.SendRejectionMail"/>
<sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>

<endEvent id="approveEnd"/>

<endEvent id="rejectEnd"/>

</process>

</definitions>

第 2 到 11 行看起来有些令人生畏,但它与你在几乎所有流程定义中看到的相同。这是为了与 BPMN 2.0 标准规范完全兼容所需的那种样板内容。

每个步骤(在 BPMN 2.0 术语中称为**'activity'**)都有一个 id 属性,使其在 XML 文件中具有唯一标识符。所有 activity 还可以有一个可选的 name,当然这也提高了可视化图的可读性。

activity 之间通过序列流连接,在可视化图中它是一条有向箭头。执行流程实例时,执行将从开始事件沿序列流流向下一个 activity。

从排他网关(带 X 的菱形)离开的序列流明显比较特殊:两条都定义了以表达式形式表示的条件(见第 25 和 32 行)。当流程实例执行到达该网关时,会对条件求值,取第一个解析为 true 的条件。这里的*exclusive(排他)*正是这个意思:只选一个。当然,如果需要不同的路由行为,也可以使用其他类型的网关。

这里以表达式形式写出的条件形如 ${approved},它是 ${approved == true} 的简写。变量 'approved' 称为流程变量。流程变量是与流程实例一起存储的持久数据,可以在流程实例的整个生命周期中使用。在本例中,这意味着我们必须在流程实例的某个时刻(当经理用户任务被提交时,或者用 Flowable 术语说,被完成时)设置该流程变量,因为它不是流程实例启动时就可用的数据。

现在我们有了流程的 BPMN 2.0 XML 文件,下一步需要把它**'部署'**到引擎。部署一个流程定义意味着:

  • 流程引擎会把 XML 文件存储在数据库中,以便需要时随时取回
  • 流程定义会被解析成内部的、可执行的对象模型,从而可以从中启动流程实例。

要把流程定义部署到 Flowable 引擎,需使用 RepositoryService,它可以从 ProcessEngine 对象获取。使用 RepositoryService,通过传入 XML 文件的位置并调用 deploy() 方法实际执行,即可创建一个新的 Deployment:

RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("holiday-request.bpmn20.xml")
.deploy();

现在我们可以通过 API 查询,验证引擎已知该流程定义(同时顺带了解一点 API)。做法是通过 RepositoryService 创建一个新的 ProcessDefinitionQuery 对象。

ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId(deployment.getId())
.singleResult();
System.out.println("Found process definition : " + processDefinition.getName());

启动流程实例​

现在我们已经把流程定义部署到流程引擎,因此可以以该流程定义为'蓝图'启动流程实例。

要启动流程实例,我们需要提供一些初始流程变量。通常,这些变量通过呈现给用户的表单获取;当流程由某种自动动作触发时,则通过 REST API 获取。在本例中,我们保持简单,使用 java.util.Scanner 类直接在命令行输入一些数据:

Scanner scanner= new Scanner(System.in);

System.out.println("Who are you?");
String employee = scanner.nextLine();

System.out.println("How many holidays do you want to request?");
Integer nrOfHolidays = Integer.valueOf(scanner.nextLine());

System.out.println("Why do you need them?");
String description = scanner.nextLine();

接下来,我们可以通过 RuntimeService 启动一个流程实例。收集到的数据以 java.util.Map 实例传入,其中键是稍后用于取回这些变量的标识符。流程实例使用一个 key 启动。该 key 与 BPMN 2.0 XML 文件中设置的 id 属性匹配,本例中为 holidayRequest。

(注意:你以后会学到启动流程实例的许多其他方式,而不仅仅是使用 key)

<process id="holidayRequest" name="Holiday Request" isExecutable="true">

RuntimeService runtimeService = processEngine.getRuntimeService();

Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employee", employee);
variables.put("nrOfHolidays", nrOfHolidays);
variables.put("description", description);
ProcessInstance processInstance =
runtimeService.startProcessInstanceByKey("holidayRequest", variables);

流程实例启动时,会创建一个执行实例并置于开始事件中。从那里,该执行实例沿序列流到达经理审批的用户任务,并执行该用户任务的行为。该行为会在数据库中创建一个任务,之后可以通过查询找到它。用户任务是一个等待状态,引擎将停止继续执行任何操作,返回 API 调用。

插曲:事务性​

在 Flowable 中,数据库事务对保证数据一致性和解决并发问题起着关键作用。当你发起一次 Flowable API 调用时,默认情况下一切都是同步的,并且属于同一个事务。也就是说,当方法调用返回时,一个事务已经被启动并提交。

流程实例启动时,从流程实例启动到下一个等待状态之间会有一个数据库事务。在本例中,即第一个用户任务。当引擎到达该用户任务时,状态被持久化到数据库,事务被提交,API 调用返回。

在 Flowable 中,继续推进流程实例时,总是有一个数据库事务从前一个等待状态走到下一个等待状态。数据一旦持久化,可以在数据库中存放很长时间,甚至如有必要可达数年,直到执行某个把流程实例进一步推进的 API 调用。请注意,当流程实例处于这种等待状态、等待下一次 API 调用时,不会消耗任何计算或内存资源。

在本例中,当第一个用户任务被完成时,会使用一个数据库事务从该用户任务经过排他网关(自动逻辑)走到第二个用户任务。或者沿另一条路径直接走到结束。

查询并完成任务​

在一个更真实的应用中,会有一个用户界面,员工和经理可以登录并查看各自的任务列表。借助这些列表,他们可以检查作为流程变量存储的流程实例数据,并决定如何处理该任务。在本例中,我们将通过执行那些通常位于驱动 UI 的服务调用背后的 API 调用来模拟任务列表。

我们还没有配置用户任务的分配。我们希望第一个任务进入 'managers' 组,第二个用户任务分配给最初的请假申请人。为此,向第一个任务添加 candidateGroups 属性:

<userTask id="approveTask" name="Approve or reject request" flowable:candidateGroups="managers"/>

如下所示,向第二个任务添加 assignee 属性。请注意,我们不是使用上面 'managers' 这样的静态值,而是基于流程实例启动时传入的流程变量进行动态分配:

<userTask id="holidayApprovedTask" name="Holiday approved" flowable:assignee="${employee}"/>

要获取实际的任务列表,我们通过 TaskService 创建一个 TaskQuery,并将查询配置为只返回 'managers' 组的任务:

TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
System.out.println("You have " + tasks.size() + " tasks:");
for (int i=0; i<tasks.size(); i++) {
System.out.println((i+1) + ") " + tasks.get(i).getName());
}

使用任务标识,我们现在可以获取特定流程实例的变量,并在屏幕上显示实际的申请内容:

System.out.println("Which task would you like to complete?");
int taskIndex = Integer.valueOf(scanner.nextLine());
Task task = tasks.get(taskIndex - 1);
Map<String, Object> processVariables = taskService.getVariables(task.getId());
System.out.println(processVariables.get("employee") + " wants " +
processVariables.get("nrOfHolidays") + " of holidays. Do you approve this?");

如果你运行这段代码,看起来应该类似这样:

getting.started.console.logging3

经理现在可以完成任务。在现实中,这通常意味着用户提交了一个表单。表单中的数据随后作为流程变量传入。这里,我们将通过在任务完成时传入一个含 'approved' 变量的 map 来模拟这一过程(这个名字很重要,因为后面序列流的条件会用到它):

boolean approved = scanner.nextLine().toLowerCase().equals("y");
variables = new HashMap<String, Object>();
variables.put("approved", approved);
taskService.complete(task.getId(), variables);

任务现在已完成,离开排他网关的两条路径之一会根据 'approved' 流程变量被选中。

编写 JavaDelegate​

谜题还缺最后一块:我们还没有实现申请被批准时要执行的自动逻辑。在 BPMN 2.0 XML 中这是一个服务任务,它在上面看起来是这样的:

<serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="org.flowable.CallExternalSystemDelegate"/>

在现实中,这段逻辑可以是任何东西,从通过 HTTP REST 调用一个服务,到对组织已使用数十年的某个系统执行一些遗留代码调用。我们这里不实现实际逻辑,只简单地记录一下处理过程。

创建一个新类(在 Eclipse 中 File → New → Class),填写 org.flowable 作为包名、CallExternalSystemDelegate 作为类名。让该类实现 org.flowable.engine.delegate.JavaDelegate 接口,并实现 execute 方法:

package org.flowable;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;

public class CallExternalSystemDelegate implements JavaDelegate {

public void execute(DelegateExecution execution) {
System.out.println("Calling the external system for employee "
+ execution.getVariable("employee"));
}

}

当执行到达服务任务时,会实例化 BPMN 2.0 XML 中引用的类并调用它。

现在运行示例,日志消息会显示出来,证明自定义逻辑确实被执行了:

getting.started.console.logging4

使用历史数据​

选择使用像 Flowable 这样的流程引擎的众多原因之一,是它会自动为所有流程实例存储审计数据或历史数据。这些数据可以用来生成丰富的报告,洞察组织如何运作、瓶颈在哪里等等。

例如,假设我们想展示到目前为止所执行流程实例的持续时间。为此,我们从 ProcessEngine 获取 HistoryService,并对历史活动创建一个查询。在下面的代码片段中你可以看到我们还添加了一些额外的过滤条件:

  • 仅某个特定流程实例的活动
  • 仅已完成的活动

结果还按结束时间排序,这意味着我们将按执行顺序获得它们。

HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> activities =
historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstance.getId())
.finished()
.orderByHistoricActivityInstanceEndTime().asc()
.list();

for (HistoricActivityInstance activity : activities) {
System.out.println(activity.getActivityId() + " took "
+ activity.getDurationInMillis() + " milliseconds");
}

再次运行示例,我们现在在控制台看到类似这样的内容:

startEvent took 1 milliseconds
approveTask took 2638 milliseconds
decision took 3 milliseconds
externalSystemCall took 1 milliseconds

小结​

本教程介绍了各种 Flowable 和 BPMN 2.0 的概念与术语,同时演示了如何以编程方式使用 Flowable API。

当然,这只是旅程的开始。后续章节将更深入地探讨 Flowable 引擎支持的众多选项和特性。其他章节还会介绍 Flowable 引擎可以搭建和使用的各种方式,并详细描述所有可行的 BPMN 2.0 构件。

Flowable REST API 入门​

本节展示与上一节相同的示例:部署流程定义、启动流程实例、获取任务列表并完成任务。如果你还没读过那一节,最好先浏览一下,了解那里做了什么。

这一次,使用 Flowable REST API 而不是 Java API。你很快就会注意到,REST API 与 Java API 非常接近,熟悉其中一个自然意味着你也能上手另一个。

要获得 Flowable REST API 的完整详细概览,请查阅 REST API 章节。

设置 REST 应用​

当你从 flowable.org 网站下载 .zip 文件时,REST 应用可以在 wars 文件夹中找到。你需要一个 servlet 容器(如 Tomcat、Jetty 等)来运行该 WAR 文件。

注意:flowable-rest.war 基于 Spring Boot,这意味着它支持 Spring Boot 所支持的 Tomcat / Jetty servlet 容器。

使用 Tomcat 时步骤如下:

  • 下载并解压最新最好的 Tomcat zip 文件(从 Tomcat 网站选择 'Core' 发行版)。
  • 将解压后的 Flowable 发行版 wars 文件夹中的 flowable-rest.war 文件,复制到解压后的 Tomcat 文件夹的 webapps 文件夹。
  • 在命令行中,进入 Tomcat 文件夹的 bin 文件夹。
  • 执行 './catalina run' 来启动 Tomcat 服务器。

在服务器启动过程中,你会看到一些 Flowable 日志消息掠过。最后,像 'INFO [main] org.apache.catalina.startup.Catalina.start Server startup in xyz ms' 这样的消息表示服务器已准备好接收请求。请注意,默认使用内存 H2 数据库实例,这意味着数据不会在服务器重启后保留。

在接下来的章节中,我们将使用 cURL 来演示各种 REST 调用。所有 REST 调用默认都受到基本认证保护。所有调用中使用用户 'rest-admin'、密码 'test'。

启动后,通过执行以下命令验证应用是否正常运行:

curl --user rest-admin:test http://localhost:8080/flowable-rest/service/management/engine

如果你得到一个正常的 json 响应,说明 REST API 已经启动并运行。

部署流程定义​

第一步是部署流程定义。使用 REST API 时,这通过以 'multipart/formdata' 方式上传一个 .bpmn20.xml 文件(或多个流程定义时的 .zip 文件)来完成:

curl --user rest-admin:test  -X POST -F "file=@holiday-request.bpmn20.xml" http://localhost:8080/flowable-rest/service/repository/deployments

要验证流程定义是否已正确部署,可以请求流程定义列表:

curl --user rest-admin:test http://localhost:8080/flowable-rest/service/repository/process-definitions

这会返回当前已部署到引擎的所有流程定义的列表。

启动流程实例​

通过 REST API 启动流程实例与通过 Java API 做同样的事情类似:提供一个 key 来标识要使用的流程定义,以及一个初始流程变量的 map:

curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "processDefinitionKey":"holidayRequest", "variables": [ { "name":"employee", "value": "John Doe" }, { "name":"nrOfHolidays", "value": 7 }]}' http://localhost:8080/flowable-rest/service/runtime/process-instances

这会返回类似这样的结果:

{"id":"43","url":"http://localhost:8080/flowable-rest/service/runtime/process-instances/43","businessKey":null,"suspended":false,"ended":false,"processDefinitionId":"holidayRequest:1:42","processDefinitionUrl":"http://localhost:8080/flowable-rest/service/repository/process-definitions/holidayRequest:1:42","activityId":null,"variables":[],"tenantId":"","completed":false}

任务列表与完成任务​

流程实例启动时,第一个任务被分配给 'managers' 组。要获取该组的所有任务,可以通过 REST API 进行一次任务查询:

curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "candidateGroup" : "managers" }' http://localhost:8080/flowable-rest/service/query/tasks

这会返回 'managers' 组的所有任务列表。

现在可以使用以下方式完成这样一个任务:

curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "action" : "complete", "variables" : [ { "name" : "approved", "value" : true} ]  }' http://localhost:8080/flowable-rest/service/runtime/tasks/25

不过,你很可能会得到这样的错误:

{"message":"Internal server error","exception":"couldn't instantiate class org.flowable.CallExternalSystemDelegate"}

这意味着引擎找不到服务任务中引用的 CallExternalSystemDelegate 类。要解决这个问题,需要把该类放到应用的 classpath 上(这需要重启)。按照这一节所述创建该类,将其打包为 JAR,并放到 Tomcat 的 webapps 文件夹下 flowable-rest 文件夹的 WEB-INF/lib 文件夹中。