最近更新

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

如何升级

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

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

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

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

如果项目升级并启动应用程序后,遇到以下异常:

com.vaadin.flow.server.ExecutionFailedException: Vite build exited with a non zero status

需要从项目目录删除这些文件或文件夹:node_modulespackage.jsonpnpm-lock.yamltsconfig.jsontypes.d.tsvite.config.tsvite.generated.ts

另外,如果安装了全局的 Node.js,则需要升级至 https://nodejs.org 列出的最新的 LTS 版本。

依赖更新

下列主要依赖库更新:

  • Spring Boot 3.4

  • Vaadin 24.6

新功能和改进

Studio 改进

热部署提示

Studio 可以在支持热部署的文件(视图控制器和 XML,消息包,角色等)右上角显示一个新的图标,以提示当前文件的热部署状态。

这个指示器的作用是持续为开发人员提示源码中最新更改是否已经发布到运行中的应用程序。

应用程序日志分析

Studio 可以检测到应用程序控制台输出的常见异常并提供建议的解决方案。

热部署指示器也是通过分析应用程序控制台输出实现的。

Jmix Run/Debug 配置

我们引进了一个新的 Jmix run/debug 配置,可以替代标准的 Gradle 配置。当在 IDE 中打开 Jmix 项目时自动创建该配置。可以通过 Jmix 图标辨别新的配置。

与 Gradle 配置相比,新的 Jmix 配置可以停止应用程序而不产生任何控制台错误。

Run/Debug Configurations 窗口中可以点击 Add New Configuration 然后选择 Jmix Application 创建 Jmix run/debug 配置。如果右键点击 Jmix 工具窗口的根节点并选择 Start Application 也会创建这个配置。

classNames 编辑器和自动完成

Studio 对于 UI 组件 classNames 属性值的输入提供了高级支持。当在视图 XML 中编辑时,提供了 CSS 类名的自动完成选项。Jmix UI 组件提供了一个可以选择类名的编辑器窗口。

可用的类名从以下来源获取:

  • com.vaadin.flow.theme.lumo.LumoUtility 类及其内部类。

  • io.jmix.flowui.themes.JmixLumoUtility 类。

  • 任何使用 @ThemeUtilityClasses 注解的自定义类。可以在你自己的扩展组件或应用程序中提供共享的类名。

按标签生成 OpenAPI 客户端

当按照 Integrating Applications Using OpenAPI 指南通过 OpenAPI 结构生成客户端代码时,可以只选择 API 结构中的部分标签。这样在集成时如果不需要所有的路径,可以减少生成的代码量。

消息模板扩展组件

消息模板 扩展组件支持创建可重用的消息模板,用于发送电子邮件或应用内通知。

多标签应用程序模式(试验)

多标签应用程序模式 扩展组件支持在应用程序主视图的标签页中打开视图。

这个扩展组件通过在主视图标签样打开视图透明地替换了 页面导航 功能。也可以使用 ViewBuilders bean 在当前主视图标签页、新标签页或对话框窗口中打开视图。

多标签应用程序模式扩展组件目前还处于试验阶段,可能在下一个 Jmix 版本中可能会发生重大改动。

编辑地图中的对象

地图 扩展组件支持对矢量源中的要素进行选择、移动或编辑。

参阅 GitHub issue #2832

高级 BPM 任务列表视图

现在可以通过视图创建向导的 BPM: Advanced task list view 模板生成高级 BPM 任务列表视图。

这个视图比内置的 My tasks 多了一些功能并可以在项目中根据需要自定义。

参阅 GitHub issue #3752

审计中的替代用户

实体审计 扩展组件中的 Entity log 视图现在可以为每个改动显示登录用户和 替代用户

参阅 GitHub issue #4034

DataGrid 空状态

dataGrid 数据网格 组件现在支持 emptyStateComponentemptyStateText 属性,用于在没有数据的时候显示一些内容。

参阅 Vaadin 文档 和 GitHub issue #3884

REST API 和 REST 数据存储改进

