我们昨天发布的Activiti v6 Beta3中已经加入了一个非常需要的功能-临时变量。 在本文中,我将向您展示一个示例,该示例说明如何使用瞬态变量来覆盖一些以前不可能(或最佳)的高级用例。

到目前为止,Activiti中的所有变量都是持久的 。 这意味着将变量和值存储在数据存储中,并保留历史审核数据。 另一方面,瞬态变量的行为和行为类似于常规变量,但它们不会持久存在。 除了不持久之外,以下是瞬态变量的特殊功能:

  • 当流程实例的状态持久保存到数据库时,临时变量将一直保留到下一个“等待状态”。
  • 瞬态变量屏蔽具有相同名称的持久变量。

有关瞬时变量和API的更多详细信息,请参见文档 。

下面显示了用于演示暂态变量的某些位的过程定义。 这是一个非常简单的过程:想法是我们将向用户询问诸如关键字和语言之类的东西,并使用它来进行GitHub API调用。 如果成功,结果将显示给用户。 为此很容易编写一个UI(或使用Beta3 angularJS应用程序中的新表单 ),但是在这篇文章中,我们将只关注代码。

可以在以下Github存储库上找到BPMN 2.0 xml和代码: https : //github.com/jbarrez/transient-vars-example

flowable 瞬态变量 Transient Variables_数据库

让我们一起完成整个过程。 该过程首先从用户提供一些有关应搜索内容的输入开始(通常使用开始表格来完成)。

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