Введение в Activiti с весны

Введение в 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 будет искать эту папку для развертывания определения процесса.

Мы создадим демонстрационный процесс, содержащий одну пользовательскую задачу:

image

Ответственный за пользовательское задание устанавливается как инициатор процесса. Файл 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.