栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Activiti 7.x 新 API 的使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Activiti 7.x 新 API 的使用

概述

Activiti 7 提供 Activiti Cloud 和 Activiti Core 两种使用方式。前者以 Cloud Native 方式提供云端部署并以微服务方式使用;后者仍然可以集成到产品中使用(由集成着自己封装微服务)。

新的 API 封装在 org.activiti.api 包中。目前网上针对这些新 API 的使用方法介绍文档非常少,除了官方 Activiti Core 简单介绍外,就只剩下 Activiti Core Examples 样例代码。

本文尝试对新 API 的使用方法做些简单说明,供大家使用 Activiti 7 时进行参考。

本文的读者是熟悉 Activiti 基本原理,能熟练使用 Activiti 5/6,并希望了解 Activiti 7.x 新提供的 XXXRuntime API 的开发人员,

Activiti 7.x 新 API 的设计思路

从现有官方文档和样例分析看来,Activiti 7.x 新 API 在设计方面做了以下工作:

  • 与 Spring Boot 及 Spring Security 做了深度集成。包括流程发起者(Initiator),用户任务(User Task)的执行人(Assignee)等,直接从 Sprint Security 的 Security Context 中获取。当项目集成了 Spring Security 后,会非常方便。
  • 服务任务(Service Task)可直接调用 Srping 的 Bean(org.activiti.api.process.runtime.connector.Connector 类型);流程流转过程中的各类事件(如流程启动/完成、任务开始/结束、变量创建等等),均可通过创建 Spring 的 Bean,并返回相应类型来监听和处理。
  • 对流程流转过程中的变量(Variable)访问方式进行了重新设计:变量分为流程级别(Process)和任务级别(Task),可分别通过 ProcessRuntime 和 TaskRuntime 进行访问。当然底层实现仍然与 Execution 绑定。个人认为,这部分的设计并不完善,会给流程过程造成很多麻烦。规避方式就是仍然使用原有的 XXXService 接口。详见后文样例。

需说明一点:Activiti 7.x 向前兼容,即原有的 XXXService API 仍然可继续使用。新的 XXXRuntime API 是对原有 XXX Service API 进行了一层封装而已。

上述几点工作中,Spring 和 Spring Security 集成方式很好理解,参考其样例代码即可。本文对其新的 Variable 设计和使用方式进行分析说明。

Activiti 7.x 中的变量(Variable)

Activiti 7.x 中的变量(Variable)可分为两级:

  • 流程级:整个流程过程中均能访问。在流程启动时可设置,在服务任务(Service Task)中可通过 OutBoundVariable 并配合 -extensions.json 配置文件进行设置。
  • 任务级:仅用户任务( User Task)中使用的变量。

下面代码演示如何通过新的 API 访问这两类变量:

void listProcessVariables(String processInstanceId) {
    log.info(">>> Process Variables:");
    List variables = processRuntime.variables(
        ProcessPayloadBuilder.variables().withProcessInstanceId(processInstanceId).build());
    for (VariableInstance vi : variables) {
        log.info("t> " + vi.getName() + " -> " + vi.getValue());
    }
}
 
void listTaskVariables(String taskId) {
    log.info(">>> Task Variables:");
    List  variables = taskRuntime.variables(
        TaskPayloadBuilder.variables().withTaskId(taskId).build());
    for (VariableInstance vi : variables) {
        log.info("t> " + vi.getName() + " -> " + vi.getValue());
        if ("content".equals(vi.getName())) {
        }
    }
}

注意:processRuntime 提供 API 来设置变量,但其结合 Spring Security 对调用者身份进行了验证:仅允许流程的发起者执行此操作。

因此用户任务( User Task)暂时没有找到设置流程级变量的方法。

两类变量的区别可参考下表:

变量类型

设置方式

获取方式

流程级
  • 流程启动时设置。
  • Service Task 中通过 OutBoundVariable 设置(需结合 -exentions.json 配置文件)。
  • 如果 User Task 的执行者为流程发起者(Initiator),也可通过调用 ProcessRuntime API 进行设置。
  • User Task 或 Service Task 中可通过 ProcessRuntime API 获取。
  • Service Task 通过 InBoundVariable 传入(需结合 -exentions.json 配置文件)。
  • User Task 可通过 -exentions.json 配置文件将流程级变量转换为当前任务的任务级变量,并通过 TaskRuntime API 获取。
任务级
  • User Task 中在 complete() 时传入。
  • User Task 使用 TaskRuntime 设置。
  • User Task 可通过 TaskRuntime API 获取。

在 Activiti 7 中,流程定义文件缺省放置在 src/main/resources/processes/ 路径下,Spring Boot 启动时会自动从该路径下加载流程定义文件(*.bpmn20.xml)。

此外,还会同时加载 -extensions.json 配置文件。该配置文件目前在网上没有找到任何文档说明,因此只能通过测试和阅读 Activiti 源代码获取一些基本用法(Activiti 源代码没有注释,很郁闷)。

以下为此扩展配置文件中对变量(Variable)控制的一些基本配置信息,供参考。

选取配置文件为 activiti-api-basic-connector-example 中的例子进行修改,如下:

{
  "id": "RankMovieIdModel",
  "extensions": {
    "RankMovieId": {
      "mappings": {
        "serviceTaskId": {
          "inputs": {
            "movieName": {
              "type": "variable",
              "value": "movieToRank"
            }
          },
          "outputs": {
            "movieDesc": {
              "type": "variable",
              "value": "movieDescription"
            }
          }
        },
        "userTaskId": {
          "inputs": {
            "movieName": {
              "type": "variable",
              "value": "movieToRank"
            },
            "movieDescription": {
              "type": "variable",
              "value": "movieDesc"
            }
          }
        }
      },
      "properties": {
        "movieToRankId": {
          "id": "movieToRankId",
          "name": "movieToRank",
          "type": "string",
          "required": true
        },
        "movieDescId": {
          "id": "movieDescId",
          "name": "movieDesc",
          "type": "string",
          "required": false
        }
      }
    }
  }
}

配置文件中,extensions.RankMovieId 指定了此文件对 ID 为 RankMovieId 的流程生效(对应到 *.bpmn20.xml 中流程定义的 ID)。包含两个部分:

  • mappings:对流程中 ServiceTask 和 UserTask 使用的变量进行控制。
  • properties:对流程级变量的类型进行说明。

接下来结合样例代码,我们看下这些配置的作用。

样例流程定义如下:

 流程启动后,先进入一个 Service Task,从 Service Task 中获取到 Movie 的 Description,然后进入 Add Rating 的 User Task,由用户对这个 Movie 打分(Rating)。

启动流程的代码如下:

ProcessInstance startProcess() {
    ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder.start()
        .withProcessDefinitionKey("RankMovieId")
        .withName("myProcess")
        .withVariable("movieToRank", "Lord of the rings").build());
    return processInstance;
}

启动流程时,通过 withVariable 创建了一个流程级别的变量:movieToRank。

在接下来执行的 ServiceTask 时(TaskID 为 serviceTaskId),通过 extentions.json 定义了一个名称为 movieName 的变量给 ServiceTask 使用,其值为 movieToRank 流程变量的值。

于是 ServiceTask 的处理代码可以访问此变量值:

@Bean("Movies.getMovieDesc")
public Connector getMovieDesc() {
    return integrationContext -> {
        Map inBoundVariables = integrationContext.getInBoundVariables();
        logger.info(">> inbound: " + inBoundVariables);
        integrationContext.addOutBoundVariable("movieDescription",
            "The Lord of the Rings is an epic high fantasy novel written by English author and scholar J. R. R. Tolkien");
        return integrationContext;
    };
}

上面代码输出的日志中,将输出:

>> inbound: {movieName=Lord of the rings}

注意在 Task 中拿到的变量名称为 movieName,不再是流程变量中的 movieToRank。

该 Task 中增加一个输出变量:movieDescription,结合 extentions.json 中定义的输出变量名 movieDesc,任务执行完成后,将创建一个新的流程级变量:movieDesc(注意是以 extensions.json 中定义的变量名为准,而不是 addOutBoundVariable 中传入的变量名参数)。

接下来在 UserTask 中,可以通过 ProcessRuntime 获取进程级变量。上面的  extentions.json 中定义了两个 UserTask 的输入变量 movieName 和 movieDescription,因此也可以通过 TaskRuntime 获取到任务级的变量(注意变量名与流程级的变量名不同)。

UserTask 完成时,可传入新的变量 rating:

void completeAvailableTasks() {
    Page tasks = taskRuntime.tasks(Pageable.of(0, 20));
    tasks.getContent().forEach(task -> {
        logger.info(">>> Performing task -> " + task);
        listTaskVariables(task);
        taskRuntime.complete(TaskPayloadBuilder.complete()
            .withTaskId(task.getId())
            .withVariable("rating", 5).build());
    });
}

注意:这个新的变量 rating 只能作为任务级别变量,无法成为流程级别,即使 extensions.json 中增加了 outputs 定义,也不行(实测无效)。

问题及规避

目前的设计,无法在 UserTask 中设置流程级别的变量。前文已经说过,即使用 ProcessRuntime 也无法设置,仅当 UserTask 的 Assignee 是流程的创建者才行。

这会带来一些问题:例如在子流程 UserTask 中设置的值,无法作为变量用于父流程中 Exclusive Gateway 的判断表达式。

这时,只能使用传统的 runtimeService 方法,设置流程全局变量:

String executionId = taskService.createTaskQuery().taskId(task.getId()).list().get(0).getExecutionId();
runtimeService.setVariable(executionId, "approved", approved);

结论

Activiti 7 的新 Runtime API 设计思路很好,但并不完善。

实际使用过程中,往往需要结合原有的 Service API,才能实现完整的功能。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/981328.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号