Быстрый старт#

В данном разделе описан пример создания одного из сценариев переходов между состояниями процесса — flow регистрации пользователя.

Данный flow имеет два экрана:

  • ввод логина и пароля;

  • ввод ФИО.

  1. Создайте в ресурсах проекта файл flow/createUser.xml с описанием flow.

<flow xmlns="http://ufs.<домен>/platform/flow-definition"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://ufs.<домен>/platform/flow-definition http://ufs.<домен>/platform/flow-definition.xsd"
      start-state="loginForm">

    <!--Форма 1: Ввод логина и пароля.
    Доступные события: сохранение логина
    Доступные переходы: переход на Форму 2
    -->
    <state name="loginForm">
        <event name="saveLogin" handler="createUserHandler#saveLogin"/>
        <state-transition name="success" to="usernameForm"/>
    </state>

    <!--Форма 2: Ввод ФИО.
    Доступные события: сохранение ФИО
    Доступные переходы: переход к системному state — end
    -->
    <state name="usernameForm">
        <event name="saveUsername" handler="createUserHandler#saveUsername"/>
        <state-transition name="success" to="end"/>
    </state>

</flow>

Обработкой событий занимается специальный bean-обработчик:

public class CreateUserHandler {

        @Autowired
        @Qualifier("workflowExecutor")
        //получаем контекст события
        private EventContext context;

        public Transition saveLogin() {
            final LoginFormDTO loginFormDTO = context.parseInputToJson(LoginFormDTO.class);

            final String login = loginFormDTO.getLogin();
            final String password = loginFormDTO.getPassword();

            //some business logic

            return Transition.go("success");
        }

        public Transition saveUsername() {
            final UsernameFormDTO user = context.parseInputToJson(UsernameFormDTO.class);

            final String name = user.getName();
            final String surname = user.getSurname();

            //some business logic

            return Transition.go("success");
        }
    }

Пояснения к обработчику:

  • Обработчик занимается обработкой событий во flow.

  • Всю исходную информацию обработчик получает через EventContext. Наименование bean EventContext совпадает с наименованием spring-executor.

  • Обработчик собирает всю необходимую информацию с EventContext, и далее обращается к специальным сервисам для непосредственного исполнения бизнес-логики.

  • Методы, обрабатывающие события, не должны иметь аргументы. Возврат метода — объект типа Transition (переход).

  • Transition идентифицируется именем. Во flow XML-файле расписано, что означает каждый transition (например переход к следующем шагу flow, либо переход в subflow).

  1. Сконфигурируйте Workflow machine в Spring-контексте приложения.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:workflow="http://ufs.<домен>/platform/workflow"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://ufs.<домен>/platform/workflow
       http://ufs.<домен>/platform/workflow/workflow-module.xsd">

    <!--Java Workflow Machine-->
    <workflow:workflow-machine id="workflowMachine"
                               configuration="workflowConfiguration"
                               dataStorage="workflowDataStorage"
                               metaStorage="workflowMetaStorage"
                               handlerExecutor="workflowExecutor"/>

    <workflow:spring-executor id="workflowExecutor"/>


    <workflow:data-storage id="workflowDataStorage" configuration="workflowConfiguration"/>

    <workflow:local-meta-storage id="workflowMetaStorage" configuration="workflowConfiguration">
        <workflow:flow name="createUser" path="flow/createUser.xml"/>
    </workflow:local-meta-storage>

    <!--HTTP-->
    <workflow:workflow-gate machine="workflowMachine" urlRegistry="workflowUrlRegistry" errorResolver="workFlowErrorResolver"
        configuration="workflowConfiguration" monitoringHandler="monitoringHandler"/>
    <workflow:config-url-registry id="workflowUrlRegistry" configProvider="configProvider"/>

    <workflow:error-resolver id="workFlowErrorResolver" errorService="errorService" defaultErrorCode="EXAMPLEERROR" configuration="workflowConfiguration"/>

    <!--Handlers-->
    <bean id="createUserHandler" class="<домен>.platform.example.workflow.CreateUserHandler"/>
    <!-- Bean конфигурации Workflow -->
    <workflow:configuration id="workflowConfiguration">
        <workflow:default configService="localConfigService" environment="UfsPlatformEnvironmentContext" monitoringService="coreMonitoringService"/>
    </workflow:configuration>
    <!-- Пример переопределения конфигурации Workflow -->
    <!-- Кастомная реализация интерфейса <домен>.ufs.platform.WorkflowConfiguration -->
    <!--
    <bean id="customWorkflowConfiguration" class="<домен>.ufs.myproject.CustomWorkflowConfiguration"/>

    <workflow:configuration id="workflowConfiguration">
     <workflow:custom id="customWorkflowConfiguration"/>
    </workflow:configuration>
    -->

</beans>

В примере выше использованы следующие объекты конфигурации Workflow:

  • workflow-machine — центральный Java API модуля;

    • workflow-machine:id — идентификатор Workflow Machine;

    • workflow-machine:dataStorage — ссылка на хранилище данных процессов Workflow;

    • workflow-machine:metaStorage — ссылка на хранилище метаданных с описаниями flow;

    • workflow-machine:handlerExecutor — ссылка на глобальный обработчик событий.

  • spring-executor — глобальный обработчик событий. Занимается обработкой выражений типа createUserHandler#saveLogin. Конкретно данная реализация делегирует обработку событий соответствующим bean-обработчикам (bean createUserHandler, метод saveLogin);

    • spring-executor:id — идентификатор.

  • data-storage — хранилище данных flow. Использование кеша или сервис удаленного хранения данных определятся в конфигурации элемента \<core:environment\> \<core:session\>;

    • data-storage:id — идентификатор;

    • data-storage:configuration — ссылка на bean конфигурации Workflow.

  • local-meta-storage — хранилище метаданных flow. Данная реализация достает информацию о flow из локальных xml-ресурсов проекта;

    • local-meta-storage:id — идентификатор;

    • local-meta-storage:validate — включает валидацию external-flow (по умолчанию включена);

    • local-meta-storage:flow — регистрация xml со flow (минимум 1, максимум — не ограничено);

    • local-meta-storage:flow:name — наименование flow;

    • local-meta-storage:flow:path — classpath ссылка на flow xml;

    • local-meta-storage:external-flow — регистрация допустимых внешних flow (минимум 0, максимум — не ограничено);

    • local-meta-storage:external-flow:name — наименование внешнего flow.

  • workflow-gate — сервлет, адаптирующий API компонента Workflow (UIWF) для для HTTP;

    • workflow-gate:servletUrl — URL, на который происходит mapping сервлета, значение по умолчанию — /workflow-gate;

    • workflow-gate:machine — ссылка на Workflow Machine;

    • workflow-gate:urlRegistry — ссылка на регистр URL;

    • workflow-gate:configuration — ссылка на bean конфигурации Workflow;

    • workflow-gate:errorResolver — ссылка на обработчик ошибок. Аналогичен обработчику, который используется в JAX-RS;

    • workflow-gate:montoringHandler — ссылка на обработчик событий мониторинга.

  • config-url-registry — регистр URL. Используется в случаях распределенной структуры subflow (ситуация когда flow обращается к subflow, который находится в другом приложении). В данном примере никак не используется;

    • config-url-registry:id — идентификатор;

    • config-url-registry:configProvider — провайдер конфигурации, предоставляющий информацию об URL. Имплементация интерфейса <домен>.ufs.platform.workflow.provider.ConfigProvider, по умолчанию используется <домен>.ufs.platform.workflow.provider.PlatformConfigProvider.

Примеры конфигурации в Spring Boot смотрите в разделе «Подключение и конфигурация».

Работать с flow можно также по HTTP API. Для этого выполните действия, описанные ниже по тексту.

  1. Запустите flow следующим POST-запросом.

/workflow-gate?cmd=START&name=createUser

В результате будет получен ответ:

{
  "success": true,
  "body": {
    "result": "SUCCESS",
    "pid": "0732c18a-571e-4ebc-9519-5b9f445c12bf",
    "flow": "createUser",
    "state": "loginForm",
    "history": [
      {
        "id": "a1c39e0b-2c22-4637-ad02-03bd5d4d6be5",
        "flow": "createUser",
        "state": "loginForm",
        "title": "",
        "status": "ACTIVE"
      }
    ]
  }
}

Примечания к ответу:

  • ответ Workflow находится в поле body. Все остальное — это часть универсального ответа BaseResponse;

  • result — статус ответа;

  • pid — уникальный идентификатор процесса. При старте какого-либо flow, компонент создает процесс в рамках которого происходит работа flow. Если в ходе работы flow будут вызываться subflow, они будут существовать тоже в рамках этого процесса. Процесс «умрет» в тот момент, когда завершится первоначальный «главный» flow, для которого был запущен процесс. Идентификатор передается при каждом последующем запросе к Workflow после старта процесса;

  • state — наименование шага flow, на котором пользователь находится в данный момент;

  • history — блок, в котором хранится история flow.

  1. На шаге loginForm введите логин и пароль пользователя. Произойдет вызов события saveLogin.

/workflow-gate?cmd=EVENT&name=saveLogin%pid=0732c18a-571e-4ebc-9519-5b9f445c12bf

Тело запроса:

{
  "login" : "oleg",
  "password" : "some"
}

Тело ответа:

{
  "success": true,
  "body": {
    "result": "SUCCESS",
    "pid": "0732c18a-571e-4ebc-9519-5b9f445c12bf",
    "flow": "createUser",
    "state": "usernameForm",
    "history": [
      {
        "id": "065efc1a-701d-4f43-814b-c439c7ed4abc",
        "flow": "createUser",
        "state": "usernameForm",
        "title": "",
        "status": "ACTIVE"
      }
    ]
  }
}
  1. На шаге usernameForm введите ФИО.

Произойдет вызов события saveUsername:

/workflow-gate?cmd=EVENT&name=saveUsername%pid=0732c18a-571e-4ebc-9519-5b9f445c12bf

Тело запроса:

{
  "name" : "Олег",
  "surname" : "Переход"
}

Тело ответа:

{
  "success": true,
  "body": {
    "result": "END",
    "pid":"a1f11b0a-49c1-4ea6-bfcc-fe4c81dc7e2d",
    "output":"endData"
  }
}

Данный шаг является завершением процесса flow.

Для работы с HTTP API существует набор специализированных UI-компонентов.