最近更新

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

如何升级

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

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

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

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

  • 升级 Jmix Gradle 插件的版本。

  • Gradle wrapper 升级至 8.2,位于 gradle/wrapper/gradle-wrapper.properties 文件中。

  • build.gradle 中添加了 vaadin.optimizeBundle = false 属性。

  • 添加了 implementation 'io.jmix.security:jmix-security-starter' 依赖。

  • 对于使用 labelsPosition="ASIDE"formLayout 组件,现在都嵌套了一个 formItem 元素。

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

新功能和改进

支持 Flow UI 的扩展组件

下列扩展组件现在已经支持 Flow UI:

BPM 改进

  • DMN 表格编辑器 已经迁移至 Flow UI。

  • BPM 建模器现在支持 External Worker Tasks

  • 在新的 Studio 流程表单创建向导中,可以选择表单展示已有的流程变量,Studio 会为该变量创建合适的 UI 组件。向导中也支持定义流程表单视图的输出。

DataGrid 改进

列渲染器

可以声明式地为 dataGrid 列分配渲染器(renderers)。

框架自带一些渲染器,可以在 XML 直接使用:numberRendererlocalDateRendererlocalDateTimeRenderer。接收参数为字符串。示例:

<column property="dueDate">
    <localDateRenderer format="MMM dd, yyyy"/>
</column>

列现在可以通过 renderer 处理方法使用自定义的渲染器,这个处理方法可以通过 Jmix UI 组件属性面板的 Handlers 标签页为任意 column 元素生成。另外,column 元素支持不使用 property 属性,也就是说,这种列不与实体的某个属性关联。此时,column 元素必须有唯一的 key 属性。

下面的示例如何在列中使用自定义渲染器显示复选框:

<column key="completed" width="4em" flexGrow="0"/>
@Supply(to = "stepsDataGrid.completed", subject = "renderer")
private Renderer<UserStep> stepsDataGridCompletedRenderer() {
    return new ComponentRenderer<>(userStep -> {
        Checkbox checkbox = uiComponents.create(Checkbox.class);
        checkbox.setValue(userStep.getCompletedDate() != null);
        checkbox.addValueChangeListener(e -> {
            // ...
        });
        return checkbox;
    });
}

可以使用 com.vaadin.flow.data.renderer.Renderer 接口的不同实现。下面的示例中,列中展示了自定义文本:

<column key="status" header="Status"/>
@Supply(to = "stepsDataGrid.status", subject = "renderer")
private Renderer<UserStep> stepsDataGridStatusRenderer() {
    return new TextRenderer<>(userStep ->
            isOverdue(userStep) ? "Overdue!" : "");
}

按多列排序

dataGrid 现在支持按多列排序。可以通过下列 XML 属性配置:

  • multiSort - 启用多列排序。

  • multiSortOnShiftClickOnly - 如果设置为 true 则仅当按下 Shift 时点击表头才按多列排序。默认值为 false

  • multiSortPriority - 如果设置为 APPEND,则点击的列排序优先级最低。如果设置为 PREPEND(默认值),则点击的列优先级最高。

示例:

<dataGrid id="usersDataGrid" dataContainer="usersDc"
        multiSort="true"
        multiSortOnShiftClickOnly="true"
        multiSortPriority="APPEND">

聚合

dataGrid 现在支持对行内数据进行聚合。如需启用聚合功能,设置表格的 aggregatable 属性为 true,并为聚合列添加 aggregation 元素以及设置聚合类型。

示例:

<dataGrid id="ordersDataGrid" dataContainer="ordersDc"
        aggregatable="true">
    <columns>
        <column property="num"/>
        <column property="date"/>
        <column property="amount">
            <aggregation type="SUM" cellTitle="Total amount"/>
        </column>
    </columns>
</dataGrid>

表头过滤器

该功能目前为预览版。外观和内部实现可能在后续发布版本中做重大修改。

dataGrid 中的数据可以使用嵌入表头的 属性过滤器 进行过滤。

使用 filterable XML 属性定义哪些列支持过滤。可过滤的列表头带有漏斗图标(funnel)。如果用户点击该图标,会显示一个带属性过滤器的弹窗。如果设置了过滤条件,则列的图标会高亮。

为了更好地显示过滤器图标,请为表格列设置合适的列宽,或者设置 autoWidth 属性。并且,不能让列宽可拖动,否则,用户可能会变更列宽导致图标不可见。

示例:

<columns>
    <column property="username" filterable="true" width="20em"/>
    <column property="firstName" filterable="true" autoWidth="true"/>
    <column property="lastName" filterable="true" autoWidth="true"/>
    <column property="email"/>
</columns>

表头的属性过滤器与独立的属性过滤器以及 genericFilter 通用过滤器 一样,是通过在 数据加载器 添加过滤条件实现的。标准流程中,过滤条件会翻译成 JPQL 语句,并在数据库层面实现数据过滤。

可过滤的列也支持与 propertyFiltergenericFilter 组件同时使用。所有的条件都会用 AND 连接。

此时,列过滤器条件还没有与页面的 URL 绑定。也就是说,如果用户使用了列过滤器,然后导航至详情页面又返回,则过滤器会被清除。我们将在下一个版本中实现列过滤器与 urlQueryParameters facet 的集成。

VirtualList 组件

virtualList 组件用于展示带有复杂内容的列表数据。每次仅渲染可见的列表数据。

virtualList 也是与数据容器连接,默认展示容器中实体的实例名称。使用 renderer 处理方法可以展示任意内容。

下面的例子中,使用 virtualList 而非 dataGrid 展示列表数据:

<data readOnly="true">
    <collection id="stepsDc" class="com.company.onboarding.entity.Step">
...
<layout>
    <genericFilter id="genericFilter" ...>
    <hbox id="buttonsPanel" ...>
        <button id="createBtn" text="Create" themeNames="primary"/>
        <simplePagination id="pagination" dataLoader="stepsDl"/>
    </hbox>
    <virtualList id="stepsVirtualList" itemsContainer="stepsDc"/>
@Autowired
private UiComponents uiComponents;

@Supply(to = "stepsVirtualList", subject = "renderer")
private Renderer<Step> stepsVirtualListRenderer() {
    return new ComponentRenderer<>(step -> {
        HorizontalLayout hbox = uiComponents.create(HorizontalLayout.class);
        // 创建每个数据的内容
        return hbox;
    });
}

注意,virtualList 里面的展示的数据在页面上是不能选择且不能导航的。标准的 列表组件操作 也不能用于该组件,因此,如需操作的话,可以定义自己的 CRUD 操作。

Html 组件

使用 html 组件可以在视图中插入任意的 HTML 内容。

HTML 内容可以通过内部的 content 元素定义,或通过项目资源目录内的某个文件定义,或定义在消息包内。最后一种情况是比较容易支持国际化的。示例:

com/company/onboarding/view/sample/sample-view.xml
<html content="msg://helloWorld"/>
messages_en.properties
com.company.onboarding.view.sample/helloWorld=<h2>Hello World</h2>

Settings Facet

settings facet 可以保存并恢复当前用户的页面配置。此时,仅支持下列组件:

  • dataGridtreeDataGrid - facet 保存列的顺序和宽度,以及排序参数。

  • detailsgenericFilter - facet 保存 opened 状态。

  • simplePagination - facet 保存选择的页面数据展示条数,需要 itemsPerPageVisibletrue

项目需要有如下依赖才能使用 facet:

implementation 'io.jmix.flowui:jmix-flowui-data-starter'

当页面的 XML 包含 auto="true" 的 settings facet 时,该 facet 会管理页面中所有支持的组件,要求组件必须有 id:

<facets>
    <settings auto="true"/>

如果仅需管理某个特定组件,可以使用内部的 component 元素定义,示例:

<facets>
    <settings>
        <component id="customersDataGrid"/>
    </settings>

如果需要排除某些组件,可以设置 facet 的 auto="true",然后使用 enabled="false" 的组件配置:

<facets>
    <settings auto="true">
        <component id="customersDataGrid" enabled="false"/>
    </settings>

该 facet 还提供了 handler 可用于保存和恢复视图以及组件的任意属性。下面的示例演示如何保存一个复选框的值:

@ViewComponent
private SettingsFacet settings;
@ViewComponent
private JmixCheckbox testCheckbox;

@Install(to = "settings", subject = "applySettingsDelegate")
private void settingsApplySettingsDelegate(final SettingsFacet.SettingsContext settingsContext) {
    settings.applySettings();
    Optional<Boolean> value = settingsContext.getViewSettings().getBoolean("testCheckbox", "value");
    testCheckbox.setValue(value.orElse(Boolean.FALSE));
}

@Install(to = "settings", subject = "saveSettingsDelegate")
private void settingsSaveSettingsDelegate(final SettingsFacet.SettingsContext settingsContext) {
    settingsContext.getViewSettings().put("testCheckbox", "value", testCheckbox.getValue());
    settings.saveSettings();
}

有两个恢复设置的 handler:

  • applySettingsDelegate 在视图的 ReadyEvent 之前调用。

  • applyDataLoadingSettingsDelegate 在视图的 BeforeShowEvent 之前调用,可以用于恢复与数据加载相关的设置。

saveSettingsDelegate handler 在视图的 DetachEvent 之前调用。

UI 的设置以 JSON 格式保存在主数据存储的 FLOWUI_USER_SETTINGS 表中。可以在 实体探查 中打开 flowui_UserSettingsItem 实体管理保存的设置。

Timer Facet

新加的 timer(定时器)facet 支持以特定的时间间隔运行一些视图中的代码,它运行在一个可以处理 UI 事件的线程中,并能更新视图中的组件。

UI 元素和属性

前缀和后缀组件

XML 中可以为实现了 HasPrefixHasSuffix 接口的组件添加前缀(prefix)和后缀(suffix)组件。示例:

<textField id="nameField" property="name">
    <prefix>
        <icon icon="ASTERISK"/>
    </prefix>
    <suffix>
        <button id="setNameBtn" text="Set name"/>
    </suffix>
</textField>

内联 CSS 属性

所有组件现在支持内联的 css 属性,可以为组件设置样式。示例:

<button id="editBtn" action="usersDataGrid.edit" css="color: red;"/>

alignSelf 属性

组件新增了 alignSelf 属性用于在内部独立组件覆盖容器组件配置的 alignItems 属性。示例:

<hbox alignItems="CENTER" height="10em">
    <span id="totalLabel" text="Total"/>
    <span id="completedLabel" text="Completed" alignSelf="END"/>
    <span id="overdueLabel" text="Overdue"/>
</hbox>

该属性支持所有组件。对应于 CSS 的 align-self 属性。

下拉框选项的批量加载

具有下拉框的 UI 组件(comboBox 下拉列表, entityComboBox 实体下拉框, multiSelectComboBox 多选下拉框, multiSelectComboBoxPicker)现在可以根据用户的输入批量加载选项。例如,当用户输入 foo 时,组件会从数据库最多加载 50 个名称中包含 foo 的选项并在下拉框展示。当用户往下滚动列表时,组件会加载后续的 50 个选项。

如需使用这个功能,可以在组件内部定义 itemsQuery 元素替代 itemsContainer 属性。itemsQuery 元素需要包含内部的 query 元素用于指定查询语句,以及配置一些其他关于如何加载数据的属性。

entityComboBox 中使用 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>

comboBox 中使用 itemsQuery 的示例:

<comboBox id="departmentField" pageSize="30" >
    <itemsQuery searchStringFormat="(?i)%${inputString}%">
        <query>
            <![CDATA[select e.name from Department e where e.name like :searchString order by e.name]]>
        </query>
    </itemsQuery>
</comboBox>

可以看到,comboBox 中使用 itemsQuery 时,不需要指定 classfetchPlan 属性,因为查询语句会直接返回纯值列表(即 e.name)。

组件的 pageSize 属性定义批量加载数据的大小。默认为 50。

选项的批量加载也可以通过 itemsFetchCallback handler 编程式定义。示例:

<entityComboBox id="departmentField" property="department"/>
@Install(to = "departmentField", subject = "itemsFetchCallback")
private Stream<Department> departmentFieldItemsFetchCallback(final Query<Department, String> query) {
    String param = query.getFilter().orElse("");
    return dataManager.load(Department.class)
            .condition(PropertyCondition.contains("name", param))
            .firstResult(query.getOffset())
            .maxResults(query.getLimit())
            .list()
            .stream();
}

示例中,尽管数据是通过 DataManager 加载,但是你也可以用这个方案改成通过自定义服务加载。

只读数据加载器

XML 中定义 数据加载器loader 元素现在支持 readOnly 属性。如果该属性设置为 true,则数据加载器不会获取 DataContext 的引用,也不会在加载后将实体合并到 DataContext。因此,这个加载器加载的数据不受 DataContext 跟踪,即使发生变化也不会自动保存。

列表视图的模板现在默认使用这个属性替换 data 元素中的 readOnly="true"(会导致整个 DataContext 无法操作)属性。这两种配置都是为了使 DataContext 忽略只读数据而提高性能,但数据加载器的 readOnly 属性提供了更加细粒度的控制:常规的 DataContext 可以用于保存修改的实体,而同时为类似下拉框的组件仅加载只读数据。

Studio 现在生成的集合数据加载器默认带 readOnly="true"

下面的示例中,User 会合并到 DataContextDepartment 实体集合则不会:

<data>
    <instance id="userDc" class="com.company.onboarding.entity.User">
        <fetchPlan extends="_base"/>
        <loader/>
        <collection id="stepsDc" property="steps"/>
    </instance>

    <collection id="departmentsDc" class="com.company.onboarding.entity.Department">
        <fetchPlan extends="_base"/>
        <loader id="departmentsDl" readOnly="true">
            <query>
                <![CDATA[select e from Department e order by e.name]]>
            </query>
        </loader>
    </collection>
</data>

主从视图模板

新的 Master-detail view 模板支持创建主从视图,实体列表位于左侧,选择实体的详情位于右侧。

用户替代

用户替代 的视图已经在 Flow UI 中实现。

新建的项目在用户列表视图中的 Additional 下拉框中已经包含 User substitutions 选项。如需在已有项目中显示该菜单,打开 user-list-view.xml 并为 dataGrid 添加 sec_showUserSubstitutions 操作,以及 dropdownButton 按钮的对应操作:

<dropdownButton id="additionalBtn" ...>
    <items>
        <actionItem id="showUserSubstitutionsItem" ref="usersDataGrid.showUserSubstitutions"/>
...
<dataGrid id="usersDataGrid" ...>
    <actions>
        <action id="showUserSubstitutions" type="sec_showUserSubstitutions"/>

代码自动完成进行注入

Studio 现在提供了一种在 Spring bean 和视图控制器中注入依赖的新方式。

当你在一个方法内部输入一些字符时,会出现一个代码自动完成的弹窗,这里除了显示本地变量和类字段外,也能显示可用的 bean 和 UI 组件了。那些还没有在类里面注入的 bean 和 UI 组件会以斜体显示。如果你选择一项,则会自动注入到构造器或通过合适的注解(@Autowired@ViewComponent)注入字段,并且字段可以在光标处立即可用。

可以在 Jmix 插件配置Coding Assistance 标签页配置最少输入的字符数或关闭该功能。

支持 Data Repositories

Studio 现在完全支持创建和管理 data repositories

如需创建 repository,点击 Jmix 工具窗口的 NewData Repository。在 New Jmix Data Repository 对话框中,选择一个实体并点击 OK。Studio 会创建扩展自 JmixDataRepository 的 repository 接口,并在应用程序主类上添加 @EnableJmixDataRepositories

当在编辑器内打开一个 data repository 时,Studio 会在编辑器顶部显示带 2 个按钮的操作面板。Add Derived Method 按钮会创建一个从方法名生成查询语句的方法。Add Query Method 会创建一个指定了 JPQL 查询的方法。这两种方式都会打开特定的对话框用于配置查询语句及其参数。

对于 repository 中已有的方法,Studio 会在侧边槽展示一个齿轮图标,可以用于修改方法参数,比如添加排序或修改 fetch plan。也可以将查询语句抽取至一个 @Query 注解内,按照自己的需要修改。

特定实体的 data repository 显示在 Jmix 工具窗口实体的 Data Repositories 节点中。

数据模型备注

现在可以为实体和属性添加备注,请使用 @io.jmix.core.metamodel.annotation.Comment 注解,示例:

@Comment("""
        Stores information about books.
        Has reference to Genre.""")
@JmixEntity
@Table(name = "BOOK")
@Entity
public class Book {
    // ...

    @Comment("Book title")
    @Column(name = "TITLE")
    private String title;
}

对于除了 HSQL 之外的所有数据库,Studio 会生成 setTableRemarkssetColumnRemarks Liquibase changelog,将备注存储在数据库 schema 中。因此,使用任何数据库工具都可以看到。

项目中也可以从元数据(或直接从类注解)抽取备注展示到应用程序的 UI 中,或用于生成文档。框架提供了方便的 MetadataTools.getMetaAnnotationValue() 方法。

Studio 支持使用 实体设计器 创建备注:通过实体和属性参数的 Comment 链接按钮实现。如果设置了备注,则链接会显示前几个字。

视图设计器改进

现在 Jmix UI 工具窗口可以在编辑 XML 或 Java 控制器时展示了。支持在编写 Java 控制器代码时看到组件树、修改组件属性,甚至为视图添加新组件。还可以通过拖拽的方式从组件层级结构中将组件拖入控制器进行注入。

Preview 面板需要进行前端构建并启动 Vaadin 开发模式服务,这可能需要一些时间。因此,为了使项目的打开更加快捷,Preview 面板默认关闭,仅在点击 XML 编辑器顶部的 Start Preview 按钮时才打开。这样后续所有打开的项目视图都会有预览。也可以通过 Stop Preview 按钮停止预览。

Profile-specific Properties

Studio 现在可以基于在主 application.properties 文件中设置 spring.profiles.active 读取 profile-specific 文件中的配置了。因此,可以配置多个开发环境的独立 profile。

下面的示例展示了创建一个 dev profile,并在其中定义数据库连接,然后设置为开发环境默认配置文件的代码。

application.properties
spring.profiles.active = dev

# ...
application-dev.properties
main.datasource.url = jdbc:postgresql://localhost/onboarding-21
main.datasource.username = root
main.datasource.password = root

做了这些修改之后,Studio 的 数据存储配置 编辑器会从 application-dev.properties 读写数据库配置,而不再是 application.properties

你可以让 application-dev.properties 文件不参与版本管理,避免共享数据库连接配置。当在生产环境运行时,可以通过命令行或者环境变量指定不同的配置文件。

自定义数据库连接

现在可以定义一个连接至 Jmix 原生不支持的 附加数据存储 了。

该功能目前处于预览状态,并且默认关闭。如需启用,双击 Shift,在打开的列表中选择 Jmix Features,然后勾选 Generic Database Support for Additional Data Store

然后,当创建附加数据存储时,可以在 Database type 下拉框中找到 Generic DB 选项。如果选择这个类型,Studio 会让你输入以下参数:

  • DBMS type - 设置该数据库类型的唯一标识,这个标识也会用作该数据库相关类的前缀(下面会解释)。可以输入一个仅包含小写字母的短字符串,例如 foo

  • Database URL - JDBC 连接的 URL,示例:jdbc:foosql://localhost/database

  • Driver class name - JDBC 驱动的类名,示例:org.foosql.Driver

  • Driver artifact - JDBC 驱动制件的坐标,示例:org.foosql:foosql:1.0.0

  • Connection test query - 测试数据库连接的一个 SQL 查询语句,示例:select 1

  • Database platform - 设置一个继承自 org.eclipse.persistence.platform.database.DatabasePlatform 的类,用于为 EclipseLink ORM 框架描述该数据库。可以选择已有的适合你数据库的类,或者 Create DatabasePlatform class 创建一个新的类。

点击 OK

Studio 会在根包内创建一个 Myds1StoreConfiguration 类,其中带有必需的 bean 定义。此外,还会在 <base-package>/dbms 包内创建下列桩代码:

  • FooPlatform - 继承自 DatabasePlatform 的类。为 EclipseLink ORM 框架描述该数据库。

  • FooDbmsFeatures - 实现 DbmsFeatures 接口的类。为 Jmix 框架描述该数据库。

  • FooSequenceSupport - 实现 SequenceSupport 接口的类。描述该数据库如何处理序列。

  • FooDbTypeConverter - 实现 DbTypeConverter 接口的类。定义 Java 对象和 JDBC 参数、结果之间的转换方法。

Studio 还会在 build.gradle 添加 implementation 'org.foosql:foosql:1.0.0' 依赖。

之后,你需要在生成的庄代码中实现具体的方法。可以参考框架中的类,例如 JmixPostgreSQLPlatformPostgresqlDbmsFeatures 等。

破坏性改动

Production Build

由于 Vaadin 24.1.9 的改动,build.gradle 需要包含下列内容:

vaadin {
    optimizeBundle = false
}

这是 Production build 必需的代码。

认证对象中的角色

现在当前用户的角色由 Spring Security 的 SimpleGrantedAuthority 类包含,使用一个字符串表示一个角色。字符串的格式如下:

  • 资源角色:ROLE_<role-code>,例如:ROLE_system-full-access

  • 行级角色:ROW_LEVEL_ROLE_<role-code>,例如:ROW_LEVEL_ROLE_my-role

对应的授权 Java 类对象可以通过 RoleGrantedAuthorityUtils 类使用角色编码创建。

build.gradle 中需要包含下列 starter(Studio 会在升级时自动添加):

implementation 'io.jmix.security:jmix-security-starter'

之前在 Authentication 对象中表示角色的类 RoleGrantedAuthority 已经删除。

参考 GitHub issue #233 了解详情。

FormLayout 中的标签位置

如果 formLayout 中的组件标签放置在组件旁边,则这样的组件需要放入 formItem 内。

下面的示例中,组件的标签都位于侧边,而不论布局的宽度如何:

<formLayout dataContainer="userDc" width="100%" labelsPosition="ASIDE">
    <formItem>
        <textField id="usernameField" property="username" readOnly="true"/>
    </formItem>
    <formItem>
        <textField id="firstNameField" property="firstName"/>
    </formItem>
    <formItem>
        <textField id="lastNameField" property="lastName"/>
    </formItem>
    <formItem>
        <checkbox id="activeField" property="active"/>
    </formItem>
</formLayout>

如果定义了一些响应式布局的点以及使用了 labelsPosition="ASIDE",则也有同样的要求:

<formLayout dataContainer="userDc" width="100%" labelsPosition="ASIDE">
    <responsiveSteps>
        <responsiveStep minWidth="0" columns="1" labelsPosition="TOP"/>
        <responsiveStep minWidth="40em" columns="1" labelsPosition="ASIDE"/>
        <responsiveStep minWidth="50em" columns="2" labelsPosition="TOP"/>
        <responsiveStep minWidth="65em" columns="2" labelsPosition="ASIDE"/>
    </responsiveSteps>
    <formItem>
        <textField id="usernameField" property="username" readOnly="true"/>
    </formItem>
    <formItem>
        <textField id="firstNameField" property="firstName"/>
    </formItem>
    <formItem>
        <textField id="lastNameField" property="lastName"/>
    </formItem>
    <formItem>
        <checkbox id="activeField" property="active"/>
    </formItem>
</formLayout>

当升级项目至 Jmix 2.1 时,Studio 会自动完成这个改动。

SimplePagination.setTotalCountDelegate 签名变化

SimplePagination.setTotalCountDelegate() 方法的签名发生了变化。现在接收的参数是 Function<DataLoadContext, Integer>,而非 Function<LoadContext, Integer>

DataLoadContextLoadContextValueLoadContext 的共同父类,因此,这个改动可以使得 simplePagination 的计数代理能用 keyValueCollection 数据容器。

如果你的代码中通过编程的方式调用 SimplePagination.setTotalCountDelegate() 添加了代理,则需要进行修改。仅需将参数强转为 LoadContext,示例:

pagination.setTotalCountDelegate(dataLoadContext -> {
    long count = dataManager.getCount((LoadContext<?>) dataLoadContext);
    //...
});

使用 @Install 注解创建的代理不受影响。

参考 GitHub issue #2192 了解详情。

BaseContainerSorter.createComparator 签名变化

BaseContainerSorter.createComparator() 方法的签名也做了修改,目的是为了支持 dataGrid 中的多列排序(参考 GitHub issue #1265)。现在的参数为 Sort.Order 而非 Sort

如果你实现了 自定义排序,则需要修改你的对应方法。

jmix-main-view-navigation CSS 类

main-view.xmlnavjmix-main-view-navigation CSS 类添加了如下样式:

display: flex;
flex-direction: column;

如果你针对这个元素添加自定义的 CSS,则需要修改以适配 flexbox 布局。

变更日志