1. Overview
1.概述
Simply put, Activiti is a workflow and Business Process Management platform.
简单地说,Activiti是一个工作流程和业务流程管理平台。
We can get started quickly by creating a ProcessEngineConfiguration (typically based on a configuration file). From this, we can obtain a ProcessEngine – and through the ProcessEngine, we can execute workflow & BPM operations.
我们可以通过创建ProcessEngineConfiguration(通常基于一个配置文件)来快速入门。由此,我们可以获得一个ProcessEngine – 通过ProcessEngine,我们可以执行工作流和BPM操作。
The API provides various services that can be used to access and manage processes. These services can provide us information about the history of processes, what’s currently running and the processes that are deployed but not running yet.
该API提供了各种服务,可用于访问和管理进程。这些服务可以为我们提供有关进程历史的信息,当前正在运行的内容以及已经部署但尚未运行的进程。
The services can also be used to define the process structure and manipulate the state of the process, i.e. run, suspend, cancel, etc.
这些服务还可以用来定义进程结构和操纵进程的状态,即运行、暂停、取消等。
If you are new to the API, check out our Introduction to Activiti API with Java. In this article, we’ll discuss how we can set up Activiti API within a Spring Boot application.
如果你是API的新手,请查看我们的用Java介绍Activiti API。在这篇文章中,我们将讨论如何在Spring Boot应用程序中设置Activiti API。
2. Setup With Spring Boot
2.使用Spring Boot进行设置
Let’s see how we can setup Activiti as a Spring Boot Maven application and start using it.
让我们看看如何将Activiti设置为Spring Boot Maven应用程序,并开始使用它。
2.1. Initial Setup
2.1.初始设置
As usual, we need to add the maven dependency:
像往常一样,我们需要添加maven的依赖性。
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
</dependency>
The latest stable version of the API can be found here. It works with Spring Boot up through v1.5.4. It doesn’t work with v2.0.0.M1 yet.
该API的最新稳定版本可以在这里找到。它可以与Spring Boot的v1.5.4版本一起使用。它还不能与v2.0.0.1版一起使用。
We can also generate a Spring Boot project using https://start.spring.io and select Activiti as a dependency.
我们也可以使用https://start.spring.io生成一个Spring Boot项目,并选择Activiti作为依赖项。
Just by adding this dependency and the @EnableAutoConfiguration annotation to the Spring Boot Application, it’ll do the initial setup:
只要把这个依赖关系和@EnableAutoConfiguration注解添加到Spring Boot应用程序中,它就能完成初始设置。
- Create Datasource (The API requires a database to create the ProcessEngine)
- Create and Expose the ProcessEngine bean
- Create and Expose the Activiti services beans
- Create the Spring Job Executor
2.2. Creating and Running a Process
2.2.创建和运行一个进程
Let’s construct an example of creating and running a business process. To define a process we will need to create a BPMN file.
让我们构建一个创建和运行一个业务流程的例子。为了定义一个流程,我们将需要创建一个BPMN文件。
Then, just download the BPMN file. We will need to put this file in the src/main/resources/processes folder. By default, Spring Boot will look in this folder to deploy the process definition.
然后,只要下载BPMN文件。我们将需要把这个文件放在src/main/resources/processes文件夹中。默认情况下,Spring Boot会在这个文件夹中查找,以部署流程定义。
We’ll create a demo process containing one user tasks:
我们将创建一个包含一个用户任务的演示流程。
The assignee of the user task is set as the Initiator of the process. The BPMN file for this process definition looks like:
用户任务的分配者被设定为流程的发起者。这个流程定义的BPMN文件看起来像。
<process id="my-process" name="say-hello-process" isExecutable="true">
<startEvent id="startEvent" name="startEvent">
</startEvent>
<sequenceFlow id="sequence-flow-1" sourceRef="startEvent" targetRef="A">
</sequenceFlow>
<userTask id="A" name="A" activiti:assignee="$INITIATOR">
</userTask>
<sequenceFlow id="sequence-flow-2" sourceRef="A" targetRef="endEvent">
</sequenceFlow>
<endEvent id="endEvent" name="endEvent">
</endEvent>
</process>
Now, we’ll create a REST controller to handle requests to start this process:
现在,我们将创建一个REST控制器来处理启动这个过程的请求。
@Autowired
private RuntimeService runtimeService;
@GetMapping("/start-process")
public String startProcess() {
runtimeService.startProcessInstanceByKey("my-process");
return "Process started. Number of currently running"
+ "process instances = "
+ runtimeService.createProcessInstanceQuery().count();
}
Here, runtimeService.startProcessInstanceByKey(“my-process”) starts the execution of the process whose key is “my-process”. runtimeService.createProcessInstanceQuery().count() will get us the number of process instances.
这里,runtimeService.startProcessInstanceByKey(“my-process”)开始执行键为“my-process”的进程。runtimeService.createProcessInstanceQuery().count()将获得进程实例的数量。
Every time we hit the path “/start-process”, a new ProcessInstance will be created and we’ll see an increment in the count of the currently running processes.
每次我们点击路径“/start-process”,一个新的ProcessInstance将被创建,我们将看到当前运行的进程数量的增加。
A JUnit test case shows us this behavior:
一个JUnit测试案例向我们展示了这种行为。
@Test
public void givenProcess_whenStartProcess_thenIncreaseInProcessInstanceCount()
throws Exception {
String responseBody = this.mockMvc
.perform(MockMvcRequestBuilders.get("/start-process"))
.andReturn().getResponse().getContentAsString();
assertEquals("Process started. Number of currently running"
+ " process instances = 1", responseBody);
responseBody = this.mockMvc
.perform(MockMvcRequestBuilders.get("/start-process"))
.andReturn().getResponse().getContentAsString();
assertEquals("Process started. Number of currently running"
+ " process instances = 2", responseBody);
responseBody = this.mockMvc
.perform(MockMvcRequestBuilders.get("/start-process"))
.andReturn().getResponse().getContentAsString();
assertEquals("Process started. Number of currently running"
+ " process instances = 3", responseBody);
}
3. Playing With Processes
3.玩转程序
Now that we have a running process in Activiti using Spring Boot let’s extend the above example to demonstrate how we can access and manipulate the process.
现在,我们在Activiti中使用Spring Boot有了一个正在运行的进程,让我们扩展上面的例子,展示我们如何访问和操作这个进程。
3.1. Get the List of Tasks for a Given ProcessInstance
3.1.获取给定进程实例的任务列表
We have two user tasks A and B. When we start a process, it’ll wait for the first task A to be completed and then will execute task B. Let’s create a handler method that accepts requests to view the tasks related to a given processInstance.
我们有两个用户任务A和B。当我们启动一个进程时,它将等待第一个任务A完成,然后将执行任务B。让我们创建一个处理方法,接受查看与给定processInstance相关的任务的请求。
The objects, like Task, cannot be sent as a response directly and hence we need to create a custom object and convert the Task to our custom object. We’ll call this class TaskRepresentation:
像Task这样的对象,不能直接作为响应发送,因此我们需要创建一个自定义对象,并将Task转换为我们的自定义对象。我们将这个类称为TaskRepresentation。
class TaskRepresentation {
private String id;
private String name;
private String processInstanceId;
// standard constructors
}
The handler method will look like:
处理方法将看起来像。
@GetMapping("/get-tasks/{processInstanceId}")
public List<TaskRepresentation> getTasks(
@PathVariable String processInstanceId) {
List<Task> usertasks = taskService.createTaskQuery()
.processInstanceId(processInstanceId)
.list();
return usertasks.stream()
.map(task -> new TaskRepresentation(
task.getId(), task.getName(), task.getProcessInstanceId()))
.collect(Collectors.toList());
}
Here, taskService.createTaskQuery().processInstanceId(processInstanceId).list() uses TaskService and gets us the list of tasks related to the given processInstanceId. We can see that when we start running the process we created, we will get the task A by making a request to the method we just defined:
这里,taskService.createTaskQuery().processInstanceId(processInstanceId).list() 使用TaskService,为我们获取与给定processInstanceId相关的任务列表。我们可以看到,当我们开始运行我们创建的进程时,我们将通过向我们刚刚定义的方法发出请求来获得任务A。
@Test
public void givenProcess_whenProcessInstance_thenReceivedRunningTask()
throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.get("/start-process"))
.andReturn()
.getResponse();
ProcessInstance pi = runtimeService.createProcessInstanceQuery()
.orderByProcessInstanceId()
.desc()
.list()
.get(0);
String responseBody = this.mockMvc
.perform(MockMvcRequestBuilders.get("/get-tasks/" + pi.getId()))
.andReturn()
.getResponse()
.getContentAsString();
ObjectMapper mapper = new ObjectMapper();
List<TaskRepresentation> tasks = Arrays.asList(mapper
.readValue(responseBody, TaskRepresentation[].class));
assertEquals(1, tasks.size());
assertEquals("A", tasks.get(0).getName());
}
3.2. Completing a Task
3.2.完成一项任务
Now, we will see what happens when we complete task A. We create a handler method that will handle requests to complete the task A for the given processInstance:
现在,我们将看看当我们完成任务A时会发生什么。我们创建一个处理方法,它将处理为给定的processInstance完成任务A的请求。
@GetMapping("/complete-task-A/{processInstanceId}")
public void completeTaskA(@PathVariable String processInstanceId) {
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)
.singleResult();
taskService.complete(task.getId());
}
taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult() creates a query on the task service and gives us the task of the given processInstance. This is the UserTask A. The next line taskService.complete(task.getId) completes this task.
Hence, now the process has reached the end and the RuntimeService doesn’t contain any ProcessInstances. We can see this using the JUnit test case:
taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult()在任务服务上创建一个查询,给我们提供给定processInstance的任务。这就是UserTask A。下一行taskService.complete(task.getId)完成了这个任务。
因此,现在进程已经到达终点,RuntimeService不包含任何ProcessInstances。我们可以通过JUnit测试案例看到这一点。
@Test
public void givenProcess_whenCompleteTaskA_thenNoProcessInstance()
throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.get("/start-process"))
.andReturn()
.getResponse();
ProcessInstance pi = runtimeService.createProcessInstanceQuery()
.orderByProcessInstanceId()
.desc()
.list()
.get(0);
this.mockMvc.perform(MockMvcRequestBuilders.get("/complete-task-A/" + pi.getId()))
.andReturn()
.getResponse()
.getContentAsString();
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().list();
assertEquals(0, list.size());
}
This is how we can use Activiti services work with processes.
这就是我们如何利用Activiti服务与流程合作。
4. Conclusion
4.结论
In this article, we went through the overview of using the Activiti API with Spring Boot. More information about the API can be found in the user guide. We also saw how to create a process and execute various operations on it using Activiti services.
在这篇文章中,我们了解了在Spring Boot中使用Activiti API的概况。关于API的更多信息可以在用户指南中找到。我们还看到了如何创建一个流程并使用Activiti服务对其执行各种操作。
Spring Boot makes it easy to use as we don’t need to worry about creating the database, deploying the processes or creating the ProcessEngine.
Spring Boot使其易于使用,因为我们不需要担心创建数据库、部署进程或创建ProcessEngine。
Keep in mind the integration of Activiti with Spring Boot is still in the experimental phase and it is not yet supported by Spring Boot 2.
请记住,Activiti与Spring Boot的整合仍处于实验阶段,Spring Boot 2还不支持它。
As always, implementation of all the examples we saw can be found over on GitHub.
一如既往,我们所看到的所有例子的实现都可以在GitHub上找到over。