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;
}
}
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