最近更新

本章节包含 Jmix 框架和 Studio 2.2 的新功能介绍,以及在升级框架版本时需要注意的一些破坏性改动。

如何升级

如需新建 Jmix 2.2 项目或者升级已有项目,需要使用 Studio 2.2 以上版本。因此,请先 升级 Jmix Studio 插件。

IntelliJ IDEA 的最低版本要求是 2023.2。

参阅 升级项目 部分的介绍了解如何使用 Studio 升级项目。自动升级迁移过程会对项目做如下修改:

  • 升级 Jmix BOM 的版本,BOM 又定义了所有依赖的版本。

  • 升级 Jmix Gradle 插件的版本。

  • Gradle 包装器版本更新到 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 应用程序属性。有关更多信息请参阅 后续部分

  • 如果项目包含 Application Settings 插件,则添加 jmix.appsettings.check-permissions-for-app-settings-entity = true 应用程序属性。有关更多信息请参阅 后续部分

请参考破坏性改动的 完整列表,并在升级后做相应修复。

更新的依赖

更新了以下主要依赖:

  • Spring Boot 3.2。有关更多信息请参阅: Spring boot release notes

  • Vaadin 24.3。有关更多信息请参阅 Vaadin 24.2 以及 24.3。迁移至 Jmix 2.2 时,Studio 会删除 .pnpmfile.cjs 文件,原因: vaadin/flow#17873。请确保升级版本后项目中没有该文件。

新功能和改进

支持 Java 21

现在可以用 Java 21 的语言特性编写应用程序了。

框架仍然使用 Java 17 构建,因此 Java 17 和 21 都可用于应用程序项目。

图表扩展组件

新的图表(Charts)扩展组件集成了 Apache ECharts JS 库。

参阅 图表扩展组件文档 和 GitHub issue #2437 了解更多内容。

地图改进

  • 添加了对 MultiPoint、MultiPolygon 和 MultiLineString 的支持。参阅: GitHub #2807

  • 添加了热力图(heatmap)图层。参阅: GitHub #2790

  • 添加了对集群的支持。参阅: GitHub #2575

BPM 改进

Studio 中的 BPM 表单向导现在支持使用实体实例而非流程变量为流程启动事件创建表单。请参考向导第一步中的 Form templateForm type 下拉列表。

  • 可以在 Studio BPMN 设计器中为服务任务设置 Async 标志。

  • 在 Studio 中开发的业务流程定义现在可以部署到正在运行的应用程序中。使用 Studio 中 BPMN 设计器顶部面板中的 Hot Deploy Process 按钮。

  • 运行时 BPM 建模器现在提供对 flowable:failedJobRetryTimeCycle 元素的支持。选中服务任务时,可以看到 Failed job retry time cycle 属性。

  • 运行时 BPM 建模器现在支持从下拉列表中为 Bean 参数选择已有的流程变量。

RichTextEditor 组件

新的 richTextEditor 组件集成了 Quill JS 库。在标准的 Add component 工具箱中可用。

横向主菜单

新的 horizontalMenu 组件支持创建带有横向菜单的主视图。

新的 Main view with top menu 模板可以通过视图创建向导使用。如果要使用新视图而不是现有主视图,请在向导的第一步中勾选 Use as default main view 复选框。然后 Studio 将替换所有视图 @Route 注解的 layout 属性,并在 jmix.ui.main-view-id 应用程序属性中指定新视图。

参阅: GitHub #2492

过滤主菜单

新的 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>

请注意,目前不支持对 横向主菜单 进行过滤。

主视图初始布局

现在,支持以声明方式定义初始布局,当主视图中未打开任何视图时将显示该布局。使用 appLayout` 组件的 initialLayout 元素:

<appLayout>
    <navigationBar .../>
    <drawerLayout .../>
    <initialLayout>
        <h2 text="Hello world!"/>
    </initialLayout>
</appLayout>

参阅: GitHub #2213

数据网格改进

处理双击事件

dataGrid 数据网格 组件现在可以在列表视图处理双击事件:打开详细信息视图,或者在查找模式下完成选择。参阅: GitHub #2582

表头过滤器的 URL 参数。

dataGrid 数据网格 表头过滤器状态可以在 URL 显示,以此提供带过滤器状态的深度链接,这样在详情视图之间切换时可以保留视图状态。

urlQueryParameters facet 中使用 dataGridFilter 元素,指向数据网格:

<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"/>

通用过滤器中的集合属性

The genericFilter 通用过滤器 组件现在支持为集合(多对多)属性创建过滤条件。

例如,在 Onboarding 示例中,可以按 steps 属性及其内部属性(steps.dueDatesteps.step.name 等)筛选用户。JPA 数据存储将自动创建带有 join 子句的相应 JPQL 查询语句。以前,只能通过手动定义 JPQL 条件 来实现此目的。

参阅: GitHub #518

向所有用户会话发送消息

UiEventPublisher Bean 现在具有 publishEventForUsers() 方法,接收应用程序事件实例和 username 集合作为参数。该方法可以将事件发送到特定用户的用户会话,无论这些用户是连接到集群中的同一服务器还是不同的服务器。

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,事件发送给所有已连接的用户。

参阅: GitHub #1235

保存实体性能改进

现在,如果详情视图是通过导航打开的,则默认情况下不会在保存并关闭操作后重新加载已编辑的实体,因为在这种情况下,列表视图无论如何都会重新加载整个列表。这样改进了复杂视图中加载和保存较大对象图的性能。

可以使用 DetailView 接口的 setReloadSaved() 方法显式控制是否加载已保存实例,例如:

@Subscribe
public void onInit(final InitEvent event) {
    setReloadSaved(true);
}

减少构建时间

如果实体自上次构建生成以来没有被修改过,则增强实体的过程中会跳过这些实体,这大大缩短了具有较大数据模型的项目的构建时间。

例如,如果已经构建了项目,然后修改了视图控制器并再次构建,此时,控制台中可以看到以下信息: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 开始,在最多 10 个实体和角色的小型项目中可以免费使用 premium RAD 功能,无需订阅。

代码片段

Studio 新增加的 代码片段 现在支持 BPM报表通知 以及 电子邮件 扩展组件。

通过向导添加组件

视图设计器Add Component 操作现在有两个 tab:

  • From Palette tab 显示组件工具箱,与以前一样;

  • Using Wizard tab 向导可以帮助解决 UI 中的复杂问题。例如,Edit entity attributes 向导会创建一个 formLayout,其中包含所选实体属性的字段,以及一个带有 fetch plan 的数据容器。

    向导的列表会根据当前视图内容变化:例如,如果视图有 dataGrid,则可使用 Add column to DataGrid 向导。

现在,Jmix UI 工具窗口的组件属性面板会显示指向所选 UI 组件文档的链接。即组件类型旁边的问号图标。

在组件层次结构的右键菜单中,也有 Jmix Documentation 项。

测试脚手架

Studio 在 Jmix 工具窗口展示 Tests 节点。双击该节点打开 Project 树的 src/test/java 文件夹。

New → Advanced → Integration TestNew → Advanced → UI Integration Test 操作支持快速创建测试 业务逻辑视图 的测试类。

破坏性改动

阻止浏览器标签页关闭

在 Jmix 2.0 中 引入 的阻止浏览器标签页意外关闭的功能现在默认不启用。在特定视图可以通过 setPreventBrowserTabClosing(true) 方法启用该功能,或配置下列应用程序属性启用全局配置:

jmix.ui.view.prevent-browser-tab-closing = true

Spring bean 的循环依赖

以前,Spring Bean 之间的循环依赖关系是由 Jmix 在框架层面启用的。

Jmix 2.2 本身不再有循环依赖,并且默认不会在应用程序项目中启用。

你的项目可能会存在 Spring Bean 的循环依赖关系,因此 Studio 迁移过程会自动将以下属性添加到项目中:

spring.main.allow-circular-references = true

我们建议删除此属性并尝试启动应用程序。如果初始化失败,请重构 Bean 以消除循环依赖关系,或继续沿用该属性。

参阅: GitHub #287

支持空过滤条件

以前,如果 属性条件 的参数值为空(null、空字符串或空集合),则其计算结果为 true。

从 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();

参阅: GitHub #2490

NoResultException

当 DataManager 的流式 加载 APIone() 方法没有返回结果,现在抛出 io.jmix.core.NoResultException 而非 java.lang.IllegalStateException。参阅: GitHub #2682

悲观锁

悲观锁功能现在抽取成为了 扩展组件

io.jmix.core.pessimisticlocking 包重命名为 io.jmix.pessimisticlocking

修改了下列属性:

  • jmix.core.pessimistic-lock.use-default-quartz-configurationjmix.pslock.use-default-quartz-configuration

  • jmix.core.pessimistic-lock.expiration-cronjmix.pslock.expiration-cron

Studio 迁移过程会自动将依赖项添加到 build.gradle 中,并更改 imports 和应用程序属性名称。

参阅: GitHub #1958

文件上传控件的验证

fileUploadField 单文件上传fileStorageUploadField 文件存储上传isInvalid() 方法不再触发验证,而仅仅检查字段本身是否有效。参阅: GitHub #2821

操作快捷键

button 按钮dataGrid 数据网格 等组件操作设置的键盘快捷键现在的处理方式不同了。参阅: GitHub #1758

应用程序属性的安全

应用程序属性 扩展组件不再要求添加 AppSettingsEntity 实体的许可便能通过 AppSettings bean 处理。

如果仍要使用之前的行为,请设置以下应用程序属性:

jmix.appsettings.check-permissions-for-app-settings-entity = true

Studio 迁移程序会自动将此属性添加到项目中。

参阅: GitHub #2710

Security Views

为了提高可用性,改进了资源和行级角色的标准视图的布局,参阅 GitHub #2519

如果扩展了这些视图,则可能需要修改代码。

DetailView 和 DataContext 接口

详情视图性能提升 中添加了以下方法:

  • DataContext.save(boolean reloadSaved)

  • DetailView.isReloadSaved()

  • DetailView.setReloadSaved(boolean reloadSaved)

如果直接实现了这些接口,则可能需要修改代码。

另外,如果未重新加载实体,则 DataContext.PostSaveEvent.getSavedInstances() 方法返回一个空集合。可以用新的 DataContext.PostSaveEvent.isEntitiesReloaded() 方法检查实体是否重新加载。

地图 API

地图 扩展组件用如下改动:

  • io.jmix.mapsflowui.kit.component.model.style.text.Padding 移至 io.jmix.mapsflowui.kit.component.model 包。参阅: GitHub #2822

  • FeaturePointFeatureMarkerFeatureLineStringFeaturePolygonFeature 类的 addStyles() 方法现在返回 void。如果需要继续使用要素的当前实例,请使用 withStyles()。参阅: GitHub #2807

  • VectorLayer 类中,addStyles() 方法现在返回 void。如果需要继续使用图层的当前实例,请使用 withStyles()。重命名的方法:isDeclutter()getDeclutter()isUpdateWhileAnimating()getUpdateWhileAnimating()。参阅: GitHub #2790

  • ClusterSource 类中,addPointStyles() 方法现在返回 void。如果需要继续使用数据源的当前实例,请使用 withPointStyles()。参阅: GitHub #2790

  • Layer 类中,isVisible() 方法重命名为 getVisible()。参阅: GitHub #2790

  • VectorLayerTileLayerImageLayerGeoMapView zoom 属性的类型从 Integer 改为 Double。参阅: GitHub #2701

变更日志

  • Jmix 框架解决的问题:

  • Jmix Studio 解决的问题: