6. 处理图片

本节中,我们将为 User 实体添加 picture 属性并学习如何上传并在 UI 展示图片。

添加文件属性

Jmix 支持将上传的文件存储在数据库之外的所谓 文件存储(File Storage) 中。文件存储最简单的情况就是文件系统的一个带有特殊结构的文件夹。将文件存储中的文件与实体关联,需要为实体创建一个 FileRef 类型的属性。

我们创建一个属性用于管理用户的照片。

如果你的应用程序正在运行,先通过主工具栏的 Stopsuspend)按钮停止运行。

Jmix 工具窗口双击 User 实体并选择其最后一个属性(我们要在最后添加新属性):

Attributes 工具栏中,点击 Addadd)。弹出的 New Attribute 对话框中,Name 字段填写 picture,然后在 Type 下拉框中选择 FileRef

attribute 2

Length 字段使用默认值(1024)即可。对于 FileRef 属性来说,列长度是用来保存文件引用而非文件本身,因此并不是限定文件的大小。

点击 OK

然后选中 picture 属性,在 Attributes 工具栏中点击 Add to Viewsadd attribute to screens)按钮:

出现的对话框中会显示所有用于展示 User 实体的视图。我们选择 User.detail 视图并点击 OK

Studio 会在 User.detail 视图的 formLayout 中添加 pictureField 组件:

<formLayout id="form" dataContainer="userDc">
    ...
    <fileStorageUploadField id="pictureField" property="picture"/>
</formLayout>

点击主工具栏中的 Debugstart debugger)按钮启动应用程序。

在运行应用程序之前,Studio 会生成 Liquibase 更改日志:

run app 1

可以看到,更改日志包含了一条增加 USER_PICTURE 列的语句。列类型为 VARCHAR(1024),因为文件引用实际上是一个字符串。

点击 Save and run

Studio 会先执行更改日志,再构建和运行应用程序。

应用程序准备好后,在浏览器打开 http://localhost:8080 并使用 admin / admin 凭证登录。

点击主菜单的 ApplicationUsers

选择一个用户并点击 Edit。表单会显示一个用于上传图片的 UI 控件:

run app 3

表单内展示图片

本小节内,我们将改进详情视图,在表单内展示上传的图片。

首先,我们在可收放的 Details 布局中放入 fileStorageUpload

form 1

现在这个空间并不是直接位于 formLayout 中(formLayout 为内部组件定义了数据容器),因此,我们需要显式地为上传控件设置 dataContainer

form 4

然后在 fileStorageUpload 组件下方添加 image 组件,并设置如下属性:

<details summaryText="Picture">
    <hbox>
        <fileStorageUploadField id="pictureField" dataContainer="userDc" property="picture"/>
        <image id="image" property="picture" dataContainer="userDc" height="10em" width="10em"
            classNames="user-picture"/>
    </hbox>
</details>
  • dataContainer="userDc" property="picture" 属性将 image 组件与 User 实体的 picture 属性进行关联。

  • classNames="user-picture" 是定义了一个 CSS 类。

从 Jmix 工具窗口的 User InterfaceThemes 打开 onboarding.css 文件,定义 user-picture 类:

form 5

object-fit: contain 属性可以确保图片能占满所有空间并保持宽高比。

.user-picture {
    object-fit: contain;
}

按下 Ctrl/Cmd+S 并切换至运行的程序。刷新用户详情视图,试试上传一个图片:

form 2

在数据网格中展示图片

我们在 User.list 视图中的数据网格中添加一列用来展示图片。

UserListView 类添加以下字段:

@ViewComponent
private DataGrid<User> usersDataGrid;

@Autowired
private UiComponents uiComponents;

@Autowired
private FileStorage fileStorage;
可以使用编辑器顶部操作面板内的 Inject 按钮为视图控制器注入依赖和 Spring bean。

Generate Handler 操作生成 InitEvent 的处理方法并按下面内容实现:

@Subscribe
public void onInit(final InitEvent event) {
    Grid.Column<User> pictureColumn = usersDataGrid.addComponentColumn(user -> { (1)
        FileRef fileRef = user.getPicture();
        if (fileRef != null) {
            Image image = uiComponents.create(Image.class); (2)
            image.setWidth("30px");
            image.setHeight("30px");
            StreamResource streamResource = new StreamResource(
                    fileRef.getFileName(),
                    () -> fileStorage.openStream(fileRef));
            image.setSrc(streamResource); (3)
            image.setClassName("user-picture");

            return image; (4)
        } else {
            return new Span();
        }
    });
    pictureColumn.setFlexGrow(0); (5)
    pictureColumn.setWidth("40px");
    usersDataGrid.setColumnPosition(pictureColumn, 0); (6)
}
1 addComponentColumn() 方法使接收一个 lambda 函数用于创建 UI 组件并显示在列中。Lambda 函数的参数是当前行的实体。
2 使用 UiComponents 工厂创建 Image 组件实例。
3 图片组件从 Userpicture 字段获取文件地址,然后从文件存储中获取内容。
4 lambda 函数返回可视化组件。
5 设置新列的宽度。
6 设置新列在数据网格中的位置。

按下 Ctrl/Cmd+S 保存修改然后切换至运行中的程序。刷新用户列表视图。可以在第一列看到用户的图片:

table 3

小结

本节中,我们增加了上传和显示用户图片的功能。

学习内容: