"Can't move a node from one state tree to another" 注销时

"Can't move a node from one state tree to another" when logging out

我正在使用 vaadin 应用程序,但在我尝试注销时一直收到此错误。我尝试了很多方法来阻止这种情况,但真的不知道该怎么做:

java.lang.IllegalStateException: Can't move a node from one state tree to another. If this is intentional, first remove the node from its current state tree by calling removeFromTree
at com.vaadin.flow.internal.StateNode.doSetTree(StateNode.java:684) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.internal.StateNode.lambda$setTree(StateNode.java:364) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.internal.StateNode.visitNodeTree(StateNode.java:643) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.internal.StateNode.setTree(StateNode.java:364) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.internal.StateNode.setParent(StateNode.java:264) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.internal.nodefeature.NodeFeature.attachPotentialChild(NodeFeature.java:78) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.internal.nodefeature.StateNodeNodeList.add(StateNodeNodeList.java:53) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.internal.nodefeature.ElementChildrenList.add(ElementChildrenList.java:42) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.dom.impl.AbstractNodeStateProvider.insertChild(AbstractNodeStateProvider.java:102) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.dom.Node.insertChild(Node.java:250) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.dom.Node.appendChild(Node.java:141) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.component.internal.UIInternals.showRouteTarget(UIInternals.java:730) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.router.internal.AbstractNavigationStateRenderer.handle(AbstractNavigationStateRenderer.java:240) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.router.Router.handleNavigation(Router.java:223) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.router.Router.navigate(Router.java:194) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.router.Router.initializeUI(Router.java:92) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.server.BootstrapHandler.createAndInitUI(BootstrapHandler.java:1489) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.server.BootstrapHandler.synchronizedHandleRequest(BootstrapHandler.java:459) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1540) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:247) ~[flow-server-2.1.3.jar:2.1.3]
at com.vaadin.flow.spring.SpringServlet.service(SpringServlet.java:95) ~[vaadin-spring-12.1.2.jar:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:459) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:352) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.springframework.web.servlet.mvc.ServletForwardingController.handleRequestInternal(ServletForwardingController.java:141) ~[spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:177) ~[spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:52) ~[spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at java.base/java.lang.Thread.run(Thread.java:830) ~[na:na]

每当我单击注销时,我都会成功重定向到登录视图,但它没有登录,而是显示 "Assertion Error: No child Node found with id -1" 并且我收到了上述错误。很少有描述。

这是我的登录视图 Class:

@Route(value = "login")
public class LoginView extends LoginOverlay implements BeforeEnterObserver, AfterNavigationObserver {


    public LoginView() {
        LoginI18n i18n = LoginI18n.createDefault();
        i18n.setHeader(new LoginI18n.Header());
        i18n.getHeader().setTitle("FBLA Genie");
        i18n.getHeader().setDescription("Login to the FBLA Genie App");
        i18n.setAdditionalInformation(null);
        i18n.setForm(new LoginI18n.Form());
        i18n.getForm().setSubmit("Sign in");
        i18n.getForm().setTitle("FBLA Genie");
        i18n.getForm().setUsername("Username/ID");
        i18n.getForm().setPassword("Password");
        setI18n(i18n);
        setAction("login");

        setForgotPasswordButtonVisible(false);

    }

    @Override
    public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
        if (SecurityUtils.isUserLoggedIn()) {
            beforeEnterEvent.forwardTo(Home.class);
        } else {
            setOpened(true);
        }
    }

    @Override
    public void afterNavigation(AfterNavigationEvent event) {
        setError(
                event.getLocation().getQueryParameters().getParameters().containsKey(
                        "error"));
    }

}

我的安全配置:

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private static final String LOGIN_PROCESSING_URL = "/login";
    private static final String LOGIN_FAILURE_URL = "/login?error";
    private static final String LOGIN_URL = "/login";
    private static final String LOGOUT_SUCCESS_URL = "/login";

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .requestCache().requestCache(new CustomRequestCache())
                .and().authorizeRequests()
                .requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()

                .and().formLogin()
                .loginPage(LOGIN_URL).permitAll()

                .loginProcessingUrl(LOGIN_PROCESSING_URL)
                .failureUrl(LOGIN_FAILURE_URL)

                .successHandler(new SavedRequestAwareAuthenticationSuccessHandler())
                .and().logout().logoutSuccessUrl(LOGOUT_SUCCESS_URL);
    }

    /**
     * Configures the Login Information and credentials to the app.
     * <p>
     * Currently using temporary security for demonstration purposes.
     */
    @Bean
    @Override
    /*
     * Can be made more secure with this
     * https://dzone.com/articles/spring-security-authentication
     */
    public UserDetailsService userDetailsService() {
        UserDetails admin...
        return new InMemoryUserDetailsManager(admin);
    }


    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers(
                ...
    }
}

