Vaadin 14 - 在文件上传时显示错误,就像在任何其他输入字段中一样

Vaadin 14 - Show errors at file upload like at any other input field

先简单提问: 如何以与所有其他输入字段相同的样式显示上传错误消息?

详情: Vaadin 14.1.5 提供上传元素:https://vaadin.com/components/vaadin-upload/java-examples

我使用以下代码创建了一个上传字段:

    MemoryBuffer buffer = new MemoryBuffer();
    Upload upload = new Upload(buffer);

此行强制执行文件过大的失败消息:

    upload.setMaxFileSize(1);

使用 UploadI18N 完成翻译(参见 https://vaadin.com/api/platform/14.1.5/com/vaadin/flow/component/upload/UploadI18N.html):

    upload.setI18n(buildMyUploadI18N(Locale.GERMAN));

通过所有的侦听器,我可以在服务器端接收和显示错误消息,例如拒绝:

    upload.addFileRejectedListener(new ComponentEventListener<FileRejectedEvent>() {
        @Override
        public void onComponentEvent(FileRejectedEvent event) {
            Notification.show(event.getErrorMessage());
        }
    });

这段代码工作正常,当要上传的文件太大时,系统会向用户显示一条通知消息。

但是:此验证消息行为与用户习惯的不同:输入字段旁边的红色文本(见屏幕截图)。

如何以与所有其他输入字段相同的样式显示上传错误消息?

我目前的解决方法如下:

除了上传元素之外,系统还创建了一个禁用的文本字段

    TextField filenameField = new TextField();
    filenameField.setEnabled(false);

上传元素中的每个错误侦听器然后在 TextField 中设置错误消息:

    upload.addFileRejectedListener(new ComponentEventListener<FileRejectedEvent>() {
        @Override
        public void onComponentEvent(FileRejectedEvent event) {
            filenameField.setInvalid(true);
            filenameField.setErrorMessage(event.getErrorMessage());
        }
    });

    upload.addFailedListener(new ComponentEventListener<FailedEvent>() {
        @Override
        public void onComponentEvent(FailedEvent event) {
            filenameField.setInvalid(true);
            filenameField.setErrorMessage(event.getReason().getMessage());
        }
    });

并在成功时重置无效状态并设置新文件名:

    upload.addSucceededListener(event -> {
        filenameField.setValue(StringUtils.trimToEmpty(event.getFileName()));
        filenameField.setInvalid(false);
    });

这是它的样子 - 不是我的首选解决方案(因为文件名不是错误的,而是文件大小),但目前这对我来说没问题:

另一种选择是使用 Paragraph,如您链接的示例页面中所示。它的源代码可以在这里找到:addRejectedListener

因此,一旦被拒绝的侦听器被调用,添加一个带有红色文本的段落,并可能将上传背景设置为粉红色(或您希望它具有的任何其他 color/style)。下面是该方法的简化版本(您应该将样式放在单独的 css 文件中,并 set/remove 一个 class 上传)


import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.HtmlComponent;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.upload.Upload;
import com.vaadin.flow.component.upload.receivers.MemoryBuffer;
import com.vaadin.flow.router.Route;


@Route("multiuploadView")
public class MultiFileUploadView extends VerticalLayout {

    Div output = new Div();
    Upload upload;
    public MultiFileUploadView(){
        MemoryBuffer buffer = new MemoryBuffer();
        upload = new Upload(buffer);
        upload.setMaxFiles(1);
        upload.setDropLabel(new Label("Upload a 300 bytes file in .csv format"));
        upload.setAcceptedFileTypes("text/csv");
        upload.setMaxFileSize(300);

        upload.addFileRejectedListener(event -> {
            Paragraph component = new Paragraph();
            showOutput(event.getErrorMessage(), component, output);
        });

        add(upload,output);
    }

    private void showOutput(String text, Component content,
                            HasComponents outputContainer) {
        outputContainer.removeAll();
        HtmlComponent p = new HtmlComponent(Tag.P);
        p.getElement().setText(text);
        p.getElement().getStyle().set("color","red");
        upload.getElement().getStyle().set("background","pink");

        outputContainer.add(p);
        outputContainer.add(content);
    }
}

这看起来像这样:

但是,除此之外,我会说你的解决方法几乎是一个人可以做的:)