Jmix View
Любой экран Jmix может служить процессной формой. Это позволяет создавать более сложные взаимодействия с пользователем по сравнению с Input Dialog.
Создание процессной формы
Процессная форма Jmix — это обычный экран приложения, который включает аннотации для передачи деталей, относящихся к процессу.
Преобразование существующего экрана
Чтобы преобразовать обычный экран в процессную форму:
-
Добавьте аннотацию @ProcessForm в контроллер класса. Объявите результаты, параметры и выходные переменные по мере необходимости.
-
Инжектируйте и свяжите переменные процесса с помощью аннотации @ProcessVariable.
-
Обработайте нажатия кнопок для завершения задачи при помощи ProcessFormContext.
| Избегайте преобразования экранов, которые уже используются. Лучше создать новый экран, который будет служить процессной формой. |
Использование Jmix Studio
Чтобы создать процессную форму с помощью Jmix Studio:
-
Нажмите New → View, чтобы открыть Мастер создания экранов.
-
Выберите шаблон BPM Process form.

-
Настройте шаблон формы и элемент, для которого он предназначен:
-
Выберите Form template из двух вариантов:
-
Process Form with Process Variables: эта форма отобразит компоненты для набора выбранных вами переменных.
-
Process Form for Entity Instance: эта форма отобразит компоненты для атрибутов конкретного экземпляра сущности вместе с любыми добавленными переменными процесса.
-
-
Выберите Form type:
-
User task form: эта форма предназначена для пользовательских задач.
-
Start form: эта форма предназначена для элементов стартового события.

-
-
-
В случае Process form for entity instance, укажите класс сущности, имя переменной и настройте фетч план.
-
Укажите переменные процесса.
-
В случае User task form укажите результаты формы. Значения по умолчанию —
submitиreject. Измените их или добавьте новые. -
Добавьте локализуемые сообщения.
-
Нажмите Create.
Форма появится среди других экранов в вашем приложении.
Настройка элемента с процессной формой
После создания процессной формы вы можете настроить элемент для её использования. Следуйте шагам:
-
Откройте Modeler.
-
Выберите соответствующий элемент (Пользовательская задача или Стартовое событие).

-
Установите Form type в
Jmix view. -
Установите Open mode:
-
Dialog: чтобы отображать форму в диалоге.
-
Navigate: чтобы отображать форму как экран с собственным URL.
-
-
Укажите View id. Список опций будет включать все экраны приложения, аннотированные
@ProcessForm. Модельер распознает процессную форму и заполнит оставшиеся настройки на основе её аннотаций. -
При наличии параметров формы, настройте их с соответствующим источником значений.
Процессная форма теперь настроена для использования в выбранном элементе.
@ProcessForm
Добавление @ProcessForm в класс контроллера экрана преобразует экран в процессную форму и делает её доступной для выбора в Modeler. Эта аннотация может включать следующие атрибуты:
-
Чтобы ограничить использование формы для определённых процессов, укажите ключи процессов в атрибуте
allowedProcessKeys:@ProcessForm(allowedProcessKeys = {"process-1", "process-2"}) -
Чтобы объявить результаты формы, используйте
outcomes:@ProcessForm( outcomes = { (1) @Outcome(id = "approve"), @Outcome(id = "reject") } ) -
Чтобы указать выходные переменные, используйте атрибут
outputVariables:@ProcessForm( outputVariables = { @OutputVariable(name = "order", type = Order.class), @OutputVariable(name = "comment", type = String.class) } ) -
Чтобы установить переменную процесса только при завершении задачи с конкретным результатом, комбинируйте атрибуты
outcomesиoutputVariablesследующим образом:@ProcessForm( outcomes = { @Outcome( id = "approve", outputVariables = { @OutputVariable(name = "nextActor", type = User.class) (1) } ), @Outcome( id = "reject", outputVariables = { @OutputVariable(name = "rejectionReason", type = String.class) (2) } ) }, outputVariables = { @OutputVariable(name = "comment", type = String.class) (3) } )1 Переменная nextActorустанавливается, когда задача завершается с результатомapprove.2 Переменная rejectionReasonустанавливается, когда задача завершается с результатомreject.3 Переменная commentустанавливается во всех случаях. -
Чтобы объявить параметры форму используйте атрибут
params. Затем установите@ProcessFormParamна полях класса, чтобы связать их с этими параметрами.@ProcessForm( params = { @Param(name = "nextActor"), @Param(name = "entityPickerCaption") } ) //... @ProcessFormParam private String nextActor; @ProcessFormParam private String entityPickerCaption;Для @ProcessFormParamможет быть указан атрибутname. Если имя не указано явно, используется имя по умолчанию, основанное на названии поля.
@ProcessVariable
@ProcessVariable может быть установлен на полях класса и компонентах экрана. Он указывает, что значение переменной процесса будет установлено в это поле, когда открывается процессная форма. В случае компонента экрана значение переменной будет установлено в этом компоненте.
@ProcessVariable
private Date date;
@ViewComponent
@ProcessVariable(name = "order")
private EntityPicker<Order> orderEntityPicker;
Если name не указано явно, имя переменной процесса по умолчанию берётся из названия поля.
ProcessFormContext
Объект ProcessFormContext содержит информацию об определении процесса, который запускается, или о пользовательской задаче, которую необходимо завершить. Используйте ProcessFormContext, когда процессная форма открывается из Start Process или My Tasks. Чтобы программно открыть процессную форму с инжектированным ProcessFormContext используйте бин ProcessFormViews.
Рассмотрите пример запуска процесса:
@ProcessVariable
private Date date;
@ViewComponent
@ProcessVariable(name = "order")
private EntityPicker<Order> orderEntityPicker;
@Autowired
private ProcessFormContext processFormContext;
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(ClickEvent<JmixButton> event) {
processFormContext.processStarting() (1)
.withBusinessKey("order-1") (2)
.addProcessVariable("date", date)
.addProcessVariable("order", orderEntityPicker.getValue()) (3)
.start(); (4)
closeWithDefaultAction(); (5)
}
| 1 | Создание экземпляра ProcessStarting. |
| 2 | Добавление бизнес-ключа для экземпляра процесса. |
| 3 | Добавление переменной процесса. |
| 4 | Запуск процесса. |
| 5 | Закрытие текущего окна. |
Рассмотрите следующий пример завершения пользовательской задачи:
@Autowired
private ProcessFormContext processFormContext;
@Subscribe("rejectBtn")
protected void onRejectBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion() (1)
.withOutcome("reject") (2)
.saveInjectedProcessVariables() (3)
.complete(); (4)
closeWithDefaultAction(); (5)
}
| 1 | Создание экземпляра TaskCompletion. |
| 2 | Выбор исхода для задачи. |
| 3 | Указывает, что значения полей класса, аннотированных @ProcessVariable, должны быть собраны и сохранены в качестве переменных процесса. |
| 4 | Завершение задачи. |
| 5 | Закрытие текущего окна. |
Примеры
Процессная Форма Запуска
Рассмотрим пример процессной формы, которая используется в качестве стартовой. Она содержит два поля:
-
Поле для ввода номера заказа.
-
Поле с элементом
entityPickerдля выбора менеджера. Менеджер может быть следующим актором процесса.
XML дескриптор:
<view xmlns="http://jmix.io/schema/flowui/view"
title="msg://com.company.bpmex1.view.forms/startProcessForm.title">
<layout>
<formLayout>
<textField id="orderNumber"
label="msg://com.company.bpmex1.view.forms/orderNumber"
datatype="string"/>
<entityPicker id="managerEntityPicker"
metaClass="User"
label="msg://managerEntityPicker.caption">
<actions>
<action id="lookup" type="entity_lookup"/>
<action id="clear" type="entity_clear"/>
</actions>
</entityPicker>
</formLayout>
<hbox id="actionsPanel" spacing="true">
<button id="startProcessBtn"
icon="CHECK"
text="msg://com.company.bpmex1.view.forms/startProcessBtn.text"/>
</hbox>
</layout>
</view>
Контроллер экрана:
@ViewController("OrderApprovalStartForm")
@ViewDescriptor("order-approval-start-form.xml")
@ProcessForm (1)
public class OrderApprovalStartForm extends StandardView {
@ViewComponent
@ProcessVariable (2)
private TypedTextField<String> orderNumber;
@ViewComponent
@ProcessVariable(name = "manager") (3)
private EntityPicker<User> managerEntityPicker;
@Autowired
private ProcessFormContext processFormContext; (4)
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(ClickEvent<JmixButton> event) {
processFormContext.processStarting()
.withBusinessKey(orderNumber.getValue()) (5)
.saveInjectedProcessVariables() (6)
.start();
closeWithDefaultAction();
}
}
| 1 | Аннотация @ProcessForm указывает, что этот экран является процессной формой и будет доступен в моделере. |
| 2 | Аннотация @ProcessVariable указывает, что компонент orderNumber соответствует процессной переменной orderNumber. Поскольку форма является стартовой, переменная еще не задана, но аннотация будет использоваться при запуске процесса. |
| 3 | Аннотация @ProcessVariable указывает, что компонент managerEntityPicker соответствует процессной переменной manager. Имя процессной переменной manager указано явно, так как оно отличается от имени компонента. |
| 4 | ProcessFormContext это объект для запуска процесса. |
| 5 | При запуске процесса можно передать бизнес-ключ для экземпляра. В данном случае используется orderNumber. |
| 6 | Метод saveInjectedProcessVariables() указывает, что значения полей, аннотированных @ProcessVariable, должны быть сохранены в качестве переменных процесса при запуске процесса. |
Вместо использования метода saveInjectedProcessVariables() можно задать переменные процесса явно:
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(ClickEvent<JmixButton> event) {
processFormContext.processStarting()
.withBusinessKey(orderNumber.getValue())
.addProcessVariable("orderNumber", orderNumber.getValue())
.addProcessVariable("manager",managerEntityPicker.getValue())
.start();
closeWithDefaultAction();
}
Процессная форма задачи
Рассмотрим пример процессной формы задачи с двумя полями:
-
Первое поле соответствует существующей переменной процесса –
orderNumber. -
Второе поле будет использоваться для новой переменной процесса -
comment.
Кнопки Approve и Reject завершают пользовательскую задачу с соответствующим исходом.
XML-дескриптор экрана:
<view xmlns="http://jmix.io/schema/flowui/view"
title="msg://orderApprovalTaskForm.title">
<layout>
<formLayout>
<textField id="orderNumber" readOnly="true"
label="msg://orderNumber"/>
<textField id="commentField" label="msg://comment"/>
</formLayout>
<hbox id="actionsPanel" spacing="true">
<button id="approveBtn" icon="CHECK" text="msg://approveBtn.text"/>
<button id="rejectBtn" icon="BAN" text="msg://rejectBtn.text"/>
</hbox>
</layout>
</view>
Контроллер экрана:
@ViewController("OrderApprovalTaskForm")
@ViewDescriptor("order-approval-task-form.xml")
@ProcessForm(
outcomes = { (1)
@Outcome(id = "approve"),
@Outcome(id = "reject")
}
)
public class OrderApprovalTaskForm extends StandardView {
@ViewComponent
@ProcessVariable (2)
private TypedTextField<String> orderNumber;
@ViewComponent
@ProcessVariable(name = "comment") (3)
private TypedTextField<String> commentField;
@Autowired
private ProcessFormContext processFormContext;
@Subscribe("approveBtn")
protected void onApproveBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion()
.withOutcome("approve")
.saveInjectedProcessVariables() (4)
.complete();
closeWithDefaultAction();
}
@Subscribe("rejectBtn")
protected void onRejectBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion()
.withOutcome("reject")
.addProcessVariable("comment", commentField.getValue()) (5)
.complete();
closeWithDefaultAction();
}
}
| 1 | Форма определяет два возможных исхода. |
| 2 | Переменная orderNumber уже установлена при запуске процесса. Благодаря аннотации @ProcessVariable значение переменной процесса orderNumber будет отображено в текстовом поле orderNumber при появлении формы. |
| 3 | Переменная comment еще не установлена, но аннотация @ProcessVariable будет учтена при завершении задачи в слушателе нажатия кнопки. |
| 4 | Значения всех полей с аннотацией @ProcessVariable будут сохранены как переменные процесса по завершении задачи. |
| 5 | Вместо того, что бы использовать метод saveInjectedProcessVariables(), вы можете определить переменные процесса напрямую. |
Opening Forms Programmatically
Используйте сервис ProcessFormViews, чтобы открывать формы запуска процессов и формы задач, определённые в модельере.
В приведённом ниже примере кнопка в списковом представлении открывает форму запуска процесса.
@Autowired
private RepositoryService repositoryService;
@Autowired
protected ProcessFormViews processFormViews;
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(final ClickEvent<JmixButton> event) {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() (1)
.processDefinitionKey("order-process")
.latestVersion()
.singleResult();
processFormViews.openStartProcessForm(processDefinition, this); (2)
}
| 1 | Получите определение процесса по ключу. |
| 2 | Отобразите форму запуска процесса с предоставленным определением. |
Чтобы открыть форму задачи, используйте метод openTaskProcessForm():
@Autowired
private TaskService taskService;
@Autowired
private ProcessFormViews processFormViews;
@Subscribe("openTaskBtn")
public void onOpenTaskBtnClick(ClickEvent<JmixButton> event) {
Task task = taskService.createTaskQuery()
.processDefinitionKey("approve-order-process")
.taskAssignee("admin")
.active()
.orderByTaskCreateTime()
.list()
.get(0);
processFormViews.openTaskProcessForm(task, this);
}
Процессная форма с параметрами
Процессные формы могут принимать внешние параметры для настройки своего поведения или внешнего вида, например, изменения заголовков компонентов. В отличие от переменных процесса, эти параметры формы имеют более узкую область применения и доступны только в конкретной форме (если только вы не сохраняете их значение в переменной процесса).
Параметры формы объявляются с помощью аннотации @ProcessForm и её атрибута params. Они связаны с полем класса с помощью аннотации @ProcessFormParam.
|
Чтобы проиллюстрировать, рассмотрим сценарий, когда вам нужна форма для выбора следующего актёра процесса. Эта форма должна включать компонент EntityPicker для выбора пользователя, который затем будет сохранен в переменной процесса. Также эту форму можно будет повторно использовать на различных этапах процесса, поэтому было бы удобно параметризировать заголовок для выбора сущности.
В общей сложности определим два параметра:
-
nextActor– для сохранения пользователя выбранного черезEntityPickerдля дальнейшего использования в процессе. -
entityPickerCaption– для настройки заголовка компонентаEntityPickerв зависимости от этапа процесса.
XML-дескриптор экрана:
<view xmlns="http://jmix.io/schema/flowui/view"
title="msg://com.company.bpmex1.view.forms/actorSelectionForm.title">
<layout spacing="true">
<formLayout width="20em">
<entityPicker id="userEntityPicker"
metaClass="User"
property="username">
<actions>
<action id="lookup" type="entity_lookup"/>
<action id="clear" type="entity_clear"/>
</actions>
</entityPicker>
</formLayout>
<hbox spacing="true">
<button id="completeTaskBtn" icon="CHECK" text="msg://completeTask"/>
</hbox>
</layout>
</view>
Контроллер экрана:
@ProcessForm(
params = {
@Param(name = "nextActor"),
@Param(name = "entityPickerCaption")
}
)
public class ActorSelectionForm extends StandardView {
@Autowired
private ProcessFormContext processFormContext;
@ViewComponent
private EntityPicker<String> userEntityPicker;
//...
@ProcessFormParam
private String nextActor;
@ProcessFormParam
private String entityPickerCaption;
@Subscribe
private void onBeforeShow(BeforeShowEvent event) {
userEntityPicker.setLabel(entityPickerCaption);
}
@Subscribe("completeTaskBtn")
private void onCompleteTaskBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion()
.addProcessVariable(nextActor, userEntityPicker.getValue())
.complete();
closeWithDefaultAction();
}
}
|
Чтобы получить полный список параметров формы процесса, используйте объект
|