1. Обзор
Проще говоря, Activiti — это платформа управления рабочими процессами и бизнес-процессами.
Мы можем быстро приступить к работе, создав ProcessEngineConfiguration
(обычно на основе файла конфигурации). Отсюда мы можем получить ProcessEngine
, а через ProcessEngine
мы можем выполнять рабочие процессы и операции BPM.
API предоставляет различные службы, которые можно использовать для доступа к процессам и управления ими. Эти сервисы могут предоставить нам информацию об истории процессов, о том, что запущено в данный момент, и о процессах, которые развернуты, но еще не запущены.
Службы также можно использовать для определения структуры процесса и управления состоянием процесса, т. е. запуска, приостановки, отмены и т. д.
Если вы не знакомы с API, ознакомьтесь с нашим Введением в API Activiti с Java . В этой статье мы обсудим, как настроить Activiti API в приложении Spring Boot.
2. Настройка с помощью Spring Boot
Давайте посмотрим, как мы можем настроить Activiti как приложение Spring Boot Maven и начать его использовать.
2.1. Начальная настройка
Как обычно, нам нужно добавить зависимость maven:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
</dependency>
Последнюю стабильную версию API можно найти здесь . Он работает с Spring Boot до версии 1.5.4. С v2.0.0.M1 пока не работает.
Мы также можем создать проект Spring Boot, используя https://start.spring.io , и выбрать Activiti в качестве зависимости.
Просто добавив эту зависимость и аннотацию @EnableAutoConfiguration
в приложение Spring Boot, оно выполнит первоначальную настройку:
- Создать источник данных (для API требуется база данных для создания
ProcessEngine
) - Создание и предоставление bean -компонента
ProcessEngine
- Создание и предоставление компонентов служб Activiti
- Создайте исполнителя заданий Spring
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. Игра с процессами
Теперь, когда у нас есть запущенный процесс в Activiti с использованием Spring Boot, давайте расширим приведенный выше пример, чтобы продемонстрировать, как мы можем получить доступ к процессу и управлять им.
3.1. Получить список задач
для данного ProcessInstance
У нас есть две пользовательские задачи 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<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. Завершение задачи
Теперь посмотрим, что произойдет, когда мы выполним задачу А.
Мы создаем метод-обработчик, который будет обрабатывать запросы на выполнение задачи A
для данного processInstance
:
@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
.
Имейте в виду, что интеграция Activiti с Spring Boot все еще находится на экспериментальной стадии и еще не поддерживается Spring Boot 2.
Как всегда, реализацию всех увиденных нами примеров можно найти на GitHub .