最近更新

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

如何升级

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

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

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

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

  • 升级 Jmix Gradle 插件的版本。

  • 升级 Gradle wrapper 至 8.14.4

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

新功能和改进

Studio 改进

附加消息包

如果在项目中定义了 附加消息包,Studio 现在支持在 Localized Message 对话框中编辑消息时选择需要标记的包。

.env 文件中的环境变量

Studio 现在支持使用 .env 文件将配置外部化。可以将特定环境的变量与 application.properties 分开存储,并使用像 ${DB_URL} 这样的占位符来使用。

忽略外键约束

Studio 现在在为关联属性生成 changelog 时会遵循 JPA 的约束模式。如果在 @JoinColumn 中设置了 ConstraintMode.NO_CONSTRAINT,则生成的 changelog 不会包含外键约束。详见 忽略外键约束

SAML 扩展组件

Jmix SAML 扩展组件支持在 Jmix 应用程序中使用 SAML 2.0 认证。使用该扩展组件,Jmix 应用程序可以作为服务提供商(SP),并依赖外部身份提供商(IdP)(例如 Keycloak、Okta、Microsoft Entra ID 等)进行用户认证。

安装和配置详情请参考 SAML 扩展组件 章节。

工作日历中的日期标记

之前,工作日历 扩展组件仅支持为假期添加描述。现在可以为任何日历条目添加 标记。对日期进行分类更加便捷,比如标记某个日期可能有不同工作小时的原因。新增的 API 方法可用于查询特定日期的信息,包括为其分配的标记。

详见 创建工作日历

流程草稿视图

BPM 扩展组件现在提供了一个专用视图来浏览和预览流程草稿。以前,草稿只能通过 建模器 视图中的对话框访问,并且无法预览。

process drafts view

详见 流程草稿

流程实例图中高亮显示已执行路径

BPM 扩展组件增强了流程实例图,已完成的节点现在高亮为绿色,更容易辨别已执行的路径。

process instance diagram

该图可在 流程实例 视图中查看。

流程表单中的动态属性

在 BPM 扩展组件中,现在可以基于 Jmix 视图在流程表单中加载和显示动态属性。可以使用 @ProcessVariableParam 注解启用此功能。详见 加载动态属性

数据模型可视化

数据工具 扩展组件现在包含一个 数据模型 视图,可以在应用程序运行时展示实体及其属性。此外,该视图还支持使用公共或自托管的 PlantUML 服务器创建数据模型图(针对所有实体或选定的子集)。

对元素集合的支持

Jmix 数据模型现在支持基本类型、FileRef 对象或自定义类型的集合。在 JPA 实体中,这些集合属性使用 @ElementCollection 进行注解,并存储在单独的数据库表中。

有关如何定义元素集合,请参阅 实体 章节;有关如何在查询中使用,请参阅 使用 DataManager

默认情况下,元素集合属性是 延迟加载 的,并且可以在需要时包含在 fetch plan 中。

如需在 Studio 中创建元素集合属性,在 New Attribute 对话框的 Attribute type 下拉菜单中选择 ELEMENT_COLLECTION

另请参考 GitHub #1271

Fragments 中的 Facets

Fragments 现在支持 facets。请参阅 Fragment 中的 Facet 以及下面相关破坏性改动的信息:

侧边栏布局

新的 sidePanelLayout 组件提供了一种声明式的方式来构建带有可折叠侧边栏的布局。允许显示上下文内容或操作,而无需离开当前视图。

side panel layout editor

侧边栏可以从不同侧打开,并且可以覆盖主要内容或将其推开。有关详细信息和用法示例,请参阅 sidePanelLayout 侧边面板

侧边对话框

Dialogs API 引入了侧边对话框 —— 一种与 sidePanelLayout 类似的 UI 模式,但通过编程方式实现。SideDialog 会创建一个附着在屏幕侧边的覆盖层。

side dialog

可以用于不需要直接嵌入视图布局中的临时交互。有关详细信息和用法示例,请参阅 SideDialog

组件中对自定义图标的支持

多个组件现在通过内部元素支持自定义图标。这些元素表示组件中的特定图标槽位 — 例如 <icon><uploadIcon><dropdownIcon>,并支持开发者提供自己的图标。支持 SVG、字体图标或图片的形式。

示例:

<button text="Download">
    <icon>
        <fontIcon fontFamily="lumo-icons" charCode="ea17"/>
    </icon>
</button>

支持的组件有:actionbuttondropdownButtoncomboButtondrawerTogglefileUploadFieldfileStorageUploadFielduploadnotificationsIndicatorwebdavDocumentUploadmenu.xml<menu><item> 都支持 <icon>)。

详见 图标

覆盖默认图标

现在可以覆盖应用程序中的默认图标。新的 JmixFontIcon 枚举将 Vaadin、Lumo(Vaadin 中不存在的图标)和 Jmix 特定的图标合并为一个统一的集合。Icons bean 提供了一种中心化的方式来创建图标 UI 组件。通过重新定义 CSS 变量或替换图标字体来更改图标。

详见 覆盖默认图标

追踪

Jmix 现在使用 Micrometer Observation API 为框架操作创建跨度(span),例如数据访问、UI 视图和 fragment 生命周期、UI 操作。Jmix 还可以使用当前用户和租户的上下文来丰富观测数据。

支持 H2 数据库(实验性)

添加了对 H2 数据库的实验性支持。现在可以在数据存储属性编辑器的 Database type 下拉菜单中选择 H2 FileH2 Server

添加 spring.h2.console.enabled=true 应用程序属性,在开发环境中启用基于 Web 的数据库控制台。该控制台通过 http://localhost:8080/h2-console 访问。

自定义更新服务(实验性)

通用 REST API实体探查BPM 实体数据任务 现在可以将保存和删除操作委托给自定义的服务,而不是直接调用 DataManager。即,支持将实体更新逻辑放在一个服务中,并能从框架的通用功能中调用。以前,必须使用 EntityChangedEvent 监听器。

自定义服务应实现以下接口,以便被框架调用:

public interface SaveDelegate<E> {

    /**
     * Called by generic framework mechanisms instead of {@code DataManager} when saving entities of type {@code E}.
     *
     * @param entity entity to save
     * @param saveContext the whole save context
     * @return saved entity
     */
    E save(E entity, SaveContext saveContext);
}

public interface RemoveDelegate<E> {
    /**
     * Called by generic framework mechanisms instead of {@code DataManager} when removing entities of type {@code E}.
     *
     * @param entity entity to remove
     */
    void remove(E entity);
}

破坏性改动

Facet 注册和加载机制

FacetProvider 机制(用于 facet 注册)现已弃用,并将在未来版本中移除。出于向后兼容性考虑,使用 FacetProvider 注册的现有自定义 facet 仍然可以继续工作。但是,强烈建议迁移到新的 FacetRegistrationBuilder API。参见 自定义 Facet

破坏性改动影响了标准 Jmix facet 的覆盖机制。如果之前使用旧机制覆盖了框架 facet,这些覆盖在升级后将不再有效。此类自定义实现必须使用新 API 重新定义:

@Configuration
public class FacetConfiguration {

    @Bean
    public FacetRegistration extTimerFacet() {
        return FacetRegistrationBuilder.create(MyOverridenFacet.class)
                .replaceFacet(OriginalFacet.class)
                .build();
    }
}

Facet API 改动

此版本对 facet API 进行了几项改进,以更好地支持 fragments 并提供更清晰的抽象。

Facet Owner 类型变更

Facet.getOwner()Facet.setOwner() 方法已更新以支持 fragment 作为所有者:

  • Facet.getOwner() 现在返回 <T extends Composite<?> & FacetOwner> T(之前为 View<?>

  • Facet.setOwner() 签名变更为 <T extends Composite<?> & FacetOwner> void setOwner(@Nullable T owner)(之前为 void setOwner(@Nullable View<?> owner)

以前,facet 所有者只能是 View。现在,任何同时实现 Composite<?>FacetOwner 的组件都可以作为 facet 所有者。这个改动使得 facets 能够与 fragments 一起使用,因为 Fragment 同时实现了这两个接口。

如果你的代码直接调用这些方法,请相应地更新类型。

Facet 类重构

具体的实现类(*Impl)已被抽象基类替换:

  • DataLoadCoordinatorImplAbstractDataLoadCoordinator

  • SettingsFacetImplAbstractSettingsFacet<S extends UiComponentSettings<S>>

如果你之前直接实例化了这些类,请使用依赖注入或新的抽象类实现。

Settings 接口参数化

settings 接口现已参数化以提高类型安全性:

  • SettingsFacetSettingsFacet<S extends UiComponentSettings<S>>

  • SettingsContextSettingsContext<S extends UiComponentSettings<S>>

如果你实现了自定义的 SettingsFacet 或使用了 SettingsContext,请添加泛型参数:

// Before:
public class MySettingsFacet implements SettingsFacet

// After:
public class MySettingsFacet implements SettingsFacet<MyUiComponentSettings>

更多信息,请参考: GitHub #4185

已弃用的返回 IcongetIcon() 方法

此版本添加了 Icons bean 以支持 覆盖默认图标。在解析 XML 图标属性时,该 bean 将没有集合名称的值视为字体图标并生成 FontIcon;包含集合名称的值则生成 Icon。例如:

  • icon="CHECK" 创建一个 FontIcon 组件,

  • icon="vaadin:check" 创建一个 Icon 组件。

因此,带有返回 IcongetIcon() 方法的组件已被弃用。如果你声明的图标没有集合名称,这些方法将返回 null。请更换为使用 getIconComponent() 获取实际的图标组件。

视图路由

Jmix 子系统提供的所有视图的路由均已更改为 kebab-case。例如:sec/resourcerolemodelssec/resource-role-models。为了向后兼容,旧路由被定义为别名,因此所有保存的外部链接应该仍然有效。

如果你覆盖了一个框架的视图并将 @Route 注解复制到你的视图类中,请将其移除。否则,该视图将无法注册,应用程序将无法启动。

有关更多信息,请参见 GitHub #4841

OIDC 和授权服务中的角色作用域

修复了 OpenID Connect 扩展组件中对 角色作用域 的处理。可以使用 jmix.oidc.filter-chain.force-ui-scope-enabledjmix.oidc.filter-chain.force-api-scope-enabled 应用程序属性恢复到之前的行为。

如果在 Jmix 2.7 中使用了 jmix.resource-server.force-api-security-scope.enabled 属性,请将其替换为 jmix.authserver.filter-chain.force-api-scope-enabled 属性并设置为 false

有关更多信息,请参见 GitHub #5094

MariaDB UUID

为了与 MariaDB 和 Liquibase 的所有之前及当前版本兼容,现在对 UUID 属性显式使用 char(36)

如果你正在使用 MariaDB,请在将项目更新到 Jmix 2.8 后按照以下说明操作。

  1. 消除已执行 changelog 的 Liquibase 校验和错误。可以使用以下两种方法之一:

    1. 使用 main.liquibase.clear-checksums=true 属性运行应用程序一次。例如,如果你的主数据存储使用 MariaDB,请执行以下命令:

      ./gradlew bootRun --args='--main.liquibase.clear-checksums=true'

      或者,可以将 main.liquibase.clear-checksums=true 添加到 application.properties 文件中,并构建一个特殊版本的应用程序,在生产数据库上运行一次。

      使用此选项在数据库上运行 Liquibase 后,数据库中的校验和将被更新,并与源代码中的 changelog 兼容。

      不要在后续启动中使用 main.liquibase.clear-checksums=true

    2. 可以在 changelog 文件中设置有效值,而不是清除校验和。对于每个使用了 uuid.type 变量的 changeset,将 validCheckSum 设置为 DATABASECHANGELOG 表的 MD5SUM 列中当前存在的值。例如:

      <changeSet id="1" author="admin">
          <validCheckSum>9:c2f20bd9d8765d4c2554826e5eb376a8</validCheckSum>
          <!--...-->
      </changeSet>
  2. 确保根 changelog(例如 com/company/sample/liquibase/changelog.xml)包含以下属性:

    <property name="uuid.type" dbms="mariadb" value="char(36)"/>
  3. 确保新生成的 changelog 对 UUID 属性使用 ${uuid.type}char(36)。例如:

    <changeSet id="1" author="sample">
        <createTable tableName="FOO">
            <column name="ID" type="${uuid.type}">

有关更多信息,请参见 GitHub #4838

变更日志

  • Jmix 框架解决的问题:

  • Jmix Studio 解决的问题: