在 Vaadin 14 (Vaadin Flow) 中呈现 AppLayout 之前,如何在视图中的 BeforeEnterObserver 中重新路由

问题描述

例如让我有

public class MainView extends AppLayout {
   public MainView() {
      User user = VaadinSession.getAttribute("user");
      if(user.isCheckSomething())
          Span span = new Span("Hello " + user.getFirstname());
   }
}

如果用户尚未登录,这将因 NPE 而失败,因为从会话中获取用户将为空。现在我可以在 if(user.isCheckSomething()) 之前添加一个空检查,但理想情况下,如果用户登录,我宁愿根本不呈现 AppLayout。也就是说,我宁愿在视图中失败BeforeEnterObserverpublic void beforeEnter(BeforeEnterEvent event) 方法中,但是 AppLayout调用 beforeEnter(...) 方法之前被调用和创建。

换句话说,如果用户未通过视图登录,我如何强制完全跳过 AppLayout 的实例化,以便永远不会构造 AppLayout

解决方法

根据经验,在构造函数中以任何方式使用 UI 确实不可靠,因为它尚未初始化。

AppLayout 有自己的 afterNavigation 方法,应该在 BeforeEnterEvent 之后调用。

public class MainView extends AppLayout {
    @Override
    protected void afterNavigation() {
        super.afterNavigation();
        User user = VaadinSession.getAttribute("user");
        if(user.isCheckSomething())
            Span span = new Span("Hello " + user.getFirstname());
    }

因此在 beforeEnter 方法中,您将重新路由以登录,否则将触发来自父布局的 after 导航。

@Override
public void beforeEnter(BeforeEnterEvent event) {
    if (!isAuthenticated()) {
        event.rerouteTo(LoginView.class);
    }
}

您可以在每个视图中实现 BeforeEnterObserver 并一遍又一遍地检查用户是否通过身份验证...或者您可以执行一次:

@SpringComponent
public class AuthenticationControl implements VaadinServiceInitListener {
     @Override
    public void serviceInit(ServiceInitEvent event) {
        event.getSource().addUIInitListener(uiEvent -> {
            final UI ui = uiEvent.getUI();
            ui.addBeforeEnterListener(/* do the check here,either with a method reference or create a separate listener class */);
        });
     }
}