简体   繁体   English

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

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

I am working on a dialog which has a download link to dynamically generated file via StreamResource and when user clicks on the download button the dialog should close.我正在处理一个对话框,该对话框具有通过 StreamResource 动态生成的文件的下载链接,当用户单击下载按钮时,该对话框应关闭。 Simple enough.很简单。 However when user opens the dialog and clicks on the download button sometimes the created file is downloaded successfully.但是,当用户打开对话框并单击下载按钮时,有时会成功下载创建的文件。 Problem is that on other times user might encounter "resource/file not found" error message randomly when attempting to download created file.问题是,在其他时候,用户在尝试下载创建的文件时可能会随机遇到“找不到资源/文件”错误消息。 Below a code snippet that reproduces the problem.在重现问题的代码片段下方。

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());
}

So user might sometimes encounter resource not found error message when pressing download.因此,用户有时可能会在按下下载时遇到资源未找到错误消息。

"Resource is not found for path" image “找不到路径的资源”图像

The funny thing is that if I close the dialog in createInputStream() method I don't get the error message.有趣的是,如果我在 createInputStream() 方法中关闭对话框,我不会收到错误消息。 Below an example.下面举个例子。

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());
}

Now no matter how many times I click on the download button I don't get the resource error message and dialog still closes as intended.现在,无论我点击下载按钮多少次,我都没有收到资源错误消息,并且对话框仍然按预期关闭。

I'm using Vaadin 13.0.1.我正在使用 Vaadin 13.0.1。

So in the end I have this question.所以最后我有这个问题。 The first code snippet doesn't work 100% of the time but the second code snippet seems to, why?第一个代码段不能 100% 工作,但第二个代码段似乎可以,为什么?

Behind the scenes, StreamResource works so that it generates a temporary URL and adds the resource instance to a map with the URL as the key.在幕后, StreamResource会生成一个临时 URL,并将资源实例添加到以 URL 作为键的映射中。 This is then used to find the right stuff to put in the response when the browser makes a request to that URL.然后,当浏览器向该 URL 发出请求时,这将用于查找要放入响应中的正确内容。

To prevent this from leaking memory indefinitely, it is implemented so that the resource is removed from that global map immediately when the "owner" component is detached.为了防止这种情况无限期地泄漏内存,它被实现为在“所有者”组件分离时立即从该全局映射中删除资源。 In your case, anchor is the owner and it is indeed detached when the dialog is closed.在您的情况下, anchor是所有者,并且在关闭对话框时它确实是分离的。 The randomness that you're observing depends on which request reaches the server first.您观察到的随机性取决于哪个请求首先到达服务器。

Hence the Anchor should not be in the Dialog, but for example as invisible component in the view itself, which you trigger in the Button click event.因此,Anchor 不应该在 Dialog 中,而是作为视图本身中的不可见组件,您在 Button click 事件中触发。 There is a complete code example in Gist here: Gist 中有一个完整的代码示例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM