StreamResource иногда ресурс не обнаруживается при нажатии кнопки загрузки в закрывающемся диалоговом окне

Я работаю над диалоговым окном, в котором есть ссылка для загрузки динамически сгенерированного файла через StreamResource, и когда пользователь нажимает кнопку загрузки, диалоговое окно должно закрываться. Достаточно просто. Однако, когда пользователь открывает диалоговое окно и нажимает кнопку загрузки, иногда созданный файл загружается успешно. Проблема в том, что в других случаях пользователь может случайно столкнуться с сообщением об ошибке «ресурс / файл не найден» при попытке загрузить созданный файл. Ниже фрагмент кода, который воспроизводит проблему.

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

Таким образом, пользователь может иногда сталкиваться с сообщением об ошибке ресурс не найден при нажатии кнопки загрузки.

Изображение «Ресурс не найден для пути»

Самое смешное, что если я закрою диалог в методе 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% случаев, а второй фрагмент кода работает, почему?


person Julius Koljonen    schedule 14.03.2019    source источник


Ответы (1)


За кулисами StreamResource работает так, что генерирует временный URL-адрес и добавляет экземпляр ресурса на карту с URL-адресом в качестве ключа. Затем это используется для поиска нужного материала для ответа, когда браузер делает запрос по этому URL-адресу.

Чтобы предотвратить утечку памяти на неопределенный срок, он реализован таким образом, что ресурс удаляется с этой глобальной карты сразу после отсоединения компонента «владелец». В вашем случае anchor является владельцем, и он действительно отключается, когда диалог закрывается. Наблюдаемая вами случайность зависит от того, какой запрос первым достигает сервера.

person Leif Åstrand    schedule 15.03.2019
comment
Отличный ответ! Итак, возвращаюсь к моей первоначальной цели - закрывать диалоговое окно, когда пользователь нажимает кнопку загрузки. По вашему мнению, второй фрагмент кода - хороший подход или есть лучший способ реализовать эту функциональность? - person Julius Koljonen; 15.03.2019
comment
Возможно, вам поможет этот способ решения проблемы. Вы можете добавить невидимый якорь рядом с кнопкой загрузки, которая открывает диалоговое окно. - person Steffen Harbich; 31.07.2019