Введение в Activiti с весны
1. обзор
Проще говоря,Activiti is a workflow and Business Process Management platform.
Мы можем быстро начать работу, создавProcessEngineConfiguration (обычно на основе файла конфигурации). Отсюда мы можем получитьProcessEngine - и черезProcessEngine, мы можем выполнять операции рабочего процесса и BPM.
API предоставляет различные сервисы, которые можно использовать для доступа и управления процессами. Эти службы могут предоставить нам информацию об истории процессов, о том, что выполняется в данный момент, а также о процессах, которые развернуты, но еще не запущены.
Сервисы также могут использоваться для определения структуры процесса и манипулирования состоянием процесса, т.е. запустить, приостановить, отменить и т. д.
Если вы новичок в API, ознакомьтесь с нашимIntroduction to Activiti API with Java. В этой статье мы обсудим, как настроить Activiti API в приложении Spring Boot.
2. Настройка с помощью Spring Boot
Давайте посмотрим, как мы можем настроить Activiti как приложение Spring Boot Maven и начать его использовать.
2.1. Начальная настройка
Как обычно, нам нужно добавить зависимость maven:
org.activiti
activiti-spring-boot-starter-basic
Последнюю стабильную версию API можно найти наhere. Работает с Spring Boot до v1.5.4. Он пока не работает с v2.0.0.M1.
Мы также можем сгенерировать проект Spring Boot, используяhttps://start.spring.io, и выбрать Activiti в качестве зависимости.
Просто добавив эту зависимость и аннотацию@EnableAutoConfiguration в приложение Spring Boot Application, оно выполнит начальную настройку:
-
Создать источник данных (API требует базы данных для созданияProcessEngine)
-
Создайте и откройте bean-компонентProcessEngine
-
Создайте и выставьте бины сервисов Activiti
-
Создать Spring Job Executor
2.2. Создание и запуск процесса
Построим пример создания и выполнения бизнес-процесса.
Чтобы определить процесс, нам нужно создать файл BPMN. Для этого мы можем использоватьhttps://activiti.alfresco.com/activiti-app/editor для создания определения процесса.
Затем просто загрузите файл BPMN. Нам нужно будет поместить этот файл в папкуsrc/main/resources/processes. По умолчанию Spring Boot будет искать эту папку для развертывания определения процесса.
Мы создадим демонстрационный процесс, содержащий одну пользовательскую задачу:
Ответственный за пользовательское задание устанавливается как инициатор процесса. Файл 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. Игра с процессами
Теперь, когда у нас есть запущенный процесс в Activiti с использованием Spring Boot, давайте расширим приведенный выше пример, чтобы продемонстрировать, как мы можем получить доступ к процессу и управлять им.
3.1. Получить списокTasks для данного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 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. Мы создаем метод-обработчик, который будет обрабатывать запросы на выполнение задачи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 list = runtimeService.createProcessInstanceQuery().list();
assertEquals(0, list.size());
}
Вот так мы можем использовать сервисы Activiti для работы с процессами.
4. Заключение
В этой статье мы рассмотрели использование Activiti API с Spring Boot.. Более подробную информацию об API можно найти вuser guide. Мы также увидели, как создать процесс и выполнить над ним различные операции с помощью сервисов Activiti.
Spring Boot упрощает использование, поскольку нам не нужно беспокоиться о создании базы данных, развертывании процессов или созданииProcessEngine.
Помните, что интеграция Activiti с Spring Boot все еще находится на экспериментальной стадии и еще не поддерживается Spring Boot 2.
Как всегда, реализация всех рассмотренных нами примеров находится вover on GitHub.