Что нового
В данном разделе приведена информация о новой функциональности и возможных несовместимых изменениях в фреймворке Jmix и Jmix Studio версии 2.2. Примите их во внимание при обновлении с предыдущей версии фреймворка.
Для создания новых проектов в Jmix 2.2 или для апгрейда существующего проекта требуется Studio 2.2 или более поздней версии, поэтому в первую очередь обновите плагин Jmix Studio. Минимальная требуемая версия IntelliJ IDEA - 2023.2. |
Раздел Апгрейд проекта содержит информацию о том, как обновить проект с помощью Studio. Процедура автоматической миграции вносит следующие изменения в ваш проект:
-
Обновляет версию Jmix BOM, которая, в свою очередь, определяет версии всех зависимостей.
-
Обновляет версию Jmix Gradle plugin.
-
Обновляет версию Gradle wrapper до 8.6 в
gradle/wrapper/gradle-wrapper.properties
. -
В проектах на Kotlin обновляет версию плагина Kotlin до 1.9.22.
-
В связи с перемещением функциональности пессимистической блокировки, заменяет использования пакетов
io.jmix.core.pessimisticlocking
наio.jmix.pessimisticlock
, заменяет свойстваjmix.core.pessimistic-lock.*
наjmix.pslock.\*
и добавляет зависимости на новый аддон вbuild.gradle
. -
Добавляет свойство приложения
jmix.ui.view.prevent-browser-tab-closing = true
. Подробнее см. ниже. -
Добавляет свойство приложения
spring.main.allow-circular-references = true
. Подробнее см. ниже. -
Добавляет свойство приложения
jmix.core.skip-null-or-empty-conditions-by-default = true
. Подробнее см. ниже. -
Добавляет свойство приложения
jmix.appsettings.check-permissions-for-app-settings-entity = true
если проект содержит дополнение Application Settings. Подробнее см. ниже.
См. полный список опасных изменений, которые могут затронуть ваш проект после обновления.
Обновленные зависимости
Следующие важные зависимости были обновлены:
-
Spring Boot 3.2. См. его release notes для получения подробной информации.
-
Vaadin 24.3. См. release notes для Vaadin 24.2 и 24.3 для получения подробной информации. Studio удаляет файл
.pnpmfile.cjs
из проекта при миграции на Jmix 2.2 (по причине проблемы, описанной в vaadin/flow#17873). Убедитесь что данный файл более не существует после миграции.
Новая и улучшенная функциональность
Поддержка Java 21
Теперь вы можете использовать Java 21 и все её языковые возможности для написания приложений.
Фреймворк по-прежнему собирается с использованием Java 17, поэтому обе версии (и 17 и 21) доступны для прикладных проектов.
Дополнение Charts
Новое дополнение Charts интегрирует JavaScript-библиотеку Apache ECharts в пользовательский интерфейс Jmix.
См. документацию по Charts и тикет #2437.
Улучшения в дополнении Maps
-
Добавлена поддержка кластеризации и тепловых карт. См. High-Density Data Visualization.
-
Добавлена поддержка MultiPoint, MultiPolygon и MultiLineString. См. #2807.
Улучшения в дополнении BPM
-
Мастер форм BPM в Studio теперь поддерживает создание форм для стартового события и использование экземпляров сущностей вместо переменных процесса. См. выпадающие списки Form template and Form type на первом шаге мастера.
-
Флаг Async может быть установлен для сервисных задач в конструкторе BPMN в Studio.
-
Определения бизнес-процессов, разработанные в Studio, теперь могут быть развернуты в работающем приложении. Используйте кнопку Hot Deploy Process на верхней панели конструктора BPMN в Studio.
-
BPM-моделер в приложении теперь поддерживает элемент
flowable:failedJobRetryTimeCycle
. См. свойство Failed job retry time cycle выбранной сервисной задачи. -
BPM-моделер в приложении теперь позволяет выбирать существующие переменные процесса для аргументов бина из выпадающих списков.
Компонент RichTextEditor
Новый компонент richTextEditor
интегрирует JavaScript-библиотеку Quill в пользовательский интерфейс Jmix. Он доступен в стандартной палитре Add Component.
Горизонтальное главное меню
Новый компонент horizontalMenu
позволяет создавать главный экран с горизонтальным меню.
Новый шаблон Main view with top menu доступен в мастере создания экранов. Если вы хотите использовать новый экран вместо существующего главного экрана, выберите флажок Use as default main view на первом шаге мастера. Тогда Studio заменит атрибут layout
аннотации @Route
во всех экранах и установит новый экран в свойство приложения jmix.ui.main-view-id
.
Фильтрация главного меню
Новый компонент menuFilterField
позволяет пользователям фильтровать элементы главного меню. Он доступен в стандартной палитре Add Component.
Атрибут menu
должен указывать на компонент listMenu
, который нужно фильтровать:
<menuFilterField menu="menu"
placeholder="Search..." classNames="ms-s me-s"/>
<nav id="navigation" classNames="jmix-main-view-navigation" ariaLabel="msg://navigation.ariaLabel">
<listMenu id="menu"/>
</nav>
Обратите внимание, что фильтрация горизонтального меню не поддерживается.
Начальная компоновка в главном экране
Теперь вы можете декларативно определить начальную компоновку, которая будет отображаться, когда в главном экране не открыты никакие экраны. Используйте элемент initialLayout
компонента appLayout
:
<appLayout>
<navigationBar .../>
<drawerLayout .../>
<initialLayout>
<h2 text="Привет, мир!"/>
</initialLayout>
</appLayout>
Подробнее см. #2213.
Улучшения таблицы данных
Параметры URL для фильтра в заголовках столбцов
Фильтр в заголовке столбцов dataGrid теперь может отражаться в URL для предоставления глубокой ссылки и сохранения состояния экрана при переходе к экрану деталей и обратно.
Используйте элемент dataGridFilter
фасета urlQueryParameters, указывающий на таблицу данных:
<facets>
<urlQueryParameters>
<dataGridFilter component="usersDataGrid"/>
</urlQueryParameters>
</facets>
<layout>
<dataGrid id="usersDataGrid" dataContainer="usersDc">
<columns>
<column property="username" filterable="true" resizable="false" autoWidth="true"/>
Управление видимостью колонок
Новый компонент gridColumnVisibility
позволяет пользователям скрывать и показывать колонки таблицы данных. Он состоит из кнопки и выпадающего меню со списком колонок.
Пример использования:
<hbox id="buttonsPanel" classNames="buttons-panel">
<!-- ... -->
<gridColumnVisibility icon="COG" themeNames="icon"
dataGrid="usersDataGrid" exclude="picture"/>
</hbox>
<dataGrid id="usersDataGrid" dataContainer="usersDc">
<columns resizable="true">
<column key="picture" sortable="false" flexGrow="0" resizable="false"/>
<column property="username"/>
<column property="firstName"/>
Свойства-коллекции в универсальном фильтре
Компонент genericFilter теперь позволяет создавать условия для свойств-коллекций (ссылок с отношением "один ко многим").
Например, в приложении Onboarding, вы можете фильтровать пользователей по свойству steps
и его вложенным свойствам: steps.dueDate
, steps.step.name
и т.д. Хранилище данных с доступом через JPA автоматически создаст соответствующий JPQL-запрос с условием join
. Ранее это можно было сделать только путем определения JPQL-условия вручную.
Подробнее см. #518.
Отправка событий всем сессиям пользователя
Теперь у бина UiEventPublisher
есть метод publishEventForUsers()
, который принимает экземпляр события и коллекцию имен пользователей. Этот метод позволяет отправлять события в сеансы определенных пользователей, независимо от того, подключены ли они к тому же серверу или к разным серверам в кластере.
Пример отправки события пользователю alice
:
public class DepartmentListView extends StandardListView<Department> {
@Autowired
private UiEventPublisher uiEventPublisher;
@Subscribe(id = "sendEventBtn", subject = "clickListener")
public void onSendEventBtnClick(final ClickEvent<JmixButton> event) {
uiEventPublisher.publishEventForUsers(new MyUiEvent(this), List.of("alice"));
}
public static class MyUiEvent extends ApplicationEvent {
public MyUiEvent(Object source) {
super(source);
}
}
}
Пример слушателя событий:
public class MainView extends StandardMainView {
@Autowired
private Notifications notifications;
@EventListener
public void onMyUiEvent(DepartmentListView.MyUiEvent event) {
notifications.show("Event received");
}
}
Если второй аргумент метода publishEventForUsers()
равен null, событие отправляется всем подключенным пользователям.
Подробнее см. #1235.
Улучшена производительность сохранения
Теперь отредактированная сущность по умолчанию не перезагружается после действия save-and-close, если экран деталей был открыт через навигацию, потому что в этом случае экран списка все равно перезагружает весь список. Это улучшает производительность для сложных экранов, загружающих и сохраняющих большие графы объектов.
Вы можете явно контролировать перезагрузку сохраненных экземпляров, используя метод setReloadSaved()
интерфейса DetailView
, например:
@Subscribe
public void onInit(final InitEvent event) {
setReloadSaved(true);
}
См. возможно опасные изменения и #1725 для получения дополнительной информации.
Сокращено время сборки
Теперь процесс сборки пропускает этап модификации байткода (enhancing) сущностей, если они не были изменены с момента последней сборки. Это значительно сокращает время сборки для проектов с большой моделью данных.
Например, если вы запустили сборку проекта, а затем модифицировали контроллер экрана и снова запустили сборку, вы должны увидеть следующее сообщение в консоли: Entities enhancing was skipped, because entity classes haven’t been changed since the last build
.
Чтобы отключить это поведение и запускать модификацию байткода всех сущностей при каждой компиляции, добавьте следующую конфигурацию в build.gradle
:
jmix {
entitiesEnhancing {
skipUnmodifiedEntitiesEnhancing = false
}
}
Улучшения в Studio
Начиная с версии Jmix Studio 2.2, премиальные RAD-функции доступны без активной подписки для небольших проектов, в которых число сущностей и ролей не превышает 10. |
Сниппеты кода
В Studio теперь доступны новые сниппеты для функционала BPM, Отчетов, Уведомлений и Отправки электронной почты, если соответствующие дополнения включены в проект.
Добавление компонентов с помощью мастеров
Действие Add Component в Дизайнер экранов теперь имеет две вкладки:
-
Вкладка From Palette показывает палитру компонентов, как и раньше;
-
Вкладка Using Wizard содержит мастера, которые помогают решать сложные задачи, связанные с пользовательским интерфейсом. Например, мастер Edit entity attributes создает
formLayout
с полями для выбранных атрибутов сущности и контейнер данных с соответствующим фетч-планом.Список мастеров зависит от содержимого текущего экрана: например, если экран уже содержит
dataGrid
, то доступен мастер Add column to DataGrid.
Ссылка на документацию по UI-компоненту
Панель инспектора окна инструментов Jmix UI теперь показывает ссылку на документацию по выбранному компоненту UI. См. значок вопроса рядом с типом компонента.
Та же ссылка доступна как элемент Jmix Documentation в контекстном меню иерархии компонентов.
Генерация классов тестов
Studio теперь отображает элемент Tests в окне инструментов Jmix. Двойной щелчок на этом элементе открывает дерево Project в папке src/test/java
.
Действия New → Advanced → Integration Test и New → Advanced → UI Integration Test позволяют быстро создавать классы для тестирования бизнес-логики и экранов.
Опасные изменения
Предотвращение закрытия вкладки браузера
Функциональность предотвращения случайного закрытия вкладки браузера, введенная в версии 2.0, теперь по умолчанию отключена. Ее можно включить для конкретного экрана методом setPreventBrowserTabClosing(true)
, или глобально для всего приложения с помощью следующего свойства:
jmix.ui.view.prevent-browser-tab-closing = true
Циклические зависимости между бинами Spring
Ранее циклические зависимости между бинами Spring были разрешены в Jmix на уровне фреймворка.
Jmix 2.2 больше не имеет циклических зависимостей и по умолчанию не разрешает их в прикладных проектах.
Есть вероятность того, что ваш проект содержит циклические зависимости между своими бинами, поэтому процедура миграции Studio автоматически добавляет следующее свойство в проект:
spring.main.allow-circular-references = true
Мы рекомендуем вам удалить это свойство и попробовать запустить приложение. Если произойдет ошибка инициализации, то либо переработайте свои бины, чтобы устранить циклические зависимости, либо верните данное свойство.
Подробнее см. #287.
Обработка пустых условий
Ранее условия по свойствам преобразовывались в true если параметр условия был пуст (null, пустая строка или пустая коллекция).
Начиная с Jmix 2.2, null или пустой параметр не приводит к пропуску условия. Для примера рассмотрим следующий код:
dataManager.load(User.class)
.condition(PropertyCondition.contains("email", null))
.list();
В Jmix 2.1 и ранее он выполнял следующий SQL:
SELECT ID, ACTIVE, EMAIL, <...> FROM USER_
В Jmix 2.2 по умолчанию он выполняет следующий SQL и передает null
в качестве значения параметра:
SELECT ID, ACTIVE, EMAIL, <...> FROM USER_ WHERE EMAIL LIKE ?
В результате, в Jmix 2.1 возвращается список всех пользователей, а в Jmix 2.2 результирующий список будет пуст.
Чтобы вернуть предыдущее поведение, установите следующее свойство приложения:
jmix.core.skip-null-or-empty-conditions-by-default = true
Процедура миграции Studio автоматически добавляет это свойство в ваш проект.
В качестве альтернативы, вы можете пропустить пустые параметры для конкретных условий:
dataManager.load(User.class)
.condition(PropertyCondition.contains("email", null).skipNullOrEmpty())
.list();
Подробнее см. #2490.
NoResultException
Исключение io.jmix.core.NoResultException
теперь выбрасывается вместо java.lang.IllegalStateException
, если метод one()
fluent API загрузки сущностей DataManager не нашел ни одного экземпляра. См. #2682.
Пессимистическая блокировка
Функция пессимистическая блокировки была выделена в дополнение.
Пакет io.jmix.core.pessimisticlocking
переименован в io.jmix.pessimisticlocking
.
Следующие свойства приложения были изменены:
-
jmix.core.pessimistic-lock.use-default-quartz-configuration
→jmix.pslock.use-default-quartz-configuration
-
jmix.core.pessimistic-lock.expiration-cron
→jmix.pslock.expiration-cron
Процедура миграции Studio автоматически добавляет зависимости в ваш build.gradle
и изменяет импорты и имена свойств.
Подробнее см. #1958.
Валидация в полях загрузки файлов
Метод isInvalid()
компонентов fileUploadField и fileStorageUploadField теперь не вызывает валидацию, а только проверяет валидное состояние поля. См. #2821.
Проверка прав в Application Settings
Дополнение Application Settings теперь не требует наличия прав на сущность AppSettingsEntity
для работы с настройками через бин AppSettings
.
Чтобы вернуть предыдущее поведение, установите следующее свойство приложения:
jmix.appsettings.check-permissions-for-app-settings-entity = true
Процедура миграции Studio автоматически добавляет это свойство в ваш проект.
Подробнее см. #2710.
Экраны подсистемы безопасности
Компоновка стандартных экранов управления ресурсными ролями и ролями уровня строк была изменена для улучшения удобства использования. См. #2519.
Если вы расширили эти экраны в своем проекте, вам может потребоваться изменить свой код.
Интерфейсы DetailView и DataContext
Следующие методы были добавлены в интерфейсы в процессе реализации задачи улучшения производительности сохранения:
-
DataContext.save(boolean reloadSaved)
-
DetailView.isReloadSaved()
-
DetailView.setReloadSaved(boolean reloadSaved)
Вам может понадобиться изменить свой код, если вы напрямую реализовали эти интерфейсы.
Кроме того, метод DataContext.PostSaveEvent.getSavedInstances()
теперь возвращает пустую коллекцию, если сущности не были перезагружены. Это можно определить с помощью нового метода DataContext.PostSaveEvent.isEntitiesReloaded()
.
DTO-сущности в стандартных экранах
Фреймворк теперь не делает различий между JPA и DTO-сущностями при навигации к экрану деталей: он так же передает идентификатор сущности в параметре URL. Предполагается, что экран деталей для DTO-сущности получит этот идентификатор и загрузит экземпляр сущности из некоторого хранилища данных, используя делегат загрузки. Если вместо идентификатора передается константа "new"
, экран создает новый экземпляр.
Если вместо идентификатора передается вся сущность (например, при открытии в диалоговом окне), для определения режима (редактирования или создания) используется метод EntityStates.isNew()
. Следовательно, важно установить сущность в состояние "не новая" после загрузки ее из хранилища данных. Для сущности DTO это можно сделать с помощью нового метода EntityStates.setNew()
, для сущности JPA это делается стандартной реализацией хранилища данных JPA.
Если редактируемую сущность не нужно повторно загружать из хранилища перед установкой в контейнер данных, вызовите setReloadEdited(false)
в конструкторе экрана деталей или обработчике события InitEvent
. Это требуется в случае DTO-сущностей, существующих исключительно в памяти и не отображенных напрямую на внешние данные.
См. #2788 для получения дополнительной информации и рекомендаций, и проект External Data Sample для примера кода.
API дополнения Maps
Следующие изменения произведены в дополнении Maps:
-
io.jmix.mapsflowui.kit.component.model.style.text.Padding
перемещен в пакетio.jmix.mapsflowui.kit.component.model
. См. #2822. -
Метод
addStyles()
классовFeature
,PointFeature
,MarkerFeature
,LineStringFeature
,PolygonFeature
теперь возвращаетvoid
. Используйте вместо него методwithStyles()
, если вам нужно вернуть экземпляр feature. См. #2807. -
Метод
addStyles()
классаVectorLayer
теперь возвращаетvoid
. Используйте вместо него методwithStyles()
, если вам нужно вернуть экземпляр слоя. Кроме того, переименованы методы:isDeclutter()
→getDeclutter()
,isUpdateWhileAnimating()
→getUpdateWhileAnimating()
. См. #2790. -
Метод
addPointStyles()
классаClusterSource
теперь возвращаетvoid
. Используйте вместо него методwithPointStyles()
, если вам нужно вернуть экземпляр источника. См. #2790. -
В классе
Layer
методisVisible()
переименован вgetVisible()
. См. #2790. -
Тип свойств зума в классах
VectorLayer
,TileLayer
,ImageLayer
иGeoMapView
изменен сInteger
наDouble
. См. #2701.