在关闭对话框中单击下载按钮时有时找不到 StreamResource 资源 window

StreamResource sometimes resource not found when clicking download button in a closing dialog window

我正在开发一个对话框,其中下载了 link 动态生成的文件 通过 StreamResource,当用户点击下载按钮时,对话框应该关闭。 很简单。但是,当用户打开对话框并单击下载按钮时 有时 创建的文件会成功下载。问题是在其他时候,用户在尝试下载创建的文件时可能会随机遇到 "resource/file not found" 错误消息。下面是重现问题的代码片段。

public class HomeView extends VerticalLayout{

Dialog dialog;

public HomeView() {
    //Set up dialog
    dialog = new Dialog();
    Button downloadButton = new Button("Download");
    //This might be the problem. Dialog might be closed before the download even starts?
    downloadButton.addClickListener(click -> dialog.close());
    Anchor anchor = new Anchor();
    anchor.add(downloadButton);
    anchor.setHref(new StreamResource("file", () -> createInputStream()));
    dialog.add(anchor);

    //Add a button to open dialog
    Button openDialog = new Button("Open Dialog");
    openDialog.addClickListener(click -> dialog.open());
    add(openDialog);
}

private InputStream createInputStream() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        outputStream.write("text".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
    return new ByteArrayInputStream(outputStream.toByteArray());
}

所以用户在点击下载时有时可能会遇到找不到资源的错误消息。

"Resource is not found for path" image

有趣的是,如果我在 createInputStream() 方法中关闭对话框,我不会收到错误消息。下面举个例子。

public class HomeView extends VerticalLayout{

Dialog dialog;

public HomeView() {
    dialog = new Dialog();
    Button downloadButton = new Button("Download");
    //Commented out
    //downloadButton.addClickListener(click -> dialog.close());
    Anchor anchor = new Anchor();
    anchor.add(downloadButton);
    anchor.setHref(new StreamResource("file", () -> createInputStream()));
    dialog.add(anchor);

    Button openDialog = new Button("Open Dialog");
    openDialog.addClickListener(click -> dialog.open());
    add(openDialog);
}

private InputStream createInputStream() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        outputStream.write("text".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
    //Close the dialog here
    dialog.close();
    return new ByteArrayInputStream(outputStream.toByteArray());
}

现在无论我点击下载按钮多少次,我都没有收到资源错误消息,对话框仍然按预期关闭。

我正在使用 Vaadin 13.0.1。

所以最后我有这个问题。 第一个代码片段在 100% 的时间都不起作用,但第二个代码片段似乎可以,为什么?

在幕后,StreamResource 会生成一个临时的 URL 并将资源实例添加到以 URL 作为键的映射中。然后,当浏览器向 URL.

发出请求时,这将用于查找要放入响应中的正确内容

为了防止这种情况无限期地泄漏内存,实现后,当“所有者”组件分离时,资源会立即从该全局映射中删除。在您的情况下, anchor 是所有者,当对话框关闭时它确实是分离的。您观察到的随机性取决于哪个请求最先到达服务器。

因此,锚点不应该出现在对话框中,而是例如作为视图本身的不可见组件,您可以在按钮单击事件中触发它。 Gist 中有一个完整的代码示例:

https://gist.github.com/TatuLund/0a0e7bdc1d182394c99fe2adfa3e7c6e