Activiti 是一个自动化工作流框架。它能帮助企业快速搭建分布式、高扩展的工作流框架。
下面这篇文章将会带你探索Activiti 工作流核心运行时API - TaskRuntime API。(P.S. 这篇文章基本上是我对官网文章的翻译,英文好的请看官网原文)
TaskRuntime API
下面有写一些demo.这些demo是Activiti官网展示的一些例子,你可以从这个地址下载这些demo。
TaskRunTime API 部分的例子可以在activiti-api-basic-task-example模块中找到。
pom.xml
在Spring Boot2 中使用Activiti添加相关依赖以及数据库驱动就行。
比如在pom.xml文件中添加以下依赖:pom.xml
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
建议使用下面的BOM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.1.0.M4</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
注册TaskRuntime实例
通过下面的方式我们可以将TaskRuntime的实例注册到APP中。
@Autowired
private TaskRuntime taskRuntime;
TaskRuntime接口中定义了一系列方法来帮助我们创建任务实例以及与任务进行交互,源码如下所示。
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);
...
}
我们可以使用TaskPayloadBuilder参数化任务的信息,来平滑地构建一个TaskRuntime实例:
taskRuntime.create(
TaskPayloadBuilder.create()
.withName("First Team Task")
.withDescription("This is something really important")
.withGroup("activitiTeam")
.withPriority(10)
.build());
上面方式创建的任务只能被 “activitiTeam” 这个分组以及任务拥有者(当前登录用户)看到。
角色与分组
在SpringBoot 工程中,为了安全考虑,角色和分组的创建Activiti依赖Spring Security 模块。在SpringBoot 工程中我们可以使用 UserDetailsService来配置可以与任务进行交互的用户以及他们各自对应的角色和分组。这个demo中是在@Configuration 配置的类中进行设置的.
需要注意的是:与TaskRuntime API 交互,必须拥有 ACTIVITI_USER 角色 (权限是: ROLE_ACTIVITI_USER)。
当与REST端点进行交互的时候,Activiti授权机构将自动设置当前登录用户。但是因为这个demo是一个教学性质的实例,它允许我们手动设置当前登录用户。在实际的工作场景中,千万不要这么做,除非你想不经过REST端点(例如HTTP请求)就改变登录用户。
任务事件监听器
最后一件需要强调的事情就是任务事件监听器的注册。
我们可以按照需要注册任意多个TaskRuntimeEventListeners。当服务触发运行时事件时,监听器能够监听到这一动作,并通知应用程序。
@Bean
public TaskRuntimeEventListener taskAssignedListener() {
return taskAssigned
-> logger.info(
">>> Task Assigned: '"
+ taskAssigned.getEntity().getName()
+"' We can send a notification to the assignee: "
+ taskAssigned.getEntity().getAssignee());
}
DemoApplication 源码
下面是DemoApplication的源码,注释里已经详细地解释了代码的含义。完整代码请查看官方源码:
package org.activiti.examples;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.api.task.runtime.events.TaskAssignedEvent;
import org.activiti.api.task.runtime.events.TaskCompletedEvent;
import org.activiti.api.task.runtime.events.listener.TaskRuntimeEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
private Logger logger = LoggerFactory.getLogger(DemoApplication.class);
@Autowired
private TaskRuntime taskRuntime;
@Autowired
private SecurityUtil securityUtil;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) {
// Using Security Util to simulate a logged in user
securityUtil.logInAs("salaboy");
// Let's create a Group Task (not assigned, all the members of the group can claim it)
// Here 'salaboy' is the owner of the created task
logger.info("> Creating a Group Task for 'activitiTeam'");
taskRuntime.create(TaskPayloadBuilder.create()
.withName("First Team Task")
.withDescription("This is something really important")
.withCandidateGroup("activitiTeam")
.withPriority(10)
.build());
// Let's log in as 'other' user that doesn't belong to the 'activitiTeam' group
securityUtil.logInAs("other");
// Let's get all my tasks (as 'other' user)
logger.info("> Getting all the tasks");
Page<Task> tasks = taskRuntime.tasks(Pageable.of(0, 10));
// No tasks are returned
logger.info("> Other cannot see the task: " + tasks.getTotalItems());
// Now let's switch to a user that belongs to the activitiTeam
securityUtil.logInAs("erdemedeiros");
// Let's get 'erdemedeiros' tasks
logger.info("> Getting all the tasks");
tasks = taskRuntime.tasks(Pageable.of(0, 10));
// 'erdemedeiros' can see and claim the task
logger.info("> erdemedeiros can see the task: " + tasks.getTotalItems());
String availableTaskId = tasks.getContent().get(0).getId();
// Let's claim the task, after the claim, nobody else can see the task and 'erdemedeiros' becomes the assignee
logger.info("> Claiming the task");
taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(availableTaskId).build());
// Let's complete the task
logger.info("> Completing the task");
taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(availableTaskId).build());
}
@Bean
public TaskRuntimeEventListener<TaskAssignedEvent> taskAssignedListener() {
return taskAssigned -> logger.info(">>> Task Assigned: '"
+ taskAssigned.getEntity().getName() +
"' We can send a notification to the assginee: " + taskAssigned.getEntity().getAssignee());
}
@Bean
public TaskRuntimeEventListener<TaskCompletedEvent> taskCompletedListener() {
return taskCompleted -> logger.info(">>> Task Completed: '"
+ taskCompleted.getEntity().getName() +
"' We can send a notification to the owner: " + taskCompleted.getEntity().getOwner());
}
}
下面是运行结果
...
2019-10-05 16:58:53.900 INFO 6268 --- [ main] o.a.e.DemoApplicationConfiguration : > Registering new user: salaboy with the following Authorities[[ROLE_ACTIVITI_USER, GROUP_activitiTeam]]
2019-10-05 16:58:54.175 INFO 6268 --- [ main] o.a.e.DemoApplicationConfiguration : > Registering new user: ryandawsonuk with the following Authorities[[ROLE_ACTIVITI_USER, GROUP_activitiTeam]]
2019-10-05 16:58:54.422 INFO 6268 --- [ main] o.a.e.DemoApplicationConfiguration : > Registering new user: erdemedeiros with the following Authorities[[ROLE_ACTIVITI_USER, GROUP_activitiTeam]]
2019-10-05 16:58:54.580 INFO 6268 --- [ main] o.a.e.DemoApplicationConfiguration : > Registering new user: other with the following Authorities[[ROLE_ACTIVITI_USER, GROUP_otherTeam]]
2019-10-05 16:58:54.742 INFO 6268 --- [ main] o.a.e.DemoApplicationConfiguration : > Registering new user: admin with the following Authorities[[ROLE_ACTIVITI_ADMIN]]
...
2019-10-05 16:59:00.232 INFO 6268 --- [ main] org.activiti.examples.SecurityUtil : > Logged in as: salaboy
2019-10-05 16:59:00.233 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : > Creating a Group Task for ‘activitiTeam‘
2019-10-05 16:59:00.261 INFO 6268 --- [ main] org.activiti.examples.SecurityUtil : > Logged in as: other
2019-10-05 16:59:00.261 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : > Getting all the tasks
2019-10-05 16:59:00.380 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : > Other cannot see the task: 0
2019-10-05 16:59:00.380 INFO 6268 --- [ main] org.activiti.examples.SecurityUtil : > Logged in as: erdemedeiros
2019-10-05 16:59:00.380 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : > Getting all the tasks
2019-10-05 16:59:00.395 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : > erdemedeiros can see the task: 1
2019-10-05 16:59:00.395 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : > Claiming the task
2019-10-05 16:59:00.405 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : >>> Task Assigned: ‘First Team Task‘ We can send a notification to the assginee: erdemedeiros
2019-10-05 16:59:00.425 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : > Completing the task
2019-10-05 16:59:00.457 INFO 6268 --- [ main] org.activiti.examples.DemoApplication : >>> Task Completed: ‘First Team Task‘ We can send a notification to the owner: salaboy