1

Activiti Core

新API的目的很明确,以满足下列需求:

  • 隔离内部和外部API以提供向后兼容
  • 通过遵循单责任方法为模块化提供未来的途径
  • 减少以前版本的API的混乱情况
  • 纳入安全和身份管理
  • 对于希望依赖流行框架提供的约定的常见用例,可以减少实现的时间
  • 供基础服务的替代实现

尚未弃用旧的API,因此仍然可以自由使用它,但是强烈建议使用新的API以获得长期支持。

该API处于Beta测试阶段,这意味着可能会在GA发布之前对其进行更改和完善。

TaskRuntime API

如果要构建业务应用程序,那么为组织中的用户和组创建任务可能会很方便。

TaskRuntime API在这里可以为你提供帮助。

可以从GitHub克隆此示例:https://github.com/Activiti/activiti-examples

该部分的代码可以在“activiti-api-basic-task-example” maven模块中找到。

如果你在Spring Boot 2应用程序中运行,则只需添加activiti-spring-boot-starter依赖项和一个数据库驱动程序,即可将H2用于内存中存储。

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/pom.xml#L45

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

建议使用BOM。

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/pom.xml#L30

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.activiti.dependencies</groupId>
            <artifactId>activiti-dependencies</artifactId>
            <version>7.1.0.M5</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>
注意:可以使用以下链接检索最新版本:https://search.maven.org/search?q=activiti-dependencies

现在,切换到DemoApplication.classhttps://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplication.java#L25

然后,你将可以使用TaskRuntime

@Autowired
private TaskRuntime taskRuntime;

将bean注入应用程序后,你应该能够创建任务并与任务交互。

public interface TaskRuntime {
  TaskRuntimeConfiguration configuration();
  Task task(String taskId);
  Page tasks(Pageable pageable);
  Page tasks(Pageable pageable, GetTasksPayload payload);
  Task create(CreateTaskPayload payload);
  Task claim(ClaimTaskPayload payload);
  Task release(ReleaseTaskPayload payload);
  Task complete(CompleteTaskPayload payload);
  Task update(UpdateTaskPayload payload);
  Task delete(DeleteTaskPayload payload);
  ...
}

例如,你可以通过执行以下操作来创建任务:

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplication.java#L45

taskRuntime.create(
            TaskPayloadBuilder.create()
                .withName("First Team Task")
                .withDescription("This is something really important")
                .withGroup("activitiTeam")
                .withPriority(10)
           .build());

只有属于activitiTeam的用户和所有者(当前登录的用户)才能看到此任务。

你可能已经注意到,可以使用TaskPayloadBuilder以流畅的方式参数化将要发送到TaskRuntime的信息。

为了处理安全性、角色和组,依赖于Spring Security模块。因为在Spring Boot应用程序内部,所以可以使用UserDetailsS​​ervice来配置可用用户及其各自的组和角色,目前在@Configuration类中执行此操作:

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplicationConfiguration.java#L26

这里需要注意的重要一点是,为了作为用户与TaskRuntime API进行交互,你需要拥有角色:ACTIVITI_USER(授予的权限:ROLEACTIVITIUSER)。

与REST端点进行交互时,授权机制将设置当前登录的用户,但是为了这个例子,使用了一个工具类(https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/SecurityUtil.java#L26),允许在上下文中设置手动选择的用户。请注意,除非你正在尝试并且想要在不经过REST端点的情况下更改用户,否则切勿这样做。查看“web”示例,以查看根本不需要该实用工具类的更多真实场景​​。

该示例中要强调的最后一件事是任务事件侦听器的注册:

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplication.java#L89

@Bean
public TaskRuntimeEventListener taskAssignedListener() {
  return taskAssigned
           -> logger.info(
                 ">>> Task Assigned: '"
                + taskAssigned.getEntity().getName()
                +"' We can send a notification to the assignee: "
                + taskAssigned.getEntity().getAssignee());
}

你可以根据需要注册任意多个TaskRuntimeEventListener,当服务触发运行时事件时,这将使你的应用程序得到通知。

ProcessRuntime API

以类似的方式,如果要开始使用ProcessRuntime API,则需要包含与之前相同的依赖项,目标是在将来提供更大的灵活性和单独的运行时,但是目前,相同的Spring Boot Starter同时提供TaskRuntimeProcessRuntime API。

该部分的代码可以在“activiti-api-basic-process-example” maven模块内找到。

public interface ProcessRuntime {
  ProcessRuntimeConfiguration configuration();
  ProcessDefinition processDefinition(String processDefinitionId);
  Page processDefinitions(Pageable pageable);
  Page processDefinitions(Pageable pageable,
              GetProcessDefinitionsPayload payload);
  ProcessInstance start(StartProcessPayload payload);
  Page processInstances(Pageable pageable);
  Page processInstances(Pageable pageable,
              GetProcessInstancesPayload payload);
  ProcessInstance processInstance(String processInstanceId);
  ProcessInstance suspend(SuspendProcessPayload payload);
  ProcessInstance resume(ResumeProcessPayload payload);
  ProcessInstance delete(DeleteProcessPayload payload);
  void signal(SignalPayload payload);
  ...
}

TaskRuntime API相似,为了与ProcessRuntime API进行交互,当前登录的用户必须具有“ACTIVITI_USER”角色。

首先,注入ProcessRuntime

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-process-example/src/main/java/org/activiti/examples/DemoApplication.java#L32

@Autowired
private ProcessRuntime processRuntime;

@Autowired
private SecurityUtil securityUtil;

和之前一样,我们需要SecurityUtil帮助器来定义与API交互的用户。

现在,可以开始与ProcessRuntime进行交互了:

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-process-example/src/main/java/org/activiti/examples/DemoApplication.java#L47

Page processDefinitionPage = processRuntime
                                .processDefinitions(Pageable.of(0, 10));
logger.info("> Available Process definitions: " +
                  processDefinitionPage.getTotalItems());
for (ProcessDefinition pd : processDefinitionPage.getContent()) {
  logger.info("\t > Process definition: " + pd);
}

流程定义需要放在/src/main/resources/processes/中,在此示例中,定义了以下流程:

使用Spring Scheduling功能来每秒启动一个流程,从数组中拾取随机值以进行处理:

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-process-example/src/main/java/org/activiti/examples/DemoApplication.java#L67

@Scheduled(initialDelay = 1000, fixedDelay = 1000)
public void processText() {
  securityUtil.logInAs("system");
  String content = pickRandomString();
  SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yy HH:mm:ss");
  logger.info("> Processing content: " + content
                    + " at " + formatter.format(new Date()));
  ProcessInstance processInstance = processRuntime
                  .start(ProcessPayloadBuilder
                       .start()
                       .withProcessDefinitionKey("categorizeProcess")
                       .withProcessInstanceName("Processing Content: " + content)
                       .withVariable("content", content)
                       .build());
  logger.info(">>> Created Process Instance: " + processInstance);
}

与之前一样,使用ProcessPayloadBuilder以流畅的方式参数化我们希望启动哪个流程,以及使用哪个流程变量。

现在,如果我们回顾一下流程定义,你将发现3个服务任务,为了提供这些服务任务的实现,你需要定义Connector

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-process-example/src/main/java/org/activiti/examples/DemoApplication.java#L81

@Bean
public Connector processTextConnector() {
  return integrationContext -> {
      Map inBoundVariables = integrationContext.getInBoundVariables();
      String contentToProcess = (String) inBoundVariables.get("content")
     // Logic Here to decide if content is approved or not
     if (contentToProcess.contains("activiti")) {
        logger.info("> Approving content: " + contentToProcess);
        integrationContext.addOutBoundVariable("approved",true);
     } else {
        logger.info("> Discarding content: " + contentToProcess);
        integrationContext.addOutBoundVariable("approved",false);
     }
    return integrationContext;
  };
}

这些连接器使用Bean名称(在此示例中为“processTextConnector”)自动连接到ProcessRuntime,此bean名称是从流程定义内的serviceTask元素的implementation属性中选取的:

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-process-example/src/main/resources/processes/categorize-content.bpmn20.xml#L22

<bpmn:serviceTask id="Task_1ylvdew" name="Process Content" implementation="processTextConnector">

这个新的Connector接口是JavaDelegate的自然演变,新版本的Activiti Core将通过将它们包装在Connector实现中来尝试重用JavaDelagate

public interface Connector {
  IntegrationContext execute(IntegrationContext integrationContext);
}

连接器接收带有流程变量的IntegrationContext,并返回修改后的IntegrationContext,其结果需要映射回流程变量。

在前面的示例中,连接器实现正在接收“content”变量,并基于内容处理逻辑添加“approved”变量。

在这些连接器内,你可能会包含系统到系统的调用,例如REST调用和基于消息的交互。

查看Maven模块activiti-api-spring-integration-example以获取更高级的示例,该示例使用Spring Integrations基于文件轮询器启动流程。

完整示例

你可以找到使用ProcessRuntimeTaskRuntime API来自动执行以下流程的示例:

该部分的代码可以在“activiti-api-basic-full-example” maven模块内找到。

作为仅ProcessRuntime的示例,它还对一些输入内容进行了分类,但是在这种情况下,该过程依赖于人工来决定是否批准内容。与之前一样,有一个调度任务,该任务每5秒创建一个新的流程实例,并且模拟用户检查是否有可用的任务要处理。

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-full-example/src/main/java/org/activiti/examples/DemoApplication.java#L63

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-full-example/src/main/java/org/activiti/examples/DemoApplication.java#L85

UserTask创建给一个potentialOwner,在本示例中为“activitiTeam”组,但是在这种情况下,我们不会像第一个示例那样手动创建任务,每次启动流程时,流程实例都会为我们创建任务。

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-full-example/src/main/resources/processes/categorize-human-content.bpmn20.xml#L38

<bpmn:userTask id="Task_1ylvdew" name="Process Content">
  <bpmn:incoming>SequenceFlow_09xowo4</bpmn:incoming>
  <bpmn:outgoing>SequenceFlow_1jzbgkj</bpmn:outgoing>
  <bpmn:potentialOwner>
    <bpmn:resourceAssignmentExpression>
      <bpmn:formalExpression>activitiTeam</bpmn:formalExpression>
    </bpmn:resourceAssignmentExpression>
  </bpmn:potentialOwner>
</bpmn:userTask>

属于该组的用户将可以领取任务并处理任务。



博弈
2.5k 声望1.5k 粉丝

态度决定一切


引用和评论

0 条评论