我们昨天发布的Activiti v6 Beta3中已经加入了一个非常需要的功能-临时变量。 在本文中,我将向您展示一个示例,该示例说明如何使用瞬态变量来覆盖一些以前不可能(或最佳)的高级用例。
到目前为止,Activiti中的所有变量都是持久的 。 这意味着将变量和值存储在数据存储中,并保留历史审核数据。 另一方面,瞬态变量的行为和行为类似于常规变量,但它们不会持久存在。 除了不持久之外,以下是瞬态变量的特殊功能:
- 当流程实例的状态持久保存到数据库时,临时变量将一直保留到下一个“等待状态”。
- 瞬态变量屏蔽具有相同名称的持久变量。
有关瞬时变量和API的更多详细信息,请参见文档 。
例
下面显示了用于演示暂态变量的某些位的过程定义。 这是一个非常简单的过程:想法是我们将向用户询问诸如关键字和语言之类的东西,并使用它来进行GitHub API调用。 如果成功,结果将显示给用户。 为此很容易编写一个UI(或使用Beta3 angularJS应用程序中的新表单 ),但是在这篇文章中,我们将只关注代码。
可以在以下Github存储库上找到BPMN 2.0 xml和代码: https : //github.com/jbarrez/transient-vars-example
让我们一起完成整个过程。 该过程首先从用户提供一些有关应搜索内容的输入开始(通常使用开始表格来完成)。
repositoryService.createDeployment().addClasspathResource("process.bpmn20.xml").deploy();
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("keyWord", "workflow");
variables.put("language", "java");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("githubsearch", variables);
常规变量。 它们将被保留,并且将保留审核历史记录,因为没有理由不应该这样做。
执行的第一步是“执行HTTP调用”步骤,这是带有Java委托的服务任务:
<serviceTask name="Execute HTTP call" activiti:class="org.activiti.ExecuteHttpCallDelegate"></serviceTask>
Java代码:
public class ExecuteHttpCallDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) {
String keyword = (String) execution.getVariable("keyWord");
String language = (String) execution.getVariable("language");
String url = "https://api.github.com/search/repositories?q=%s+language:%s&sort=starsℴ=desc";
url = String.format(url, keyword, language);
HttpGet httpget = new HttpGet(url);
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
CloseableHttpResponse response = httpclient.execute(httpget);
execution.setTransientVariable("response", IOUtils.toString(response.getEntity().getContent(), "UTF-8"));
execution.setTransientVariable("responseStatus", response.getStatusLine().getStatusCode());
response.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
setTransientVariable()调用)。 选择瞬态变量的原因是
- Github API的json响应非常大。 当然可以以持久的方式存储它,但这对性能不利。
- 从审计的角度来看,整个响应的意义很小。 稍后,我们将从响应中提取重要的位,并将这些位存储在历史数据中。
得到响应并将其存储在瞬态变量中之后,我们通过排它网关。 序列流如下所示:
<sequenceFlow ... >
<extensionElements>
<activiti:executionListener event="take" class="org.activiti.ProcessResponseExecutionListener"></activiti:executionListener>
</extensionElements>
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${responseStatus == 200}]]></conditionExpression>
</sequenceFlow>
请注意,对于顺序流动条件,使用瞬态或非瞬态变量没有区别。 常规的getVariable还将返回带有名称(如果已设置)的瞬态变量(这是上述文档中的阴影部分)。 当只应查询瞬态变量集时,也存在getTransientVariable 。 无论如何:对于条件:完全没有区别。
您还可以看到序列流具有一个(在图中隐藏的)执行侦听器。 执行监听器将解析json响应,选择相关位并将其存储在瞬态数组列表中。 这很重要,因为您将在代码下方阅读。
public class ProcessResponseExecutionListener implements ExecutionListener {
private ObjectMapper objectMapper = new ObjectMapper();
public void notify(DelegateExecution execution) {
List<String> searchResults = new ArrayList<String>();
String response = (String) execution.getVariable("response");
try {
JsonNode jsonNode = objectMapper.readTree(response);
JsonNode itemsNode = jsonNode.get("items");
if (itemsNode != null && itemsNode.isArray()) {
for (JsonNode itemNode : (ArrayNode) itemsNode) {
String url = itemNode.get("html_url").asText();
searchResults.add(url);
}
}
} catch (IOException e) {
e.printStackTrace();
}
execution.setTransientVariable("searchResults", searchResults);
}
}
将列表存储为瞬时变量的原因很重要。 如您在图中所看到的,接下来是一个多实例子流程。 子流程通常需要一个集合变量来创建实例。 到目前为止,这是一个持久变量,采用Java序列化 ArrayList的形式。 我从来没有喜欢过它(如果以前必须将委托表达与bean一起使用)。 这总是让我有些困扰。 现在,arraylist是临时的,不会存储在数据存储中:
<subProcess name="subProcess">
<multiInstanceLoopCharacteristics isSequential="false"
activiti:collection="searchResults" activiti:elementVariable="searchResult" />
请注意,上面的“ searchResult”变量将是一个持久变量。
请注意,在达到用户任务并将状态存储在数据存储中之前,瞬态变量将一直存在。 在启动流程实例时也可以传递瞬态变量(这在这里可以是一种选择,但是我认为存储用户输入是您想要的审计数据内容)。
例如,如果要像这样运行流程实例:
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("keyWord", "workflow");
variables.put("language", "java");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("githubsearch", variables);
List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
for (Task task : tasks) {
System.out.println("Current task : " + task.getName());
}
作为示例输出(限于5个结果):
当前任务:查看结果https://github.com/Activiti/Activiti 当前任务:查看结果https://github.com/twitter/ambrose 当前任务:查看结果https://github.com/azkaban/azkaban 当前任务:查看结果https://github.com/romannurik/AndroidDesignPreview 当前任务:审查结果https://github.com/spring-projects/spring-xd
…
用户现在可以查看每个结果的详细信息并继续该过程。
最后的话
您可以想象,瞬时变量有很多用例。 我知道对于许多人来说,这是一个重要的功能,所以我很高兴现在它已经面世了。 像往常一样,当然也欢迎您提供反馈和意见!
翻译自: https://www.javacodegeeks.com/2016/09/use-transient-variables-activiti.html