{Java} Vaadin 14 - Определение ухода пользователя (закрытие вкладки, f5 и т. Д.)
В настоящее время я использую Vaadin Flow версии 14 (https://github.com/vaadin/platform/releases/tag/14.0.0).
Я использую версию Java 1.8.0_231, 64 бит.
Я просто хочу иметь возможность обнаруживать (в java!) Всякий раз, когда пользователь выполняет одно из этих действий:
- Закрывает текущую вкладку браузера (или их браузер)
- Нажимает F5 на клавиатуре или нажимает кнопку "Обновить" в браузере.
- Нажимает на ссылку (или что-то еще), которая перенаправляет их с моего сайта
Я пробовал много разных вещей, чтобы обнаружить это. Единственное, что мне удалось обнаружить до сих пор, - это всякий раз, когда истекает текущий 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.
Я попытался добавить это в свой класс просмотра:
@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
никогда не печатает. Сервис - это не то же самое, что сеанс. Это имеет смысл.1.2
а также 3 addSessionDestroyListener
печатает спустя некоторое время. Занимает примерно 15-30 секунд.
Нет ли способа мгновенно обнаружить это?:/
3 ответа
Подход 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()
.
Браузер может закрыться из-за сбоя или утерян по другим причинам, тогда beforeunload
естественно не бывает. Последнее средство - механизм обнаружения сердцебиения. Т.е. после трех ударов сердца сервер Vaadin придет к выводу, что Браузер утерян. В этом, естественно, есть отсрочка, которой просто не избежать.
В зависимости от того, какие браузеры вам нужно поддерживать, вы также можете взглянуть на Beacon API, который поддерживается всеми современными браузерами, но не IE11.
Преимущество Beacon API в том, что он неблокирующий. С помощью прослушивателя выгрузки клиент ожидает ответа перед закрытием вкладки, что может быть плохим для пользователя.
Тем не менее, как упомянул Тату, если браузер выйдет из строя или пользователь потеряет подключение к Интернету, все, что вы можете сделать, это дождаться истечения времени ожидания сеанса.
Решение для Vaadin Flow 22. Я поместил в index.html секцию сразу после закрывающего тега </style>:
<script>
window.addEventListener('beforeunload', function (event) {
event.returnValue = 'Are you sure you want to close the application?';
});
</script>
Скорее всего, вы не увидите свое собственное сообщение в диалоговом окне — вы увидите сообщение по умолчанию. Я тоже не видела, но все равно применяю ;)