Быстрый старт#
В данном разделе описан пример создания одного из сценариев переходов между состояниями процесса — flow регистрации пользователя.
Данный flow имеет два экрана:
ввод логина и пароля;
ввод ФИО.
Создайте в ресурсах проекта файл
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).
Сконфигурируйте 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. Для этого выполните действия, описанные ниже по тексту.
Запустите 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.
На шаге 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"
}
]
}
}
На шаге 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-компонентов.