Search code examples
javavaadinvaadin8

Building a Vaadin web app with dynamic content


I'm trying to create a web app via Vaadin (Vaadin Framework 8).

I read several pages of documentation but still, I have big problems concerning the structure of a Vaadin app. My problem is that I lack something about the theory behind it, and I'll try to expose my problems with a first attempt of code. I'll really appreciate anything that can help me understand how Vaadin works.

I want to create a website where a user can register, log in and log out.

The structure of the GUI of the website is an Homepage where there is something like a button or something like that to do the login if the user is not logged, and if the user is logged, instead of the login button, it should appear a logout button.

First thing, I have a class that extends UI; in that class, I set the servlet and the init() method.

In the init() method, I start creating a VerticalLayout(), then a MenuBar and a Panel (called contentPanel). Then, I create a Navigator. The first problem I encounter is that I understand the Navigator as a possibility of browsing between different pages; the constructor of a Navigator wants a SingleComponentContainer, so for now, I don't know how to navigate between different web pages. For my example, in the constructor I use the Panel: new Navigator(this, contentPanel); Then I add different View that will then appear inside the panel. Finally, I navigate to the Welcome page.

MyUI class:

public class MyUI extends UI {

    /**
     * Class that checks if the user is in the database 
     * and the psw inserted is correct
     */
    public static Authentication AUTH;
    public static User user = null;

    @WebServlet(value = "/*", asyncSupported= true)
    @VaadinServletConfiguration(productionMode = false, ui = MyUI.class)
    public static class MyUIServlet extends VaadinServlet {
    }

    @Override
    protected void init(VaadinRequest request) {

        AUTH = new Authentication();

        VaadinSession.getCurrent().setAttribute("user", user);

        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin(true);
        setContent(layout);

        Panel contentPanel = new Panel("Main Panel");
        contentPanel.setSizeFull();

        new Navigator(this, contentPanel);
        getNavigator().addView(LoginPage.NAME, LoginPage.class);
        getNavigator().setErrorView(LoginPage.class);
        getNavigator().addView(LogoutPage.NAME, LogoutPage.class);
        getNavigator().addView(WelcomePage.NAME, WelcomePage.class);

        MenuBar.Command welcome = new Command() {
            @Override
                public void menuSelected(MenuItem selectedItem) {
                    getNavigator().navigateTo(WelcomePage.NAME);
                }
        };

        MenuBar.Command login = new Command() {
            @Override
            public void menuSelected(MenuItem selectedItem) {
                getNavigator().navigateTo(LoginPage.NAME);
            }
        };

        MenuBar.Command logout = new Command() {
            @Override
            public void menuSelected(MenuItem selectedItem) {
                getNavigator().navigateTo(LogoutPage.NAME);
            }
        };

        MenuBar mainMenu = new MenuBar();
        mainMenu.addItem("Welcome", VaadinIcons.ARROW_CIRCLE_LEFT, welcome);
        mainMenu.addItem("Login", VaadinIcons.ENTER, login);
        mainMenu.addItem("Logout", VaadinIcons.EXIT, logout);

        layout.addComponent(mainMenu);
        layout.addComponent(contentPanel);

        getNavigator().navigateTo(WelcomePage.NAME);

    }

}

LoginPage class:

public class LoginPage extends VerticalLayout implements View {

    private static final long serialVersionUID = 1L;
    public static final String NAME = "loginpage";

    public LoginPage(){

        Panel panel = new Panel("Login");
        panel.setSizeUndefined();
        addComponent(panel);

        FormLayout content = new FormLayout();
        TextField username = new TextField("Username");
        content.addComponent(username);
        PasswordField password = new PasswordField("Password");
        content.addComponent(password);

        Button send = new Button("Enter");

        send.addClickListener(new Button.ClickListener() {
            private static final long serialVersionUID = 1L;

            public void buttonClick(ClickEvent event) {

                //The authenticate method will returns
                //true if the credentials are correct
                //false otherwise
                if(MyUI.AUTH.authenticate(username.getValue(), password.getValue())){

                    //In AUTH there is a User field called "user"
                    //User is a class that represents an user (so it has mail, psw, name etc)
                    VaadinSession.getCurrent().setAttribute("user", MyUI.AUTH.getUser());

                }else{
                    Notification.show("Invalid credentials", Notification.Type.ERROR_MESSAGE);
                    }

                }
            });

        content.addComponent(send);
        content.setSizeUndefined();
        content.setMargin(true);
        panel.setContent(content);
        setComponentAlignment(panel, Alignment.MIDDLE_CENTER);

    }

}

Logout class has the same structure of Login class; there is a logout method:

private void doLogout() {

    MyUI.AUTH.setUser(null);
    VaadinSession.getCurrent().setAttribute("user", MyUI.AUTH.getUser());
    getSession().close();

}

Another problem is: how can I dynamically add components in my layout, basing on the user status (logged or not?)

Next problem is: I didn't understand how to effectively do a logout.

I'll add complete code to facilitate any tests.

public class LogoutPage extends VerticalLayout implements View {

    private static final long serialVersionUID = 1L;
    public static final String NAME = "logoutpage";

    public LogoutPage(){

        Panel panel = new Panel("Logout");
        panel.setSizeUndefined();
        addComponent(panel);

        Button logout = new Button("Logout");
        logout.addClickListener(e -> doLogout());
        addComponent(logout);

    }

    private void doLogout() {

        MyUI.AUTH.setUser(null);
        VaadinSession.getCurrent().setAttribute("user", MyUI.AUTH.getUser());
        getSession().close();

    }

}

______________________________________________________________________________

public class WelcomePage extends VerticalLayout implements View {

    private static final long serialVersionUID = 1L;
    public static final String NAME = "welcomepage";

    public WelcomePage() {
        setMargin(true);
        setSpacing(true);
        Label welcome = new Label("Welcome");
        welcome.addStyleName("h1");
        addComponent(welcome);

    }

    @Override
        public void enter(ViewChangeEvent event) {
    }

}

______________________________________________________________________________

public class Authentication {

    private static User user = null;
    //those fields should be in user; this is just a test
    private String userID = "ID";
    private String psw = "psw";

    public Authentication() {
    }

    public void setUser(User user) {
        Authentication.user = user;
    }

    public User getUser(){
        return Authentication.user;
    }

    public Boolean authenticate(String userID, String psw){

        if(userID == this.userID && psw == this.psw) {
            user = new User();
            return true;
        }

        return false;

    }

}

Solution

  • I have seen many users struggling with the vaadin concept.

    In short it is not a page-based framework, where you switch to a new page with each mouse click.

    Instead it is more like a Swing application, where you have a single gui instance, where you add forms/poups/buttons, modify them and remove them based on user interaction. This is known as a Single-Page Application.

    The Navigator is mainly used to allow the user to navigate with the backward/forward buttons of the webbrowser to the "previous" page, or bookmark specific pages.

    This link provides some more detailed informations about this concept.

    To answer you question: - Use a single page/nvigation - When not logged in, show a modal login popup - When the user correctly enters authentification, remove the popup and show the main content in the vertical layout - When the user logs out, remove the content from the vertical layout

    For your simple use case, there is no need to work with the Navigator or Views