В этой статье я расскажу о ключевых обновлениях, представленных в недавно вышедшем релизе Jmix 2.1.
Полная информация об изменениях доступна на странице документации Что нового.
Новые дополнения
Мы реализовали ряд дополнений, которые ранее были доступны в Jmix v.1 с Classic UI. Теперь вы можете легко включить ту же готовую к использованию функциональность в ваш проект с современным Flow UI на основе Vaadin 24.
Maps
Дополнение Maps было переписано с нуля. Оно предлагает новый API и имеет отличную поддержку в Studio.
Вот пример, демонстрирующий отображение OpenStreetMap с маркером в определенной точке:
<maps:geoMap id="map" width="100%" height="100%">
<maps:layers>
<maps:tile>
<maps:osmSource/>
</maps:tile>
<maps:vector id="pointsLayer">
<maps:vectorSource/>
</maps:vector>
</maps:layers>
</maps:geoMap>
@ViewComponent
private GeoMap map;
@Subscribe
public void onInit(InitEvent event) {
VectorLayer vectorLayer = map.getLayer("pointsLayer");
VectorSource vectorSource = vectorLayer.getSource();
vectorSource.addFeature(
new MarkerFeature(GeometryUtils.createPoint(12.496176, 41.902695)));
}
Этот пример относится к категории "hello world" и, разумеется, не охватывает все функции дополнения. На самом деле , карта может содержать слои тайлов, изображений и векторные слои, каждый из которых имеет свои провайдеры данных. Она может отображать маркеры, точки, полилинии и полигоны. Работа над этим дополнением еще не завершена, оно будет доработано в следующем релизе.
Dynamic Attributes
Дополнение Dynamic Attributes позволяет определять новые атрибуты сущностей без изменения схемы базы данных и перезапуска приложения. Дополнительные атрибуты, определенные для сущности, опционально могут быть разделены на несколько категорий.
Например, сущность Book может быть классифицирована по двум категориям: Electronic и Paper. У электронных книг есть атрибуты Available Formats и File Size, в то время как у бумажных книг атрибуты Cover Type, Weight и Dimensions.
Динамические атрибуты можно определять в пользовательском интерфейсе приложения:
После настройки атрибутов пользователи могут просматривать и вводить их в существующих экранах:
Динамические атрибуты автоматически отображаются либо в специальном компоненте dynamicAttributesPanel
(как показано выше), либо в любом существующем formLayout
и dataGrid
.
Notifications
Дополнение Notifications предназначено для отправки пользователям уведомлений в приложении или по электронной почте. Уведомление можно отправить через API или с помощью предоставленного дополнением экрана:
UI приложения должен включать компонент notificationsIndicator
, например в экране main-view.xml
.
<appLayout>
<navigationBar>
<header ...>
...
<ntf:notificationsIndicator classNames="ms-auto me-m"/>
</header>
</navigationBar>
Получатели смогут увидеть количество непрочитанных уведомлений в индикаторе и открыть сообщения в удобном UI:
Search
Дополнение Search обеспечивает интеграцию с Elasticsearch для обеспечения полнотекстового поиска по данным и загруженным файлам вашего приложения. Чтобы использовать дополнение, вам нужно выполнить несколько простых шагов.
Задайте подключение к Elasticsearch:
jmix.search.elasticsearch.url = http://localhost:9200
Создайте аннотированный Java интерфейс, описывающий, что должно быть проиндексировано:
@JmixEntitySearchIndex(entity = Book.class)
public interface BookIndexDef {
@AutoMappedField(includeProperties =
{"title", "author", "publisher", "genre.name"})
void bookMapping();
}
Добавьте компонент searchField
в UI приложения:
<drawerLayout>
<section ...>
<search:searchField/>
На этом всё. Данные сущности Book будут автоматически индексироваться (и переиндексироваться при каждом изменении), и пользователи смогут выполнять полнотекстовые запросы по созданному индексу:
Результаты поиска автоматически фильтруются в соответствии с разрешениями на доступ к данным текущего пользователя, исключая возможность утечки информации.
WebDAV
Дополнение WebDAV обеспечивает доступ к файлам, расположенным в файловом хранилище, по протоколу WebDAV. Это позволяет пользователям без проблем открывать и редактировать файлы с помощью их десктопных приложений (Word, Excel, LibreOffice и т. д.) без необходимости скачивать и снова загружать файлы в веб-приложение. На уровне пользовательского интерфейса дополнение предоставляет специальный компонент для загрузки и административный экран для управления файлами и их версиями:
Bulk Editor
Дополнение Bulk Editor позволяет пользователям изменять значения атрибутов сразу для нескольких экземпляров сущностей. Оно предоставляет действие, которое можно добавить в любой dataGrid
:
<dataGrid id="booksDataGrid" ...>
<actions>
...
<action id="bulkEdit" type="bulked_edit"/>
</actions>
Это действие открывает диалоговое окно, в котором пользователь может вводить значения для атрибутов сущности. Заданные атрибуты будут обновлены для всех выбранных экземпляров сущности:
JMX Console
Дополнение JMX Console предоставляет веб-интерфейс к API Java Management Extensions (JMX). Оно позволяет системным администраторам просматривать JMX-бины, редактировать атрибуты и вызывать операции прямо в пользовательском интерфейсе приложения:
Улучшения BPM
В пользовательском интерфейсе приложения теперь доступен DMN table modeler:
Мастер создания процессных форм в Studio теперь может генерировать полностью работоспособные экраны для редактирования переменных процесса и выбора выходов.
Мастер показывает переменные, определенные в процессе:
и позволяет задать выходы:
На основе вашего выбора, мастер генерирует код экрана для инжектирования переменных процесса в UI-компоненты и завершения задачи с выбранным выходом:
@ProcessForm(outcomes = {
@Outcome(id = "submit"),
@Outcome(id = "reject")
})
// ...
public class BpmProcessForm extends StandardView {
@Autowired
private ProcessFormContext processFormContext;
@ProcessVariable
@ViewComponent
private EntityPicker<Book> book;
// ...
@Subscribe("submitBtn")
protected void onSubmitBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion()
.withOutcome("submit")
.saveInjectedProcessVariables()
.complete();
closeWithDefaultAction();
}
Улучшения Data Grid
Этот релиз включает значительные улучшения компонента dataGrid
, который широко используется для представления данных в табличном формате.
Теперь пользователи могут сортировать dataGrid
по нескольким столбцам. Порядок сортировки обозначается числами, отображаемыми рядом со стрелками сортировки:
Сортировка определяется атрибутами multiSort
, multiSortOnShiftClickOnly
и multiSortPriority
компонента dataGrid
.
Еще одна новая функция - агрегация значений в строках. Для настройки агрегации для столбца установите атрибут aggregatable
компонента dataGrid
в true, добавьте элемент aggregation
к столбцу и выберите тип агрегации. Агрегированные значения будут отображаться в отдельной строке:
Следующее улучшение - способность декларативно присваивать рендереры колонкам dataGrid
. Те, кто знаком с Jmix Classic UI, обнаружат, что колонки с декларативными рендерерами очень похожи на "генерируемые колонки" в Classic UI. Вы определяете колонку в XML и создаете метод-обработчик, который возвращает рендерер:
@Supply(to = "stepsDataGrid.completed", subject = "renderer")
private Renderer<UserStep> stepsDataGridCompletedRenderer() {
return new ComponentRenderer<>(userStep -> {
// ...
return checkbox;
});
}
Есть несколько предустановленных рендереров, которые могут быть присвоены колонке в XML для форматирования дат и чисел. Кроме того, теперь колонка может быть определена в XML без привязки к атрибуту сущности, только для того, чтобы объявить для нее рендерер.
И, возможно, самой интересной новой функцией dataGrid
является фильтр в заголовках колонок. Вы можете определить, какие колонки должны иметь фильтр, используя атрибут filterable
элемента XML column
. Колонки со включенной возможностью фильтрации имеют значок "воронки" в своих заголовках. Если пользователь нажимает на этот значок, появляется диалоговое окно с условием фильтрации:
Если условие установлено, значок в этой колонке выделяется:
Концепция фильтра в заголовках колонок знакома пользователям по многим популярным продуктам, включая Excel, поэтому эта функция легко обнаруживается и используется. Мы считаем, что такой подход к фильтрации данных является отличным дополнением к двум другим компонентам, предназначенным для выполнения той же задачи: genericFilter
и propertyFilter
. Компонент genericFilter
настраивается полностью во время выполнения и позволяет создавать сложные условия, но далеко не самый простой в использовании. С другой стороны, propertyFilter
прост и понятен для пользователей, но требует настройки разработчиком заранее. Фильтр в заголовках колонок таблицы похож на propertyFilter
по возможностям, но не занимает пространства на экране и поэтому может быть сконфигурирован по умолчанию для большинства экранов, отображающих таблицы данных.
Важно отметить, что все три функции фильтрации могут быть использованы вместе на одном экране и загрузчике данных без каких-либо конфликтов. Условия всех фильтров будут просто объединены с помощью логического оператора И.
Новые UI-компоненты и фасеты
VirtualList
Новый компонент virtualList
предназначен для отображения списков элементов с произвольным содержимым. Он отображает только ту часть элементов, которая в данный момент видима, что обеспечивает хорошую производительность независимо от сложности контента.
virtualList
может использоваться в экранах вместо dataGrid
. Для этого определите компонент в XML и соедините его с контейнером коллекции данных:
<virtualList id="stepsVirtualList" itemsContainer="stepsDc"/>
Компоненты для фильтрации и пейджинга, такие как genericFilter
и simplePagination
, подключенные к загрузчику данных, будут влиять на содержимое virtualList
так же, как и на содержимое dataGrid
.
Затем вам нужно создать метод-обработчик, который отображает содержимое элемента списка:
@Supply(to = "stepsVirtualList", subject = "renderer")
private Renderer<Step> stepsVirtualListRenderer() {
return new ComponentRenderer<>(step -> {
// ...
return hbox;
});
}
Затратив некоторые усилия на вёрстку элементов virtualList
, можно получить примерно такой экран:
Html
Компонент html
позволяет вставлять в экраны произвольное HTML-содержимое. Содержимое может быть определено вложенным элементом content
, в файле, расположенном в ресурсах проекта, или в пакете сообщений для легкой интернационализации.
Settings
Фасет settings
сохраняет и восстанавливает настройки визуальных компонентов для текущего пользователя. Автоматически сохраняются параметры колонок dataGrid
, состояние opened
компонентов details
и genericFilter
, а также выбранный размер страницы для simplePagination
. Просто добавьте фасет в экран и установите его атрибут auto="true"
, и фасет будет управлять настройками всех поддерживаемых компонентов экрана, у которых заданы идентификаторы.
Фасет settings
также предоставляет возможность добавить обработчики, с помощью которых можно сохранять и восстанавливать любые свойства экрана и его компонентов.
Timer
Фасет timer
предназначен для выполнения кода экрана через определенные временные интервалы. Он работает в потоке, обрабатывающем события пользовательского интерфейса и может обновлять компоненты представления. Чтобы использовать фасет, определите его параметры в XML и создайте обработчик для TimerActionEvent
:
<timer id="timer" delay="2000" repeating="true" autostart="true"/>
@Subscribe("timer")
public void onTimerTimerAction(final Timer.TimerActionEvent event) {
// ...
}
Загрузка элементов выпадающих списков
Этот релиз предоставляет новый эффективный способ загрузки данных в компоненты с выпадающими списками, такие как comboBox
, entityComboBox
и multiSelectComboBox
. Теперь вам не нужно определять контейнер коллекции элементов списка и загружать его заранее полным списком вариантов. Вместо этого вы можете определить вложенный элемент itemsQuery
в самом компоненте и написать в нем запрос следующим образом:
<entityComboBox id="departmentField" property="department" pageSize="30">
<itemsQuery class="com.company.onboarding.entity.Department"
fetchPlan="_instance_name"
searchStringFormat="(?i)%${inputString}%">
<query>
<![CDATA[select e from Department e
where e.name like :searchString order by e.name]]>
</query>
</itemsQuery>
</entityComboBox>
Запрос будет выполнен только когда пользователь откроет выпадающий список, и результаты будут ограничены pageSize
строками (по умолчанию 50). Когда пользователь прокручивает список, данные загружаются страницами. Если пользователь вводит текст в поле, он используется для фильтрации результатов.
Вместо написания запроса JPQL в XML, вы можете определить обработчик itemsFetchCallback
и программно загрузить данные из любого источника.
Функция itemsQuery
обеспечивает значительно лучшую производительность для больших наборов данных по сравнению с прежним подходом, основанным на использовании отдельных контейнеров коллекций. В itemsQuery
элементы загружаются малыми порциями, что уменьшает использование памяти, а фильтрация выполняется на уровне хранилища данных. В результате вы можете использовать наборы данных практически любого размера в качестве источников элементов в выпадающих списках.
Очевидно, что для небольших наборов данных использование отдельного предварительно загруженного контейнера с коллекцией по-прежнему является более предпочтительным выбором, поскольку обеспечивает более быстрый отклик пользователю.
Улучшения дизайнера экранов
Теперь давайте обсудим новые функции и улучшения в Студии.
Вероятно, наиболее заметное изменение в Studio заключается в том, что окно инструментов Jmix UI с иерархией и свойствами компонентов теперь отображается в контроллерах экранов, позволяя выполнять различные операции без необходимости открывать XML-дескриптор.
Вы сможете видеть дерево компонентов, изменять свойства компонентов или даже добавлять новые компоненты во время работы с Java-кодом в контроллере.
Еще одно улучшение связано с панелью Preview.
Отображение предварительного просмотра требует сборки фронтенда и запуска Vaadin Development Mode Server, что может занимать много времени. Чтобы сэкономить время при открытии проекта, панель Preview теперь открывается только после нажатия кнопки Start Preview в верхней панели редактора XML. После активации, предварительный просмотр будет оставаться активным для всех последующих открытых экранов проекта. Чтобы отключить предварительный просмотр, просто нажмите кнопку Stop Preview.
Мы также выполнили серьезную работу по отделению функции предварительного просмотра от остальных механизмов визуального дизайнера. Предварительный просмотр использует встроенный браузер JCEF, который чувствителен к тонкостям нестандартной конфигурации проекта, IDE и операционной системы. Теперь потенциальные проблемы в этой хрупкой части системы не влияют на окно инструментов Jmix UI и функции генерации кода.
Помощь в написании кода
В этом релизе мы представляем совершенно новый подход к инжекции зависимостей и UI-компонентов в классы экранов и бины Spring.
Как только вы начнёте вводить символы внутри тела метода, появится выпадающий список автодополнения, показывающий локальные переменные, методы и поля класса, а кроме того - доступные бины и UI-компоненты. Бины и UI-компоненты, которые ещё не были инжектированы в класс, будут отображаться курсивом. Если вы выберете один из этих элементов, он будет автоматически инжектирован в конструктор или поле с соответствующей аннотацией (@Autowired
или @ViewComponent
), и станет сразу доступным для использования в текущей позиции курсора.
С помощью этой функции найти и инжектировать доступные бины и UI-компоненты очень просто и быстро. Мы надеемся, что вам это понравится!
Поддержка репозиториев данных
Студия теперь полностью поддерживает создание и управление репозиториями Spring Data.
Вы можете создать репозиторий, нажав New → Data Repository в окне инструментов Jmix. Студия создаст интерфейс репозитория и отобразит его внутри узла сущности.
Кнопки Add Derived Method и Add Query Method на панели действий редактора кода репозитория вызывают редактор методов репозитория с производными или явными запросами:
Для существующих методов репозитория Studio отображает слева иконку, нажатие на которую позволяет настроить параметры метода, например, добавить сортировку или фетч-план:
Добавление комментариев к модели данных
И еще одна новая функция, которую я хотел бы осветить в этой статье - возможность добавления комментариев к сущностям и их атрибутам.
Дизайнер сущностей теперь содержит поля Comment как для самой сущности, так и для каждого атрибута. Вы можете добавлять комментарии, и они будут отображаться в этих полях:
Текст, введенный в дизайнере, сохраняется в аннотациях @Comment
класса сущности и его полей:
@Comment("""
Stores information about books.
Has reference to Genre.""")
@JmixEntity
@Table(name = "BOOK")
@Entity
public class Book {
// ...
@Comment("Book title")
@Column(name = "TITLE", nullable = false)
private String title;
Студия генерирует операции setTableRemarks
и setColumnRemarks
в файлах Liquibase changelog для сохранения комментариев в схеме базы данных (для всех баз данных, кроме HSQL). Это позволяет получать доступ к комментариям через любые инструменты работы с базой данных. Вы также можете извлекать комментарии из метаданных или непосредственно из аннотаций класса, чтобы отображать их в пользовательском интерфейсе приложения или генерировать документацию.
Что дальше?
В следующем функциональном релизе, запланированном на февраль 2024 года, мы собираемся реализовать новое дополнение Charts и завершить работу над функциями дополнения Maps. Слой UI получит компонент RichTextArea, горизонтальное главное меню и возможности поиска по элементам главного меню. Мы также собираемся упростить использование репозиториев данных в экранах UI.
Со стороны Studio мы предоставим hot deploy BPMN-определений бизнес-процессов, генерацию пользовательских REST-контроллеров и интеграционных тестов для ваших сущностей и экранов.
Наша подробная дорожная карта опубликована в виде проекта GitHub и регулярно обновляется. Патчи для релиза 2.1 будут выходить примерно раз в месяц.
Будем рады увидеть ваши отзывы на нашем форуме!
Спасибо всем, кто поделился своими идеями, предложениями и сообщениями об ошибках!