java - {Java} Vaadin 14 - 检测用户离开(关闭选项卡、f5 等)

标签 java spring spring-boot vaadin vaadin14

我目前使用的是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) 来更改)。这使得每个 session 在 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);
    }

它仅在 session 过期时打印此消息(在我的例子中为 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 永远不会打印。服务与 session 不同。有道理。
1.23 addSessionDestroyListener 稍后打印 w。不过大约需要 15-30 秒。


有没有办法基本上立即检测到这一点? :/

最佳答案

检测关闭的 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自然不会发生。最后的手段是基于心跳的检测机制。 IE。心跳丢失 3 次后,Vaadin 服务器将断定浏览器已丢失。这其中自然有延迟,这是无法避免的。

关于java - {Java} Vaadin 14 - 检测用户离开(关闭选项卡、f5 等),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60084612/

相关文章:

java - Java 中的 vector

java - 如何使用反射调用java中的方法

spring-boot - 带密码租用/续订的 Spring boot JDBC(如 Vault 中所示)

java - 无法 Autowiring 字段 : private org. springframework.security.authentication.AuthenticationManager

java - 使用 GroupLayout 呈现在彼此之上的组件

java - 在 2 个 Controller 之间传递值时出现空指针异常

java - Spring Activity 与方面

spring - 将 spring-batch-admin 集成到现有的 spring boot 后无法导入属性

java - Spring MVC : How to modify json response sent from controller

azure - 使用 Azure AD 的 Spring Boot+Oauth 客户端凭据授予流程