1. 概述
簡單來説,Activiti 是一款工作流和業務流程管理平台。
我們可以快速上手,通過創建 ProcessEngineConfiguration(通常基於配置文件)來啓動。從中,我們可以獲得 ProcessEngine – 以及通過 ProcessEngine,我們可以執行工作流和 BPM 操作。
API 提供各種服務,可用於訪問和管理流程。這些服務可以向我們提供關於流程歷史、正在運行的流程以及尚未運行的部署流程的信息。
這些服務還可以用於定義流程結構和操作流程狀態,即運行、暫停、取消等。
如果您是 API 的新手,請查看我們的 Activiti API 使用 Java 入門。 在本文中,我們將討論如何在 Spring Boot 應用程序中設置 Activiti API。
2. 使用 Spring Boot 進行配置
讓我們看看如何將 Activiti 配置為 Spring Boot Maven 應用程序,並開始使用它。
2.1. 初步設置
如往常一樣,我們需要添加 Maven 依賴:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
</dependency>最新穩定版本的API可以在這裏找到:這裏。
我們還可以使用 https://start.spring.io 生成 Spring Boot 項目,並選擇 Activiti 作為依賴。
只需添加此依賴項和在 Spring Boot Application 中添加 @EnableAutoConfiguration 註解,它就會完成初始設置:
- 創建數據源(API 需要一個數據庫來創建 ProcessEngine)
- 創建並暴露 ProcessEngine Bean
- 創建並暴露 Activiti 服務 Bean
- 創建 Spring Job Executor
2.2. 創建和運行流程
為了構建一個流程示例,我們需要創建一個業務流程。定義流程時,我們需要創建一個 BPMN 文件。
然後,只需下載 BPMN 文件。我們需要將該文件放在 src/main/resources/processes 文件夾中。 Spring Boot 默認會在此文件夾中查找流程定義進行部署。
我們將創建一個包含一個用户任務的演示流程:
用户任務的負責人設置為流程的發起人。 此流程定義的 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>現在,我們將創建一個 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();
}在這裏,runtimeService.startProcessInstanceByKey(“my-process”)啓動了名為 “my-process”的流程的執行。 runtimeService.createProcessInstanceQuery().count()將幫助我們獲取流程實例的數量。
每次訪問路徑 “/start-process”時,都會創建一個新的 ProcessInstance,並且當前正在運行的流程數量會增加。
一個 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. 玩轉流程
現在我們已經在一個使用 Spring Boot 的 Activiti 中運行一個流程,接下來讓我們擴展上面的示例,演示如何訪問和操作流程。
3.1. 獲取指定 ProcessInstance 的任務列表
我們有兩個用户任務:A 和 B。當啓動流程時,它會等待第一個任務 A 完成,然後執行任務 B。 讓我們創建一個處理方法,用於查看與給定 ProcessInstance 相關的任務。
任務對象(如 Task)不能直接作為響應發送,因此我們需要創建一個自定義對象並將 Task 轉換為我們的自定義對象。 我們將調用此類為 TaskRepresentation。
class TaskRepresentation {
private String id;
private String name;
private String processInstanceId;
// standard constructors
}<p>處理方法將如下所示:</p>
@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());
}
在這裏,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. 完成任務 Task
現在,我們將查看在完成任務 Task A 時會發生什麼。我們創建一個處理方法,用於處理為給定的 processInstance 完成任務 Task 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() 創建了一個對任務服務的查詢,並返回指定 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());
}以下是如何使用 Activiti 服務與流程協作的方式。
4. 結論
本文介紹了使用 Activiti API 與 Spring Boot 的概述。有關 API 的更多信息,請參閲 用户手冊。我們還看到了如何使用 Activiti 服務創建流程並執行各種操作。
Spring Boot 使其易於使用,因為我們無需擔心創建數據庫、部署流程或創建 ProcessEngine。