REST API 和 REST 数据存储中的 Fetch Plans

在之前的版本中,通用 REST 端点仅能接受定义在共享 fetch plan 存储库中的命名 fetch plan 的名称。现在可以用 JSON 格式传递任意的 fetch plan。参阅 内联 Fetch Plans

这个功能会影响 REST 数据存储 的使用:现在无需在客户端和服务端应用程序中定义所有的 fetch plan。而是与视图和 Java 代码一样,可以只在客户端使用内联的 fetch plan。

REST API 开放了一个新的 能力 API。可以为客户端提供通用 REST API 功能的相关信息。目前 /capabilities 端点返回的 JSON 对象仅包含一个属性:inlineFetchPlans。如果这个属性值为 true,表示启用了内联 fetch plan。否则,客户端仍然只能传递命名 fetch plan。

可以通过应用程序属性 jmix.rest.inline-fetch-plan-enabled 禁用 REST 中的内联 fetch plan。当使用 Studio 从低版本 Jmix 升级至 2.5 时,会设置这个属性为 false,避免意外的数据泄露。

参阅 GitHub issue #4031

在 REST 数据存储使用文件存储

REST 数据存储现在包含了一个特殊的 FileStorage 实现,可以通过 /files 端点操作远端应用程序文件存储中的文件。参阅 REST 数据存储:文件存储

参阅 GitHub issue #4119

REST 端点路径可配置

REST API 端点的路径现在可以使用应用程序属性进行配置了,参阅 REST 属性:路径

参阅 GitHub issue #4052

REST API 的会话

Jmix Sessions 扩展组件提供了在使用相同 token 的 REST 请求之间维护会话的功能。在 build.gradle 中添加下面的内容可以使用这个组件:

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

参阅 GitHub issue #3915

实体 ID 使用 UUIDv7

现在为带了 @JmixGeneratedValue 注解的 UUID 属性生成 ID 时使用了 UUIDv7。这个版本的 UUID 是基于时间的,更适合自然排序和数据库主键。

UuidProvider 类的 createUuidV7() 方法现在默认用在 EntityUuidGenerator bean 中。如果仍然需要使用之前版本的 UUID,请设置应用程序属性:

jmix.core.legacy-entity-uuid=true

参阅 GitHub issue #3424

Copier 接口

新的 Copier 接口提供了 copy(Object) 方法,可以复制实体。语义上与 MetadataTools.deepCopy(Object) 类似,但是不同之处在于,新方法的实现不依赖元数据,仅通过 Java 的序列化复制对象的状态。

可以用 Copier 从 UI 中分离实体,并中视图中将分离的实体发送给自定义服务。DataContext 在通过 DataManager 保存实体时,也使用这个接口复制实体。

参阅 GitHub issue #3937

当前语言环境查询参数

现在可以在查询语句中与 current_user_ 前缀的参数一样使用预定义的 current_locale 查询参数。示例:

select e from Region e where e.locale = :current_locale

参数值是当前用户会话中的语言环境设置,从 CurrentAuthentication 对象获取。

参阅 GitHub issue #3958

热部署文件夹清理

在之前的版本中,热部署的文件夹 .jmix/conf 仅在执行 Studio 的启动应用程序之前的 Clean Hot Deploy Conf Directory 任务中清理。

为了确保清理工作更加可靠,且不依赖 Studio,我们在 Jmix Gradle 插件中添加了 cleanConf 任务。这个任务在每次启动程序的 bootRun 任务之前执行。

如果该功能出现了任何异常,可以在 build.gradle 添加下面的属性禁用 cleanConf 任务:

jmix {
    // ...
    confDirCleanupEnabled = false
}

参阅 GitHub issue #3451

破坏性改动

复选框的必选状态

checkbox 复选框 组件支持对 “required” 状态做验证。如果复选框由于其自身属性 required 或由于关联一个必需的实体属性而成为必填的字段,则仅 true 值能通过验证,并且包含该复选框的详情视图才能关闭。

