3.5.2.1.16. 多文件上传控件

FileMultiUploadField 组件允许用户把文件上传到服务器。这个组件是个按钮;用户点击时,系统自带的文件选择器会弹出,此时用户可以选择多个文件来上传。

gui multipleUpload

该组件对应的 XML 名称: multiUpload

下面是一个使用 FileMultiUploadField 的示例。

  • 在界面的 XML 描述中声明这个组件:

    <multiUpload id="multiUploadField" caption="Upload Many"/>
  • 在界面控制器中,需要注入该组件本身,还需要注入 FileUploadingAPIDataManager 这两个接口。

    @Inject
    private FileMultiUploadField multiUploadField;
    @Inject
    private FileUploadingAPI fileUploadingAPI;
    @Inject
    private Notifications notifications;
    @Inject
    private DataManager dataManager;
    
    @Subscribe
    protected void onInit(InitEvent event) { (1)
    
        multiUploadField.addQueueUploadCompleteListener(queueUploadCompleteEvent -> { (2)
            for (Map.Entry<UUID, String> entry : multiUploadField.getUploadsMap().entrySet()) { (3)
                UUID fileId = entry.getKey();
                String fileName = entry.getValue();
                FileDescriptor fd = fileUploadingAPI.getFileDescriptor(fileId, fileName); (4)
                try {
                    fileUploadingAPI.putFileIntoStorage(fileId, fd); (5)
                } catch (FileStorageException e) {
                    throw new RuntimeException("Error saving file to FileStorage", e);
                }
                dataManager.commit(fd); (6)
            }
            notifications.create()
                    .withCaption("Uploaded files: " + multiUploadField.getUploadsMap().values())
                    .show();
            multiUploadField.clearUploads(); (7)
        });
    
        multiUploadField.addFileUploadErrorListener(queueFileUploadErrorEvent -> {
            notifications.create()
                    .withCaption("File upload error")
                    .show();
        });
    }
    1 onInit() 方法里面,添加了事件监听器,这样可以在文件上传成功或者出错时做出反馈。
    2 该组件将所有选择的文件上传到客户端层(client tier) 的临时存储(temporary storage)并且调用通过 addQueueUploadCompleteListener() 方法添加的监听器。
    3 在这个监听器里面,会调用 FileMultiUploadField.getUploadsMap() 方法获得临时存储的文件标识和文件名映射关系的 map。
    4 然后,通过调用 FileUploadingAPI.getFileDescriptor() 为每一条 map 记录创建相应的 FileDescriptor 对象。 com.haulmont.cuba.core.entity.FileDescriptor (别跟 java.io.FileDescriptor 混淆了) 是一个持久化实体,唯一定义一个上传的文件,并且也用这个类从系统下载文件。
    5 FileUploadingAPI.putFileIntoStorage() 方法用来把文件从客户端层的临时存储移动到 FileStorage。这个方法的参数是临时存储中文件的标识符和对应的 FileDescriptor 对象。
    6 在将文件上传到 FileStorage 之后,通过调用 DataManager.commit() 方法将 FileDescriptor 实例存到数据库。这个方法的返回值可以用来设置给一个实体的属性,这个属性关联此文件。这里,FileDescriptor 简单的保存在数据库。上传的文件可以通过 Administration > External Files 界面查看。
    7 完成整个上传过程之后,文件列表需要通过调用 clearUploads() 方法清空以便下一次上传再使用。

下面列出能跟踪上传进度的监听器:

  • FileUploadErrorListener

  • FileUploadStartListener

  • FileUploadFinishListener

  • QueueUploadCompleteListener

最大可上传的文件大小是由 cuba.maxUploadSizeMb 应用程序属性定义的,默认是 20MB。如果用户选择了更大的文件的话,会有相应的提示信息,并且中断上传过程。

multiUpload 属性:

  • accept XML 属性 (或者相应的 setAccept() 方法) 用来设置文件选择对话框里面的文件类型掩码,但是用户还是可以选择“所有文件”来上传任意文件。

    这个属性的值需要是以英文逗号分隔的文件后缀名,比如:*.jpg,*.png

  • fileSizeLimit XML 属性 (或者相应的 setFileSizeLimit() 方法) 用来设置最大允许上传的文件大小。这个设置是针对每一个文件都有效的。

    <multiUpload id="multiUploadField" fileSizeLimit="200000"/>
  • permittedExtensions XML 属性 (或者相应的 setPermittedExtensions() 方法) 设置允许的文件扩展名白名单。

    这个属性的值需要是字符串的集合,其中每个字符串是以 . 开头的允许的文件扩展名,比如:

    uploadField.setPermittedExtensions(Sets.newHashSet(".png", ".jpg"));
  • dropZone XML 属性允许设置一个特殊的 BoxLayout 用来作为从浏览器外部拖拽文件可以放置的目标容器区域。如果这个容器的样式没有特殊设置,当文件被拖拽到这块区域的时候,这个容器会被高亮显示,否则目标区域不会显示。

参考 加载和显示图片 有更多复杂的使用上传文件的例子。