最近更新
本章节包含 Jmix 框架和 Studio 1.5 的新功能介绍,以及在升级框架版本时需要注意的一些破坏性改动。
如何升级
如需新建 Jmix 1.5 项目或者升级已有项目,需要使用 Studio 1.5 以上版本。因此,请先 升级 Jmix Studio 插件。 IntelliJ IDEA 的最低版本要求是 2022.3。 |
参阅 升级项目 部分的介绍了解如何使用 Studio 升级项目。自动升级迁移过程会对项目做如下修改:
-
升级 Jmix BOM 的版本,BOM 又定义了所有依赖的版本。
-
升级 Jmix Gradle 插件的版本。
-
在
gradle/wrapper/gradle-wrapper.properties
文件中升级 Gradle wrapper 的版本至 7.6。 -
将所有必须包含的内容添加至根(root) Liquibase Changelog 文件中。
-
application.properties
中添加了main.liquibase.change-log
配置。 -
将所有的
jmix.liquibase.*
应用程序属性都重命名为main.liquibase.*
。 -
更新附件数据存储的 Liquibase 配置(如果有的话)。
-
在 Flow UI 的项目中创建
UiMinimalRole
角色。 -
如果项目中使用了表格导出操作 / GrapesJS 扩展组件,则会修改这两个制件的名称。
请参考破坏性改动的 完整列表,并在升级后做相应修复。
新功能和改进
Liquibase Changelog
主数据存储的 root Liquibase changelog 现在包含 include
指令,用于引入项目中扩展组件的更改日志。这样一来,更改日志能兼容 Liquibase Gradle 插件 和 Liquibase CLI,并可以在不使用 Studio 或者不直接运行程序的情况下运行 Liquibase,例如在 CI 服务器中。
项目必须用 main.liquibase.change-log
配置 root 更改日志的路径,示例:
main.liquibase.change-log=com/company/demo/liquibase/changelog.xml
当添加扩展组件时,Studio 会自动维护更改日志的引入。另外,当应用程序启动时,会检查 root 更改日志中的引入项是否与项目的扩展组件匹配。如果检测到不匹配项,Studio 会显示一个通知弹窗,建议添加或删除引入。这里可以选择忽略,忽略之后不会再次出现对已忽略引入的提示。
Studio 的版本迁移程序会自动更新 root 更改日志并设置正确的应用程序属性。
更多信息,请参阅 下面 的破坏性改动章节。
Flow UI
Flow UI 模块更新至 Vaadin 23.3。
在 Flow UI 中集成了下列 Vaadin 组件:
-
TabSheet →
JmixTabSheet
(XML 元素:tabSheet
)<tabSheet width="100%"> <tab id="mainTab" label="Main"> <formLayout id="form" dataContainer="userDc">...</formLayout> </tab> <tab id="additionalTab" label="Onboarding steps"> <vbox> <hbox>...</hbox> <dataGrid width="100%" dataContainer="stepsDc">...</dataGrid> </vbox> </tab> </tabSheet>
-
MultiSelectComboBox →
JmixMultiSelectComboBox
(XML 元素:multiSelectComboBox
)<instance id="productDc" class="com.company.demo.entity.Product"> <fetchPlan extends="_base"> <property name="tags" fetchPlan="_base"/> </fetchPlan> <loader/> </instance> <collection class="com.company.demo.entity.Tag" id="allTagsDc"> <fetchPlan extends="_base"/> <loader id="allTagsDl"> <query> <![CDATA[select e from Tag e]]> </query> </loader> </collection> <!-- ... --> <formLayout id="form" dataContainer="productDc"> <textField id="nameField" property="name"/> <multiSelectComboBox property="tags" itemsContainer="allTagsDc"/> </formLayout>
-
Upload →
FileStorageUploadField
(XML 元素:fileStorageUploadField
)和FileUploadField
(XML 元素:fileUploadField
)<fileStorageUploadField id="uploadField" dataContainer="userDc" property="picture"/>
-
Image →
JmixImage
(XML 元素:image
)<image id="image" dataContainer="userDc" property="picture" height="280px" width="200px" classNames="user-picture"/>
-
很多组件现在支持 Tooltip,示例:
<textField id="nameField" property="name"> <tooltip text="Product name" position="BOTTOM_START"/> </textField>
在 Studio 中,通过 Jmix UI 组件面板中的 Add 按钮添加 tooltips。
输入对话框
Dialogs 接口增加了 createInputDialog()
方法,支持使用任意参数展示一个输入对话框。示例:
dialogs.createInputDialog(this)
.withParameters(
stringParameter("name").withLabel("Name"),
intParameter("age").withLabel("Age"))
.withCloseListener(dialogCloseEvent -> {
if (dialogCloseEvent.closedWith(DialogOutcome.OK)) {
System.out.println("Name: " + dialogCloseEvent.getValue("name"));
System.out.println("Age: " + dialogCloseEvent.getValue("age"));
}
})
.open();
后台任务
经典 UI(Vaadin 8)中可以执行不阻塞用户的异步后台任务,Flow UI 现在也支持该机制。
执行后台任务并在一个 label 中展示进度的示例:
@Autowired
private BackgroundWorker backgroundWorker;
@ViewComponent
private Span taskProgress;
@Subscribe("testBtn")
public void onTestBtnClick(ClickEvent<Button> event) {
BackgroundTaskHandler<Void> handler = backgroundWorker.handle(new SampleTask(15, null, 10));
handler.execute();
}
protected class SampleTask extends BackgroundTask<Integer, Void> {
int count;
public SampleTask(long timeoutSeconds, View<?> view, int count) {
super(timeoutSeconds, view);
this.count = count;
}
@Override
public Void run(TaskLifeCycle<Integer> taskLifeCycle) throws Exception {
for (int i = 1; i < count + 1; i++) {
Thread.sleep(1000);
taskLifeCycle.publish(i);
}
return null;
}
@Override
public void progress(List<Integer> changes) {
taskProgress.setText(changes.get(0) + "");
}
}
运行后台任务并在模态弹窗展示进度的示例:
@Autowired
private Dialogs dialogs;
@Subscribe("testBtn")
public void onTestBtnClick(ClickEvent<Button> event) {
dialogs.createBackgroundTaskDialog(new SampleTask(15, this, 10))
.withTotal(10)
.withCancelAllowed(true)
.open();
}
protected class SampleTask extends BackgroundTask<Integer, Void> {
int count;
public SampleTask(long timeoutSeconds, View<?> view, int count) {
super(timeoutSeconds, view);
this.count = count;
}
@Override
public Void run(TaskLifeCycle<Integer> taskLifeCycle) throws Exception {
for (int i = 1; i < count + 1; i++) {
Thread.sleep(1000);
taskLifeCycle.publish(i);
}
return null;
}
}
支持 Flow UI 的扩展组件
以下扩展组件目前已经支持 Flow UI:
-
Multitenancy - 多租户
-
Quartz - 定时任务
-
Application Settings - 应用程序设置
-
Grid Export Actions - 表格导出操作(支持导出所有数据,参阅 Excel 导出)。
Flow UI 菜单设计器
Flow UI 菜单设计器的 “Single mode” 做了很大提升。当切换至 “Single mode” 时,Studio 仍然会提供添加项目扩展组件菜单的功能。左侧会有单独的面板展示可用的菜单项,可以拖拽至菜单目录中,方便自定义组合菜单。
Excel 导出
表格导出操作组件现在支持将当前过滤条件产生的所有数据导出至 Excel 文件。excelExport
操作会展示包含 All rows | Current page | Selected rows 选项的弹窗。
以前的版本仅支持导出当前能看到的数据或者选中的数据。
预览功能
Flow UI 通用过滤器
GenericFilter
组件(XML 元素:genericFilter
)支持用户通过运行时创建的任意条件对数据进行过滤。
示例:
<facets>
<dataLoadCoordinator auto="true"/>
<queryParameters>
<genericFilter component="filter"/>
</queryParameters>
</facets>
<layout>
<genericFilter id="filter" dataLoader="usersDl"
summaryText="My filter">
<responsiveSteps>
<responsiveStep minWidth="0" columns="1"/>
<responsiveStep minWidth="800px" columns="2"/>
<responsiveStep minWidth="1200px" columns="3"/>
</responsiveSteps>
</genericFilter>
queryParameters
facet 中需要有 genericFilter
元素,用来将过滤器的状态反映至 URL 参数中。这样一来,当用户从详情视图返回列表视图或者刷新浏览器网页时,能使用与之前一样的过滤器条件。
现在通用过滤器仅支持属性条件。经典 UI 过滤器的其他功能(JPQL、自定义条件、分组、保存过滤器配置等)将在下一版本提供。
破坏性改动
扩展组件重命名
表格导出操作
修改了 starter 制件名:
-
io.jmix.ui:io.jmix.ui:jmix-ui-export-starter
→io.jmix.gridexport:jmix-gridexport-ui-starter
Liquibase 属性
-
jmix.liquibase.*
前缀更名为main.liquibase.*
,目的是为了遵循数据源属性的命名模式(例如,main.datasource.url
,这里main
是数据存储名称)。如果添加一个名为second
的数据存储,Liquibase 配置属性则是second.liquibase.*
。 -
application.properties
必须 包含每个数据存储的 root Liquibase 更改日志的路径。示例:main.liquibase.change-log=com/company/demo/liquibase/changelog.xml second.liquibase.change-log=com/company/demo/liquibase/second-changelog.xml
数据存储配置
附件数据存储的配置必须更改。
LiquibaseChangeLogProcessor
类已被移除。
以前的版本中,如果我们定义一个附加数据存储并设置 DB Schema Management 为 Create and Update(即,通过 Jmix 创建并维护该附件数据存储),则 Studio 会生成一个类似下面这样定义的 bean:
@Bean
public SpringLiquibase thirdLiquibase(
LiquibaseChangeLogProcessor processor,
@Qualifier("thirdDataSource") DataSource dataSource) {
return JmixLiquibaseCreator.create(
dataSource,
new LiquibaseProperties(),
processor,
"third");
}
新的 bean 定义必须与下面这个类似(“third” 是数据存储名称):
@Bean("thirdLiquibaseProperties")
@ConfigurationProperties(prefix = "third.liquibase")
public LiquibaseProperties thirdLiquibaseProperties() {
return new LiquibaseProperties();
}
@Bean("thirdLiquibase")
public SpringLiquibase thirdLiquibase(
@Qualifier("thirdDataSource") DataSource dataSource,
@Qualifier("thirdLiquibaseProperties") LiquibaseProperties liquibaseProperties) {
return JmixLiquibaseCreator.create(
dataSource,
liquibaseProperties);
}
Formatters 中对消息键值的引用
我们修复了在 XML 中定义的 formatter 对外部消息引用的错误处理问题。
现在,与其他消息一样,对于 msg://myFormat
引用,将查找当前界面消息组内的键值,例如,com.company.app.screen.foo/myFormat
。对带有三个斜杠前缀的键值,将查找没有组的消息,例如 myFormat
。
项目如果需要采用这个改动,需要查找所有这类用法,并将双斜杠改成三斜杠,示例:
<formatter>
<date format="msg:///myDateFormat"/>
</formatter>
Flow UI 项目中的 UiMinimalRole 角色
UiMinimalRole
定义访问登录页和主页面(Flow UI 称为视图)的权限。为了支持能修改这些视图,角色从框架移至项目。示例:
package com.company.demo.security;
import io.jmix.core.entity.KeyValueEntity;
import io.jmix.security.model.*;
import io.jmix.security.role.annotation.*;
import io.jmix.securityflowui.role.annotation.ViewPolicy;
@ResourceRole(name = "Flow UI: minimal access", code = UiMinimalRole.CODE, scope = SecurityScope.UI)
public interface UiMinimalRole {
String CODE = "flowui-minimal";
@ViewPolicy(viewIds = "MainView")
void main();
@ViewPolicy(viewIds = "LoginView")
@SpecificPolicy(resources = "flowui.loginToUi")
void login();
@EntityPolicy(entityClass = KeyValueEntity.class, actions = EntityPolicyAction.READ)
@EntityAttributePolicy(entityClass = KeyValueEntity.class, attributes = "*", action = EntityAttributePolicyAction.VIEW)
void keyValueEntity();
}
Flow UI DataGrid
-
DataGrid
和TreeDataGrid
的getColumns()
方法现在仅返回那些用户有权限看到的列(由于安全配置引起的不可见)。以前的版本中,该方法会返回所有的列,包括隐藏列。 -
由于安全控制隐藏的列不会修改其可见性配置。以前的版本中,这种情况会设置
visible
属性为 false。
ui-test-assist
ui-test-assist
模块不再提供对 Spock 和 Groovy 的传递依赖。此外,也不包含 UiTestAssistSpecification
、ScreenSpecification
和 TestMainScreen
类。
Spock 和 Groovy 已经移至 ui-test-assist-spock
模块。
如果你的项目包含基于 ScreenSpecification
或 UiTestAssistSpecification
的测试用例,请在 build.gradle
添加如下依赖:
testImplementation 'io.jmix.ui:jmix-ui-test-assist-spock'
并修改对 ScreenSpecification
、UiTestAssistSpecification
、TestMainScreen
的 import 为 io.jmix.ui.testassistspock.*
。