{Java} Vaadin 14 - Обнаружение ухода пользователя (закрывает вкладку, f5, et c) - PullRequest
2 голосов
/ 06 февраля 2020

Я сейчас использую Vaadin Flow версия 14 (https://github.com/vaadin/platform/releases/tag/14.0.0)
Я запускаю Java версия 1.8.0_231, 64 бит.

Я просто хочу иметь возможность обнаруживать (в java!) Всякий раз, когда пользователь выполняет одно из следующих действий:

  • Закрытие текущей вкладки браузера (или его браузера)
  • Кликает F5 на клавиатуре или нажимает кнопку Refre sh в браузере
  • Кликает ссылку (или что-нибудь еще), которая перенаправляет их с моего сайта

I ' Мы пробовали много разных вещей, чтобы обнаружить это. Единственное, что мне удалось обнаружить, - это когда истекает текущая VaadinSession (которую я могу изменить, выполнив VaadinSession.getCurrent().getSession().setMaxInactiveInterval(15)). Это истекает через 15 секунд после каждого сеанса (в моем случае 15 - просто число тестирования).



С Vaadin 8 , я думаю, вы можете просто сделать это и это будет работать из коробки:

        JavaScript.getCurrent().execute(
            "function closeListener() { catchClose(); } " +
                    "window.addEventListener('beforeunload', closeListener); " +
                    "window.addEventListener('unload', closeListener);"
        );
        JavaScript.getCurrent().addFunction("catchClose", arguments ->
        {
            System.out.println("user has quit :o");
        });

Я не могу использовать это, хотя я использую Vaadin 14 , а не 8 .


Я пытался добавить это в свой класс View:

    @Override
    protected void onDetach(DetachEvent detachEvent)
    {
        System.out.println("onDetach " + detachEvent);
    }

. Оно печатает это сообщение только по истечении сеанса (15 секунд в моем случае). Даже если я не закрою страницу.


Я пытался реализовать BeforeLeaveObserver / BeforeLeaveListener и переопределить это:

    @Override
    public void beforeLeave(BeforeLeaveEvent beforeLeaveEvent)
    {
        System.out.println("beforeLeave");
    }

Это никогда не печатается.


Я также пробовал все это, но они не делают то, что мне нужно:

        VaadinResponse.getCurrent().getService().addUIInitListener(e ->
        {
            System.out.println("1 addUIInitListener : " + e);
            e.getUI().addBeforeLeaveListener(e2 ->
            {
                System.out.println("1.1 addBeforeLeaveListener : " + e2);
            });
            e.getUI().addDetachListener(e2 ->
            {
                System.out.println("1.2 addDetachListener : " + e2);
            });
        });
        VaadinResponse.getCurrent().getService().addServiceDestroyListener(e ->
        {
            System.out.println("2 addServiceDestroyListener : " + e);
        });
        VaadinResponse.getCurrent().getService().addSessionDestroyListener(e ->
        {
            System.out.println("3 addSessionDestroyListener : " + e);
        });

1 addUIInitListener печатается, когда пользователь загружает страницу.
1.1 addBeforeLeaveListener никогда печатает.
2 addServiceDestroyListener никогда не печатает. Сервис - это не то же самое, что Сессия. Имеет смысл tho.
1.2 и 3 addSessionDestroyListener печатные издания некоторое время спустя. Занимает 15-30 секунд.


Разве нет способа обнаружить это в основном мгновенно? : /

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

В зависимости от того, какие браузеры вам нужно поддерживать, вы также можете взглянуть на Beacon API , который поддерживается всеми современными браузерами, но не IE11.

Преимущество API маяка заключается в том, что он не блокируется. С прослушивателем unload клиент ждет ответа, прежде чем закрыть вкладку, что может быть плохо для пользователя.

Тем не менее, как упомянул Tatu, если происходит сбой браузера или пользователь теряет соединение inte rnet, все Вы можете подождать, пока истечет время ожидания сессии.

1 голос
/ 06 февраля 2020

Подход JavaScript для обнаружения закрытия все еще работает.

Синтаксис только что немного изменился

UI.getCurrent().getPage().executeJs("function closeListener() { $0.$server.windowClosed(); } " +
        "window.addEventListener('beforeunload', closeListener); " +
        "window.addEventListener('unload', closeListener);",getElement());


@ClientCallable
public void windowClosed() {
    System.out.println("Window closed");
}

Хотя это не 100% пуленепробиваемый способ, так как я думаю, что нет все браузеры работают одинаково. Например, приведенный выше код запускается дважды с Chrome, где достаточно прослушивания beforeunload.

Это позволяет упростить JavaScript до

    UI.getCurrent().getPage().executeJs(
"window.addEventListener('beforeunload', () => $0.$server.windowClosed()); ",getElement());

BeforeLeaveObserver работает с навигацией. Поэтому, если вы используете RouterLink или вызываете ui.navigate("route"), то BeforeLeaveEvent отправляется, но не при вызове page.setLocation().

Браузер может закрыться из-за cra sh или проиграл по другим причинам, тогда beforeunload естественно не произойдет. Последним средством является механизм обнаружения, основанный на сердцебиении. Т.е. после трех ударов сердца сервер Vaadin сделает вывод, что браузер потерян. Естественно, в этом есть задержка, которую просто невозможно избежать.

...