我的 SecurityUtils:

/**
 * A Class for Util methods in security
 */
public final class SecurityUtils {

    private SecurityUtils() {
        // Util methods only
    }

    static boolean isFrameworkInternalRequest(HttpServletRequest request) {
        final String parameterValue = request.getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER);
        return parameterValue != null
                && Stream.of(ServletHelper.RequestType.values())
                .anyMatch(r -> r.getIdentifier().equals(parameterValue));
    }


    public static boolean isUserLoggedIn() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication != null
               && !(authentication instanceof AnonymousAuthenticationToken)
               && authentication.isAuthenticated();
    }

    public static boolean isAccessGranted(Class<?> securedClass) {
        //Allows if there are no roles required
        Secured secured = AnnotationUtils.findAnnotation(securedClass, Secured.class);
        if (secured == null) return true;

        //looks up role options
        List<String>   allowedRoles       = Arrays.asList(secured.value());
        Authentication userAuthentication = SecurityContextHolder.getContext().getAuthentication();
        return userAuthentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .anyMatch(allowedRoles::contains);
    }
}

我的自定义请求缓存:

class CustomRequestCache extends HttpSessionRequestCache {

    @Override
    public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
        if (!SecurityUtils.isFrameworkInternalRequest(request)) {
            super.saveRequest(request, response);
        }
    }

}

我的 ConfigureUIServiceInitListener:

@Component
public class ConfigureUIServiceInitListener implements VaadinServiceInitListener {

    @Override
    public void serviceInit(ServiceInitEvent event) {
        event.getSource().addUIInitListener(uiEvent -> { //
            final UI ui = uiEvent.getUI();
            ui.addBeforeEnterListener(this::beforeEnter);
        });
    }


    private void beforeEnter(BeforeEnterEvent event) {
        if (!SecurityUtils.isAccessGranted(event.getNavigationTarget())) {
            if (SecurityUtils.isUserLoggedIn()) {
                event.rerouteToError(NotFoundException.class);
            } else {
                event.rerouteTo(LoginView.class);
            }
        }
    }
}

我的主视图

@PWA(name = "",
     shortName = "",
     description = "This is the Application made by Shourya Bansal")
@PreserveOnRefresh
@UIScope
public class MainView extends AppLayout {
    public static final Tab  HOME_TAB        = createTab(VaadinIcon.HOME, "Home", Home.class);
    public static final Tab  ADD_STUDENT_TAB = createTab(VaadinIcon.FILE_ADD, "Add a Student", CreateStudent.class);
    public static final Tab  ADD_HOURS_TAB   = createTab(VaadinIcon.EDIT, "Add Hours to Student", AddHours.class);
    public static final Tab  VIEW_EDIT_TAB   = createTab(VaadinIcon.EYE, "View and Edit Students", GetStudentInformation.class);
    public static final Tab  REPORT_TAB      = createTab(VaadinIcon.RECORDS, "Generate Reports", Reports.class);
    public static final Tab  MAIL_TAB        = createTab(VaadinIcon.MAILBOX, "Send Message", MailView.class);
    public static final Tab  DOC_TAB         = createTab(VaadinIcon.QUESTION, "Documentation and FAQs", Documentation.class);
    public static final Tabs tabs            = getTabs();

    public MainView() {
        final Tabs tabs = new Tabs();

        //Uses Tabs for Navigation
        tabs.setOrientation(Tabs.Orientation.HORIZONTAL);
        tabs.add(getAvailableTabs());
        tabs.setFlexGrowForEnclosedTabs(1);

        Image logo = new Image("https://github.com/Mastermind497/Shourya_FBLA/raw/master/logo/Logo.png", "Logo");
        logo.setHeight("12em");

        Button toGitHubPage = new Button("Go To GitHub Page");
        toGitHubPage.addClickListener(buttonClickEvent -> UI.getCurrent().getPage().executeJs("window.open(\"https://github.com/Mastermind497/Shourya_FBLA\", \"_blank\", \"\");"));

        //A Button for Toggling Dark Mode
        final Button toggleButton = new Button("Dark Mode", VaadinIcon.MOON.create());
        toggleButton.addClickListener(click -> {
            ThemeList themeList = UI.getCurrent().getElement().getThemeList();

            if (themeList.contains(Lumo.DARK)) {
                themeList.remove(Lumo.DARK);
                toggleButton.setText("Dark Mode");
                toggleButton.setIcon(VaadinIcon.MOON.create());
            } else {
                themeList.add(Lumo.DARK);
                toggleButton.setText("Light Mode");
                toggleButton.setIcon(VaadinIcon.SUN_O.create());
            }
        });

        HorizontalLayout buttons = new HorizontalLayout(toGitHubPage, toggleButton);
        //Creates a Vertical Layout to store all the above components
        VerticalLayout verticalLayout = new VerticalLayout();

        //Adds component to Vertical Layout
        verticalLayout.setSizeFull();
        verticalLayout.add(logo);
        verticalLayout.add(buttons);
        verticalLayout.add(tabs);

        //Aligns everything to the center
        verticalLayout.setAlignItems(FlexComponent.Alignment.CENTER);

        //Checks to see if main database is made. Makes if not
        MySQLMethods.setUp();

        addToNavbar(verticalLayout);
        this.setDrawerOpened(false);
    }

    /**
     * Generates the tabs for the Navbar
     *
     * @return The Tabs for the navBar
     */
    public static Tabs getTabs() {
        return new Tabs(getAvailableTabs());
    }

    /**
     * Creates an ArrayList of the Tabs for Each page
     *
     * @return The Tabs
     */
    private static Tab[] getAvailableTabs() {
        final ArrayList<Tab> tabs = new ArrayList<>(7);
        tabs.add(HOME_TAB);
        tabs.add(ADD_STUDENT_TAB);
        tabs.add(ADD_HOURS_TAB);
        tabs.add(VIEW_EDIT_TAB);
        tabs.add(REPORT_TAB);
        tabs.add(MAIL_TAB);
        tabs.add(DOC_TAB);
        tabs.add(createTab(createLogoutLink()));

        return tabs.toArray(new Tab[0]);
    }


    private static Anchor createLogoutLink() {
        final Anchor a = populateLink(new Anchor(), VaadinIcon.LOCK, "Log Out");
        a.setHref("/logout");
        return a;
    }

    private static Tab createTab(VaadinIcon icon, String title, Class<? extends Component> viewClass) {
        RouterLink routerLink = new RouterLink(null, viewClass);
        routerLink.setHighlightCondition(HighlightConditions.sameLocation());
        return createTab(populateLink(routerLink, icon, title));
    }


    private static Tab createTab(Component content) {
        final Tab tab = new Tab();
        tab.addThemeVariants(TabVariant.LUMO_ICON_ON_TOP);
        tab.add(content);
        return tab;
    }


    private static <T extends HasComponents> T populateLink(T a, VaadinIcon icon, String title) {
        a.add(icon.create());
        a.add(title);
        return a;
    }
}

我的登录视图

/**
 * A Class that allows logging in to the system. Huge potential for security, currently not using
 * its full capabilities for demonstration purposes.
 */
@Route(value = "login")
@PageTitle("Login | FBLA Genie")
@PreserveOnRefresh
@UIScope
public class LoginView extends VerticalLayout implements BeforeEnterObserver {

    /**
     * The main login form
     */
    final LoginForm login = new LoginForm();

    /**
     * Sets up the Login View and adds it to the its page
     */
    public LoginView() {
        addClassName("login-view");
        setSizeFull();

        setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
        setAlignItems(FlexComponent.Alignment.CENTER);

        login.setAction("login");

        Image logo = new Image("https://github.com/Mastermind497/Shourya_FBLA/raw/master/logo/Logo.png", "Logo");
        logo.setHeight("24em");

        add(
                logo,
                login
        );
    }

    /**
     * Turns on security, preventing access to the rest of the app before login is complete
     *
     * @param beforeEnterEvent A lambda event that is used by the login view to validate if the app should
     *                         be open or remain closed
     */
    @Override
    public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
        //Checks whether there is a parameter error
        if (!beforeEnterEvent.getLocation()
                .getQueryParameters()
                .getParameters()
                .getOrDefault("error", Collections.emptyList())
                .isEmpty()) {

            //makes error visible
            login.setError(true);
        }
    }
}

您遇到过这个错误Error "Can't move a node from one state tree to another." when re-adding a previously removed component after refreshing with @PreserveOnRefresh

它已经被团队修复,应该会在下一个小版本中发布。 (我猜它会是 14.2.1)。目前,作为解决方法,您可以删除注释

Vaadin 也不支持在静态字段中存储组件。就我而言,这就是问题所在。 (Vaadin 18).