3.1 版本说明
如何升级
|
如需使用 Jmix 3.1 创建新项目或升级已有项目,需要 Studio 3.1 或更高版本,因此请先 更新 Jmix Studio 插件。 Jmix Studio 3.1 需要 IntelliJ IDEA 2026.1 或更高版本。 |
有关如何使用 Studio 升级项目,请参阅 升级项目 部分。自动迁移程序会对项目进行以下更改:
-
更新 Jmix BOM 的版本,以及所有依赖库的版本。
-
更新 Jmix Gradle 插件的版本。
-
将 Gradle wrapper 更新到 9.8.0
-
在
application.properties添加一下应用程序属性,以保持扩展组件之前的行为:
You can remove these properties later to get the new behavior.
另请参阅升级后可能影响项目的完整 破坏性变更 列表。
新功能和改进
Jmix CLI
Jmix CLI 是一个新的命令行工具,无需 IDE 即可创建 Jmix 项目:可在终端、脚本中或由 AI 编码 agent 使用。该工具使用与 Studio 相同的项目模板,并在新项目中添加 Jmix Agent Toolkit。有关如何安装和使用,请参阅 使用 Jmix CLI。
Studio 改进
-
视图创建向导 新增了一个列表和主从视图的步骤,可以在其中选择用户如何过滤数据:genericFilter(默认)、为选择的属性生成的一组 propertyFilter 组件、如果项目中包含 Search 扩展组件则使用 fullTextFilter,或者不使用过滤器。
-
实体设计器 支持为实体或实体引用属性定义 @LookupField 注解。视图创建向导在为引用属性生成选择组件时会使用此注解。
-
实体设计器中新加的 Views with Attribute 操作会显示绑定到实体属性的视图组件,并在所选组件处打开视图 XML。还支持将属性添加到实体的视图中。该操作可在属性表格工具栏和每个属性行中使用。
-
新的 Copy View 操作会复制一个视图,包括其控制器、XML 和消息。
-
New → Advanced → Custom Component 操作会创建 自定义 UI 组件 的文件:组件类、XML 加载器以及注册加载器的 Spring 配置。还可以为组件的 XML 元素创建 XSD schema、创建 Studio 元数据,以及创建一个包含 Lit Web 组件的 JavaScript 文件。
-
包含未应用的 Liquibase 变更日志的对话框现在会显示所选变更日志的内容。可以用来查看新加扩展组件中包含的变更日志。
-
可以从
LoadContext.Query和setQueryString()方法中查询语句的侧边栏图标打开 JPQL 设计器。 -
Studio 检查会检查 Java 代码中定义的有 流式带区 的报表结构。会报告报表引擎不支持的结构,例如,包含多个个流式带区、流式带区的子带区,或者不是 SQL 或 JPQL 的数据集。
新增 AI Chat 扩展组件
新的 AI Chat 扩展组件可用于构建 AI 聊天界面。AI 的回答来自应用程序实现的 LLMProvider 接口,因此这些聊天 UI 组件可与 Spring AI、供应商 SDK 或自己的 LLM 服务配合使用。
-
aiChat 是一个完整的聊天组件,支持流式回答、Markdown 消息、文件附件和对消息的操作。可以与自定义的聊天消息实体集合绑定,从而实现保存对话。
-
aiMessageList 和 aiMessageInput 可以单独使用,构建
aiChat自定义的聊天界面。 -
aiCodeBlock 支持在聊天消息和其他任何视图中显示源代码。
新增 UI 恢复扩展组件
新的 UI 恢复 扩展组件在服务器节点重启、HTTP 会话过期或浏览器关闭时保留视图中未保存的更改。在用户操作期间将更改作为草稿保存到数据库,并在用户再次打开视图时提示恢复草稿。草稿在集群中以及应用程序完全重启后仍然可用。
动态模型扩展组件
动态模型 扩展组件不再处于实验阶段。并提供以下新功能:
-
UI 处理器 为视图添加行为:在按钮点击、值更改和视图事件发生时运行定义的表达式,并且可以调用带
@DynamicModelOperation注解的应用程序方法。 -
全文搜索:可搜索的动态属性会被索引。
-
集群支持:在一个节点上发布的模型会自动发布到所有其他节点。
-
Dynamic model: modify settings without data loss 角色支持用户仅发布不会丢失数据的更改。
-
模型历史 显示模型的所有已发布版本。
-
可以更改 属性顺序。
-
可以为引用属性设置 查找字段类型和操作。
-
动态视图的菜单项可以有 图标。
-
Generate XML 按钮会 将视图模板渲染为 XML,然后可以进行编辑。
-
模型中授予某个角色的访问权限也适用于该角色的子角色。参考 继承角色。
-
动态实体和属性会显示在 数据工具 的视图中。
AI 工具扩展组件
AI 工具 扩展组件具有以下新功能:
-
新的 @ExcludeFromAi 注解在代码级别对数据加载工具隐藏实体或属性。与
jmix.aitools.dataload.*包含和排除属性不同,该注解无法在部署时被覆盖,因此只能通过更改代码并重新构建应用程序来开放隐藏数据。 -
聊天 UI 会 自动设置会话标题。默认情况下,使用第一条用户消息作为标题。新的 jmix.aitools.ui.conversation-title-mode 属性定义标题的规则。
报表扩展组件
报表 扩展组件有以下新功能:
-
报表带区现在可以是 流式 的:通过数据库游标按行读取并写入 XLSX 文档,而不是加载到内存中。如需配置流式带区,请在报表详情视图中勾选 Streaming,或在
@BandDef注解中设置streaming = true。 -
新的 AI 生成的 JPQL 数据集类型支持用自然语言描述带区数据。在报表详情视图中,LLM 根据提示生成 JPQL 查询语句,视图将其存储在报表定义中。报表运行通过
DataManager执行存储的语句,并应用当前用户的数据访问权限。
UI 约束扩展组件
UI 约束 扩展组件提供了 UiComponentPolicyContext,用于 检查组件权限,并为 视图打开后创建的内容 提供了新的 UiComponentPolicyApplier 方法。
懒加载标签页中的组件和操作现在会在标签页被选中时遵循 UI 组件策略。隐藏标签页也可能在视图打开期间选中另一个标签页。标签页选择时的自动策略应用默认启用,可以通过 jmix.uiconstraints.apply-policies-on-tab-selection 禁用。
分组数据网格扩展组件
通过将 groupDataGridFilter 元素添加到 urlQueryParameters facet,可以将已生效的 表头过滤器 保留在 URL 查询参数中。
电子邮件发送扩展组件
-
新的 电子邮件连接 视图替代了 OAuth2 token 视图。使用授权码流程连接邮箱账户,对于 Microsoft 则使用设备码流程,并存储刷新令牌。该视图还显示连接参数,可以测试与邮件服务器的连接。
-
新的 jmix.email.oauth2.redirect-uri 属性可以设置授权码流程的重定向 URI,例如当应用程序在反向代理后运行时。
-
扩展组件会自动设置
XOAUTH2认证机制,因此无需添加spring.mail.properties.*配置。
只读视图
新的 只读视图 显示用户无法编辑的实体实例。只读视图继承 StandardReadView,按 id 加载实体,并且视图的 DataContext 也是只读的。
-
可以在 Studio 中使用 视图创建向导 的 Entity read view 和 DTO entity read view 模板创建只读视图。
-
可以使用 ViewNavigators 和 DialogWindows bean,以及标签页模式扩展组件的 ViewBuilders bean 打开只读视图。
-
如果实体有只读视图,则 list_read 操作会以只读模式打开,而不是打开详情视图。新的 entity_read 操作可以显示在实体选择器中选中的实体。
-
@ReadViewTemplate 注解在运行时为实体生成只读视图。动态模型扩展组件为声明了 只读类型视图 的动态实体生成只读视图。
可调整大小的侧面板
用户现在可以在运行时通过拖动侧面板内边缘的手柄来 调整侧边面板组件的大小。水平和垂直位置的侧面板都支持该功能,并遵循配置的最小和最大尺寸。settings facet 可以保存和恢复当前用户选择的尺寸。
SVG 组件
新的 svg 组件直接在视图中渲染 SVG。SVG 内容可以在内部的 content 元素中设置,使用 file 属性从文件加载,或在视图控制器中设置。
浮窗组件
新的 popover 组件是一个浮窗,在目标组件旁边打开,浮窗能包含任何组件。可以在视图或 fragment XML 中声明,并将 target 属性设置为目标组件的 id。通过 UI 的点击、鼠标悬停或聚焦打开,也可以从视图控制器打开,并且支持模态窗。
数据网格的浮窗渲染器
使用新的 浮窗渲染器 可以在 dataGrid 列中显示长文本。如果单元格文本过长,则用省略号截断,点击单元格会在浮窗中显示完整文本。在 XML 中为列添加 popoverRenderer 元素,或在 Java 中创建 PopoverRenderer。
滑块组件
新的组件支持用户沿轨道拖动手柄来选择单个数字或数字范围:
-
integerSlider 和 decimalSlider 支持选择
Integer或Double值。与其他字段一样,可以与实体属性绑定并支持验证器。 -
integerRangeSlider 和 decimalRangeSlider 支持选择值的范围,例如过滤数据。
徽标组件
新的 badge 组件用于显示一个简短信息,例如状态、计数或标签。徽标可以显示文本、图标和数字,主题样式可设置颜色和大小。可以使用 dataContainer 和 property 属性将徽标绑定到实体属性,以显示属性值。
查找字段注解
新的 @LookupField 实体注解定义了框架为选择引用而生成的组件:带下拉列表的 entityComboBox,或打开查找视图的 entityPicker。用于 genericFilter 和 propertyFilter 参数、可编辑的 dataGrid 单元格以及运行时视图模板。将该注解放在实体类上,则对所有该实体的引用有效;或放在引用属性上,仅对该属性有效。还可以设置组件的操作,并在用户输入时分页加载下拉列表,使用 JPQL 查询语句或按实例名称搜索。
entityComboBox 的 itemsQuery 元素新增了 byInstanceName 属性,无需 JPQL 查询即可按实例名称查找项。
破坏性变更
Vaadin 25.3
更新到 Vaadin 25.3 带来以下更改(见 #5720):
-
image 组件不能再包含其他组件。
JmixImage不再提供setText()/getText()、setWhiteSpace()、setEnabled()/isEnabled()、add()和remove()方法。在 XML 中,image的enabled、text和whiteSpace属性以及内部组件将被忽略。 -
JmixMenuBarRootItem.updateClassName()方法已移除。 -
InMemoryUploadHandler和FileTemporaryStorageUploadHandler现在继承 Vaadin 的AbstractUploadHandler,而不是TransferProgressAwareHandler。FileTemporaryStorageUploadHandler在上传失败或被拒绝时删除临时文件,其getFileInfo()方法在当前上传组件创建文件之前返回null。 -
在 标签页模式 扩展组件中,app shell 的
@Push配置在调用UIInitListener监听器之前应用,因此监听器可以覆盖该配置。 -
Anchor.setHref()和IFrame.setSrc(),以及anchor和iframe的href和srcXML 属性,对于 Vaadin 认为不安全的 URL scheme(例如javascript:)会抛出IllegalArgumentException。将该 scheme 添加到 Vaadin 的safeUrlSchemes配置参数,或在代码中使用setUnsafeHref()和setUnsafeSrc()。 -
addThemeName("")抛出IllegalArgumentException。 -
TreeGrid方法expand()、collapse()、expandRecursively()和collapseRecursively()现在接收Collection<? extends T>和Stream<? extends T>参数。如果在TreeDataGrid子类中重写了这些方法,请更新方法签名。 -
许多
VaadinIcon常量和对应的JmixFontIcon常量已弃用。JmixSideDialog的setRole()已弃用,改用setAriaRole();Dialogs.SideDialogBuilder的withOverlayRole()已弃用,改用withAriaRole()。
AI 工具扩展组件
-
JpqlExecutionResult.getRows()和EntityDataLoadResult.getRows()的返回的行现在对于没有值的列包含null(见 #5598)。以前这种情况是包含空字符串。工具返回给模型的行也包含null而不是空字符串。方法签名相同,因此编译器不会显示需要修复的位置。读取行时请检查值是否为null:EntityDataLoadResult result = aiDataLoadService.loadData("customers with their email"); for (Map<String, Object> row : result.getRows()) { Object email = row.get("email"); String text = email != null ? email.toString() : ""; // email can be null } -
EntityDataLoadResult.getQuery()现在返回实际执行或验证失败的查询语句(见 #5749)。如果生成的查询语句被修复,该方法返回修复后的查询,其解释、警告、maxResults和firstResult都来自修复后的结果。LLM 生成的原始查询无法从结果中获取。 -
AiChatMessageService接口新增了loadLatestMessages()方法(见 #5649)。如果有自己实现,请实现该方法。聊天中心现在按最后一条消息的时间而不是创建时间对对话进行排序和分组。 -
新对话现在会将第一条用户消息作为标题(见 #5648)。以前会保留
New AI Conversation标题。如果代码在第一条消息之前为对话设置了自定义标题,第一条消息会替换该标题。如需保留自定义的标题,请在显示该对话的AiChatFragment上调用setTitleMode(AiConversationTitleMode.NONE)。如需在整个应用程序中保留以前的行为,请将 jmix.aitools.ui.conversation-title-mode 属性设置为NONE。
图表扩展组件
-
默认主题具有新的调色板和间距。图例位于底部居中,标题位于顶部居中。如需让外观更接近之前的版本,请在
charts:chart上设置colorPalette="#5470c6, #91cc75, #fac858, #ee6666, #73c0de, #3ba272, #fc8452, #9a60b4, #ea7ccc",在charts:legend上设置top="0",并在charts:title上设置left="0" top="0"。检查顶部或底部有组件的图表,例如滑块dataZoom:可能与标题或图例重叠。 -
轴标签和名称保留在图表内部,轴名称会移动以避免与轴标签重叠。如需恢复以前的行为,请在
charts:gridItem上设置outerBoundsMode="NONE",或在轴上设置nameMoveOverlap="false"。 -
富文本样式继承普通标签的字体和文本阴影设置。如需恢复以前的行为,请将
"richInheritPlainLabel": false添加到nativeJson。 -
条形图、象形条形图、K线图和箱线图的形状不再超出网格。如需恢复以前的行为,请在轴上设置
containShape="false"。 -
tooltip
valueFormatter函数的第二个参数现在是原始系列数据中的索引,而不是dataZoom过滤后的索引。请更新用到这个参数的 JavaScript 函数。 -
Grid.containLabel已弃用。请改用outerBoundsMode="SAME"和outerBoundsContain="AXIS_LABEL"。启用containLabel时,outerBounds*选项将被忽略。
电子邮件发送扩展组件
-
OAuth2 token 视图替换为新的连接视图,视图 id 从
email_tokenView更改为email_connectionView(见 #5546)。旧的email/token路由仍然有效。请在以下位置替换旧视图 id:-
如果应用程序使用单菜单模式,则在
menu.xml中替换。否则,主视图会因NoSuchViewException而失败。 -
在资源角色的
@ViewPolicy和@MenuPolicy注解中替换。否则,用户将无法访问该视图。
-
-
扩展组件不再定义
mailSendTaskExecutorbean(见 #5703)。以前,Vaadin 可能将此 bean 用于异步工作,并且如果应用程序有另一个TaskExecutorbean,则启动失败。现在:-
按名称注入
mailSendTaskExecutorbean 的代码会在启动时因NoSuchBeanDefinitionException而失败。请移除这类注入。 -
自定义代码中名为
mailSendTaskExecutor的 bean 不再替换电子邮件发送池。扩展组件会忽略这个 bean,并在启动时记录警告。 -
@Async方法和 Vaadin 异步任务在 Spring Boot 的applicationTaskExecutorbean 运行,而不是在电子邮件发送池运行。该池有不同的大小和无界队列。
-
-
启用 OAuth2 认证时,扩展组件会更严格地检查配置(见 #5539):
-
忽略
spring.mail.password属性,扩展组件会记录警告。以前,与 OAuth2 认证一起设置的密码会使扩展组件使用基本认证。 -
如果未设置
spring.mail.username、jmix.email.oauth2.client-id或jmix.email.oauth2.secret,应用程序将无法启动。以前,这些错误仅在发送电子邮件时出现。
-
地图扩展组件
-
有
featureModifyEnabled="true"的源默认不再显示 Delete 操作。在源上设置featureDeleteEnabled="true",或将 jmix.maps.ui.feature-modify-includes-delete 应用程序属性设置为true,可以为所有未设置featureDeleteEnabled的源保留以前的行为。 -
SourceFeatureDeleteEvent和addSourceFeatureDeleteListener()已从HasFeatureModify移到HasFeatureDelete。请在代码中将HasFeatureModify.SourceFeatureDeleteEvent替换为HasFeatureDelete.SourceFeatureDeleteEvent。
OIDC 和 SAML 扩展组件
自动配置的以下元素已重命名(见 #5484):
-
OidcAutoConfiguration.DefaulOidcVaadinWebSecurity→DefaultOidcVaadinWebSecurity -
SamlAutoConfiguration.DefaulSamlVaadinWebSecurity→DefaultSamlVaadinWebSecurity -
SamlAutoConfiguration中的claimsRoleMapperbean →samlAssertionRolesMapper
请更新继承这些类或按名称引用该 bean 的代码。
报表扩展组件
-
io.jmix.reports.yarg.loaders.impl.GroovyDataLoader类。扩展组件对groovy加载器类型使用JmixGroovyDataLoader。与被移除的类不同,新的类会检查jmix.core.unsafe-runtime-features-enabled和jmix.reports.groovy-enabled属性。 -
io.jmix.reports.yarg.exception包中的InitializationException和ReportingXmlException类。 -
io.jmix.reports.yarg.util.db.QueryRunner的update()和batch()方法。请改用 SpringJdbcTemplate或 JDBC。 -
io.jmix.reports.yarg.util.db.DbUtils的commitAndClose()、commitAndCloseQuietly()、rollback()、rollbackAndClose()、rollbackAndCloseQuietly()、loadDriver()、printStackTrace()和printWarnings()方法。 -
UnoConverter.createAny(Object)方法。请改用new Any(new Type(XCell.class), value)。 -
AbstractFormatter.SIMPLE_ALIAS_REGEXP和DataExtractorImpl.EMPTY_MAP字段。
扩展组件不再修改整个应用程序的 XML 处理器(见 #5755)。以前,扩展组件依赖中的 Xalan 2.7.3 和 Xerces 2.12.2 会成为默认的 JAXP TransformerFactory 和 SchemaFactory,因此使用 Hazelcast 的应用程序无法启动。现在,应用程序从 JDK 获取这些工厂。可能导致以下问题:
-
依赖 Xalan 特有 XSLT 功能的代码可能会失败。
-
处理超出 JDK 限制的 XML 可能会失败。
-
在 Java 21 上,由于 JDK-8349516 缺陷,校验带有空 CDATA 的
StAXSource会失败。例如,BPM 无法部署此类 DMN 文件(见 #5778)。
如需保留以前的工厂,请在应用程序启动前设置系统属性,例如在 main() 方法中、SpringApplication.run() 之前设置。在这种情况下,使用 Hazelcast 的应用程序会像以前一样无法启动。
System.setProperty("javax.xml.transform.TransformerFactory",
"org.apache.xalan.processor.TransformerFactoryImpl");
System.setProperty("javax.xml.validation.SchemaFactory:" + XMLConstants.W3C_XML_SCHEMA_NS_URI,
"org.apache.xerces.jaxp.validation.XMLSchemaFactory");
实体引用的加载状态
DataManager.getReference() 返回的实体实例现在仅将 id 和之后设置的属性报告为已加载(见 #5660)。以前,EntityStates.isLoaded() 对此类实例的每个属性都返回 true。
现在对于实体引用:
-
isLoaded()对除 id 和创建后设置的属性之外的所有属性返回false。 -
isLoadedSafe()返回YES或NO,并且不调用 getter。 -
isLoadedWithFetchPlan()对于包含其他属性的 fetch plan 返回false。 -
getCurrentFetchPlan()返回包含 id 和创建后设置的属性的 fetch plan。
这有以下效果:
-
引用在序列化时(在 REST、BPM 流程变量等中)仅包含 id 和设置了值的属性。
-
引用不包含在
@PostConstruct方法或字段初始化器中创建时分配的默认值。 -
将引用
DataContext.merge()到有已加载实例的上下文中时,不会用 null 替换已加载的值。
如果你的代码依赖引用将所有属性报告为已加载,则需要更新。
UI 集成测试
运行带 @UiTest 的 UI 集成测试 的 JmixUiTestExtension 现在会在每个测试后销毁 Vaadin servlet、服务上下文和 servlet 上下文(见 #5794)。以前是不会被销毁的,并会在内存中保留已关闭的 Spring 应用程序上下文,直到测试运行结束。这会产生以下影响:
-
每个测试后会调用
ServiceDestroyListener监听器。如果此类监听器(例如在VaadinServiceInitListener中添加的监听器)关闭了执行器或 bean 等共享资源,那么现在会在第一个测试后执行关闭,而后续使用同一 Spring 上下文的测试将使用已关闭的资源。 -
每个测试后,
UI.getCurrent()、VaadinSession.getCurrent()、VaadinService.getCurrent()和RequestContextHolder.getRequestAttributes()会返回null。这会影响@AfterAll方法、在@UiTest之前注册的 JUnit 扩展,以及 Spring 测试执行监听器的afterTestMethod()方法。测试类的@AfterEach方法仍能获取这些对象。 -
JmixUiTestExtension现在带有@NullMarked注解。在 Kotlin 中,未做 null 检查就调用getViewBasePackages()的代码可能无法编译。对于将该扩展的ui、vaadinSession、uiTestAuthenticator、initialView或viewBasePackages字段作为非空使用,或用可空返回类型重写其方法的子类,也是如此。