SpringでのActivitiの概要
1. 概要
簡単に言えば、Activiti is a workflow and Business Process Management platform.
ProcessEngineConfiguration(通常は構成ファイルに基づく)を作成することで、すぐに始めることができます。 これから、ProcessEngineを取得できます。ProcessEngine,を介して、ワークフローとBPM操作を実行できます。
APIは、プロセスへのアクセスと管理に使用できるさまざまなサービスを提供します。 これらのサービスは、プロセスの履歴、現在実行されているもの、およびデプロイされているがまだ実行されていないプロセスに関する情報を提供します。
サービスを使用して、プロセス構造を定義し、プロセスの状態を操作することもできます。 実行、一時停止、キャンセルなど
APIを初めて使用する場合は、Introduction to Activiti API with Javaを確認してください。 この記事では、SpringBootアプリケーション内でActivitiAPIを設定する方法について説明します。
2. SpringBootを使用したセットアップ
ActivitiをSpringBootMavenアプリケーションとしてセットアップして使用を開始する方法を見てみましょう。
2.1. 初期設定
いつものように、maven依存関係を追加する必要があります。
org.activiti
activiti-spring-boot-starter-basic
APIの最新の安定バージョンはhereにあります。 v1.5.4までのSpring Bootで動作します。 v2.0.0.M1ではまだ機能しません。
https://start.spring.ioを使用してSpring Bootプロジェクトを生成し、依存関係としてActivitiを選択することもできます。
この依存関係と@EnableAutoConfigurationアノテーションをSpring Bootアプリケーションに追加するだけで、初期設定が行われます。
-
データソースの作成(APIには、ProcessEngineを作成するためのデータベースが必要です)
-
ProcessEngineBeanを作成して公開する
-
ActivitiサービスBeanを作成して公開する
-
Spring Job Executorを作成する
2.2. プロセスの作成と実行
ビジネスプロセスを作成して実行する例を作成しましょう。
プロセスを定義するには、BPMNファイルを作成する必要があります。 このために、https://activiti.alfresco.com/activiti-app/editorを使用してプロセス定義を作成できます。
次に、BPMNファイルをダウンロードします。 このファイルをsrc/main/resources/processesフォルダーに配置する必要があります。 デフォルトでは、Spring Bootはこのフォルダーを参照してプロセス定義をデプロイします。
1つのユーザータスクを含むデモプロセスを作成します。
ユーザータスクの担当者がプロセスの開始者として設定されます。 このプロセス定義のBPMNファイルは次のようになります。
次に、このプロセスを開始するリクエストを処理する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のTasksのリストを取得します
2つのユーザータスクAとBがあります。 プロセスを開始すると、最初のタスクAが完了するのを待ってから、タスクBを実行します。 特定のprocessInstanceに関連するタスクを表示するリクエストを受け入れるハンドラーメソッドを作成しましょう。
Taskのようなオブジェクトは、応答として直接送信できないため、カスタムオブジェクトを作成し、Taskをカスタムオブジェクトに変換する必要があります。 このクラスをTaskRepresentationと呼びます。
class TaskRepresentation {
private String id;
private String name;
private String processInstanceId;
// standard constructors
}
ハンドラーメソッドは次のようになります。
@GetMapping("/get-tasks/{processInstanceId}")
public List getTasks(
@PathVariable String processInstanceId) {
List 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 tasks = Arrays.asList(mapper
.readValue(responseBody, TaskRepresentation[].class));
assertEquals(1, tasks.size());
assertEquals("A", tasks.get(0).getName());
}
3.2. Taskを完了する
ここで、タスク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()はタスクサービス上でクエリを作成し、与えられた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 list = runtimeService.createProcessInstanceQuery().list();
assertEquals(0, list.size());
}
これが、Activitiサービスがプロセスで動作する方法です。
4. 結論
この記事では、Spring Boot.でのActiviti APIの使用の概要について説明しました。APIの詳細については、user guideを参照してください。 また、Activitiサービスを使用してプロセスを作成し、その上でさまざまな操作を実行する方法も確認しました。
Spring Bootを使用すると、データベースの作成、プロセスのデプロイ、ProcessEngineの作成について心配する必要がないため、簡単に使用できます。
ActivitiとSpring Bootの統合はまだ実験段階であり、Spring Boot 2ではまだサポートされていないことに注意してください。
いつものように、私たちが見たすべての例の実装はover on GitHubで見つけることができます。