✔️本专栏将从Camunda(卡蒙达) 7中的关键概念到实现中国式工作流相关功能。
✔️文章中只包含演示核心代码及测试数据,完整代码可查看作者的开源项目snail-camunda
✔️请给snail-camunda 点颗星吧
变量可将数据添加到流程的某个范围【作用域】内使用。通常,变量由名称和值组成。该名称用于跨流程构造进行标识。例如,如果一个活动设置了一个名为var的变量,则后续活动可以使用该名称访问它。变量的值是一个Java对象。
所有可以具有变量的实体都称为变量作用域。作用域可以是执行(包括流程实例)和任务。参考以下流程模型,其中红点标记活动任务。
该流程的运行时结构如下:
如下图的流程实例,其中包含两个子执行,每个子执行都创建了一个任务。所有这五个实体都是变量作用域,箭头标记父子关系。在父作用域上定义的变量可以在每个子作用域中访问,除非子作用域定义了同名的变量。反之,无法从父范围访问子变量。直接附加到相关范围的变量称为局部变量。
在这种情况下,在处理Task 1 时,可以访问变量 worker 和 customer。由于作用域的结构,变量 worker 可以定义两次,以便Task 1 访问与Task 2 不同的工作变量。但是,两者都共享变量 customer,这意味着如果其中一个任务更新了该变量,则此更改对另一个任务也是可见的。
这两个任务都可以分别访问两个变量,而这些变量都不是局部变量。所有三个执行都各有一个局部变量。
假设我们在Task 1 上设置了一个局部变量 customer
虽然仍然可以从Task 1 访问名为 customer 和 worker 的两个变量,但Execution 1 上的 customer 变量是隐藏的,这里就是可见性的问题了,因此可访问的 customer 变量是Task 1 的局部变量。也可以理解为就近原则。
Primitive Types与其他变量值类型的不同之处在于,它们可以在 API 查询(例如流程实例查询)中用作过滤条件。
file类型可用于存储文件或输入流的内容以及元数据,如文件名、编码和文件内容对应的MIME类型。
object类型表示自定义Java对象。当这样的变量被持久化时,它的值将根据序列化过程进行序列化。这些过程是可配置和可交换的。
流程变量也可以通过Camunda Spin插件提供的JSON和XML等格式存储。Spin为类型对象的变量提供了序列化器,这样Java变量就可以以这些格式持久化到数据库中。
提示:
字符串值存储在数据库中类型为(n)varchar的列中,长度限制为4000 (Oracle为2000)。根据使用的数据库和配置的字符集,此长度限制可能导致实际字符的数量不同。可变值长度不会在Camunda引擎内部进行验证,如果超出长度限制,则会抛出数据库级异常。如果需要验证,则可以单独实现,并且必须在调用Camunda API设置变量之前进行。
当将Object类型变量传递给流程引擎时,可以指定序列化格式来告诉流程引擎以特定格式存储该值。基于此格式,引擎查找序列化器。序列化器能够将Java对象序列化为指定的格式,并将其从该格式的表示反序列化。
流程引擎为application/x-java-serialized-object格式提供了一个内置对象序列化器。它能够序列化实现接口Java .io. serializable的Java对象,并应用标准的Java对象序列化。不设置则默认为:defaultSerializationFormatapplication/x-java-serialized-object
CustomerData customerData = new CustomerData();
ObjectValue customerDataValue = Variables.objectValue(customerData)
.serializationDataFormat(Variables.SerializationDataFormats.JAVA)
.create();
execution.setVariable("someVariable", customerDataValue);
如下代码会在变量作用域层次结构的最高位置设置了一个变量。
com.example.Order order = new com.example.Order();
runtimeService.setVariable(execution.getId(), "order", order);
com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariable(execution.getId(), "order");
如果想精确地设置在某个执行上,则使用local 方法
com.example.Order order = new com.example.Order();
runtimeService.setVariableLocal(execution.getId(), "order", order);
com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariable(execution.getId(), "order");
com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariableLocal(execution.getId(), "order");
// both methods return the variable
它将变量值封装在所谓的类型化值中。
StringValue typedStringValue = Variables.stringValue("a string value");
runtimeService.setVariable(execution.getId(), "stringVariable", typedStringValue);
StringValue retrievedTypedStringValue = runtimeService.getVariableTyped(execution.getId(), "stringVariable");
String stringValue = retrievedTypedStringValue.getValue(); // equals "a string value"
文件可以作为 BLOB 保存在数据库中。
FileValue typedFileValue = Variables
.fileValue("addresses.txt")
.file(new File("path/to/the/file.txt"))
.mimeType("text/plain")
.encoding("UTF-8")
.create();
runtimeService.setVariable(execution.getId(), "fileVariable", typedFileValue);
FileValue retrievedTypedFileValue = runtimeService.getVariableTyped(execution.getId(), "fileVariable");
InputStream fileContent = retrievedTypedFileValue.getValue(); // a byte stream of the file contents
String fileName = retrievedTypedFileValue.getFilename(); // equals "addresses.txt"
String mimeType = retrievedTypedFileValue.getMimeType(); // equals "text/plain"
String encoding = retrievedTypedFileValue.getEncoding(); // equals "UTF-8"