参阅 Vaadin 文档 和 GitHub issue #4045

核心模块重构

由于重构了核心子系统对数据库相关库的依赖(GitHub issue #3918),下面这些破坏性改动可能会影响当前项目:

  • NotInstantiatedListNotInstantiatedSet 类从 io.jmix.data.impl.lazyloading 移至 io.jmix.eclipselink.lazyloading 包。这些类用来在 Kotlin 项目中初始化实体集合属性。需要更新实体中的依赖。

  • io.jmix.data.entity.ReferenceToEntity 可嵌入实体已经移除。如果项目中使用了,请自己创建一个拷贝。

  • io.jmix.flowuidata.accesscontext.UiGenericFilterModifyGlobalConfigurationContext 类移至 io.jmix.flowui.accesscontext 包。

  • io.jmix.flowuidata.action.genericfilter 包内的所有类移至 io.jmix.flowui.action.genericfilter 包。

  • io.jmix.securityflowui.model 包内的所有类移至 io.jmix.security.model 包。

  • io.jmix.flowuidata.genericfilter.UiDataGenericFilterSupport 类功能迁移至 io.jmix.flowui.component.genericfilter.GenericFilterSupport

参阅 GitHub issue #3982

授权服务的 Token 存储

授权服务 扩展组件现在将 token 保存在数据库中,以确保在服务重启时能保留之前的 token。

如果正在使用 密码授权,需要定义一个 JdbcOAuth2AuthorizationServiceObjectMapperCustomizer 类型的 bean,并按如下代码实现:

import io.jmix.authserver.service.mapper.DefaultOAuth2TokenUserMixin;
import io.jmix.authserver.service.mapper.JdbcOAuth2AuthorizationServiceObjectMapperCustomizer;
// ...
@SpringBootApplication
public class MyApplication implements AppShellConfigurator {
    // ...

    @Bean
    JdbcOAuth2AuthorizationServiceObjectMapperCustomizer tokenObjectMapperCustomizer() {
        return objectMapper ->
                objectMapper.addMixIn(User.class, DefaultOAuth2TokenUserMixin.class);
    }
}

这里的 User 是你项目中的用户实体类。

如果在使用 token 时出现 java.lang.IllegalArgumentException: The class …​ is not in the allowlist 异常,则表示实体包含了某种类型的属性,这个类型在 token 序列化器中默认不支持。需要创建一个 mixin 类,扩展 DefaultOAuth2TokenUserMixin,然后在 JdbcOAuth2AuthorizationServiceObjectMapperCustomizer bean 中使用。示例:

package com.company.backend.security;

import com.company.backend.entity.Department;
import com.company.backend.entity.UserStep;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.jmix.authserver.service.mapper.DefaultOAuth2TokenUserMixin;
import io.jmix.core.FileRef;

import java.util.List;

public class OAuth2TokenUserMixin extends DefaultOAuth2TokenUserMixin {

    @JsonIgnore
    private Department department;

    @JsonIgnore
    private List<UserStep> steps;

    @JsonIgnore
    private FileRef picture;
}

如果仍然希望使用之前的内存 token 存储,设置 jmix.authserver.use-in-memory-authorization-service 应用程序属性为 true。在通过 Studio 升级 Jmix 2.5 时,该属性默认设置为 true,以保留相应的逻辑。

参阅 GitHub issue #4153

FileStorageLocator 接口

io.jmix.core.FileStorageLocator 接口添加了 getAll() 方法。如果你有自己实现这个接口,则需要实现这个方法。参阅 GitHub issue #4119

构造器变化

由于内部的重构(GitHub issue #4152),下列 bean 的构造器发生了变化:

  • DetailViewNavigationProcessor

  • HtmlContainerReadonlyDataBindingImpl

  • MenuItemCommands

  • UrlQueryParametersFacetProvider

  • ViewNavigationDelegate

如果你扩展了这些 bean,需要对照修改。

变更日志

  • Jmix 框架解决的问题:

  • Jmix Studio 解决的问题: