lunes, 15 de abril de 2019

16. Vaadin LoginForm (1). Basic components

updated on April 16, 2019

0. Introduction


A simple login form can have basically:
  • A user name input field
  • A password input field
  • A submit button
  • A component for showing messages
  • A component for selecting the language
We are calling this class "LoginForm" and this name must be the same as the one defined in then openadmin.listeners.LoggedInListener class for redirecting to the user that has not been logged in. See this previous post.

1. Designing the visual interface



Here is a simple sketch of the login form

+---------------------------------------------------------+
| +--------+                                              |
| | LOGO   |     1                ENTERPRISE NAME         |
| |        |                                              |
| +--------+                                              |
+---------------------------------------------------------+
|                           +---------------------------+ |
|                2          | Language selector combo   | |
|                           +---------------------------+ |
+---------------------------------------------------------+
|                                                       |
|                 +-------------------+                   |
|           User: |                   |                   |
|                 +-------------------+                   |
|                                                         |
|                                                         |
|                 +-------------------+                   |
|       Password: |                   |                   |
|                 +-------------------+                   |
|                                                         |
|                         +-------------------+           |
|                         |  Login Button     |           |
|                         +-------------------+           |
|                                                         |
|  +--------------------------------------------------+   |
|  |  Notification messages                           |   |
|  +--------------------------------------------------+   |
|                                                         |
+---------------------------------------------------------+

We are considering 3 containers indicated in yellow colour:

  1. Header panel
  2. Language selector panel
  3. Login panel

2. Image resources

The image resources (photos of the enterprise) are in this folder. If not exists the route from webapp folder you should create it.

  • Deployed Resources/webapp/frontend/img/enterprise
The images are taken from a "Whatsapp group" and are a protest against the citriculture problems in Valencia (Spain). It is a simple example. The images are the same but have different size.





About the flag images, we have talked about in a previous entry. They are in this folder:
  • Deployed Resources/webapp/frontend/icon/flags
3. i18n resources
They are in this folder. If not exists i18n folder you should create it.
  • src/main/resources/i18n
There are 2 groups of resources:
  1. login
  2. main

the contents of the English version of login is:


user = User
password = Password
login = Login
invalid_credentials = Invalid credentials

and the contents of the English version of main is:


enterprise=The Death of Agriculture in Valencia 


3. LoginForm component

Take into account that:

  1. Is annotated by @Route("") as it is the first route Vaadin looks for.
  2. Extends a VerticalLayout
  3. Implements II18nChange (created in a previous post), to allow changing labels affected by the Locale. The method it implements is changeI18nLables() 
  4. It has 3 parts (header panel, language selector panel and login panel)
  5. The language selector panel has a component that was created in the previous post that select the language and changes all labels content affected by the language change.
  6. The login button executes the login() procedure to test if the user can log in.
  7. The keyboard key "enter" also activates the login() procedure
  8. If the user is logged in, it is redirected to a view that is annotated by  @Route("main").
  9. The valid user is "user" and the password is "password"
Here is the code


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
ackage openadmin.ui;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Html;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.PasswordField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

import openadmin.session.SessionData;
import openadmin.utils.VaadinUtils;


@Route("")
@PageTitle("Login")
@SuppressWarnings("serial")
public class LoginForm extends VerticalLayout implements II18nChange{
 private TextField userName;
 private PasswordField password;
 private Button login;
 private LocaleCombo langCombo;
 private Label lblUserName;
 private Label lblPassword;
 private Label lTitle;
 private Image imageLang;
 
 @Inject
 private SessionData sesData;
 
 public LoginForm() {
 }
 
 /**
  * Initialization of the 3 panels
  */
 @PostConstruct
 private void init() {
  add(getHeaderPanel());
  add(getLangSelectorPanel());
  add(getLoginPanel());
 }
 
 
 /** Enterprise header **/
 private HorizontalLayout getHeaderPanel() {
 
  HorizontalLayout headerPanel = new HorizontalLayout();
  
  
  Image logo = new Image("frontend/img/enterprise/enterprise04.jpg", "logo");
  headerPanel.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, logo);
  headerPanel.add(logo);
  
  HorizontalLayout title = new HorizontalLayout();
  title.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
  
  lTitle=new Label(getTranslation ("main.enterprise"));
  
  headerPanel.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, lTitle);
  title.add(lTitle);
  
  headerPanel.add(title);
  return headerPanel;
 }

 private HorizontalLayout getLangSelectorPanel() {
  
  HorizontalLayout langSelPanel = new HorizontalLayout();
  
  langSelPanel.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
  
  // 1. Language ComboBox.
  langCombo = new LocaleCombo(sesData, this);
  
  langSelPanel.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, langCombo);
  langSelPanel.add(langCombo);
    
  // 2.Flag Icon
  imageLang = new Image("frontend/icon/flags/" + sesData.getLangEnum().name() + ".png", "language");
  //imageLang = new Image("frontend/icon/flags/" + lEnum.name() + ".png", "language");  // Jetty
  
  
  langSelPanel.setVerticalComponentAlignment(FlexComponent.Alignment.CENTER, imageLang);
  langSelPanel.add(imageLang);

  return langSelPanel;
 }
 
 private Component getLoginPanel() {
         
        VerticalLayout loginPanel= new VerticalLayout();
        VerticalLayout loginForm = new VerticalLayout();
  
        // 1. User
        lblUserName = new Label(getTranslation ("login.user"));
  userName=new TextField();
  userName.setValue("admin");
  loginForm.add(lblUserName, userName);
   
  //2. Password
  lblPassword = new Label(getTranslation("login.password"));
  password = new PasswordField();
  loginForm.add(lblPassword, password);
  password.setWidth("15em");
  
  //3. Line separation
  loginForm.add(new Html("<br/>"));
  
  //4. Buttons layout
  HorizontalLayout buttonsLay = new HorizontalLayout();
  buttonsLay.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
  loginForm.add(buttonsLay);
  buttonsLay.add(login = new Button(getTranslation("login.login"), VaadinIcon.SIGN_IN.create()));
  
  //5. Login button
  login.addClickListener(event -> login()); //assign action to button
  
  //6 Keyboard event listeners 
  loginForm.getElement().addEventListener("keypress", event -> login()).setFilter("event.key == 'Enter'");
  loginPanel.setHorizontalComponentAlignment(FlexComponent.Alignment.CENTER, loginForm);
  loginPanel.add(loginForm);
  
  return loginPanel;
 }
 
 /**
  * Try to log in if credentials are correct 
  */
 private void login() {
  if (userName.getValue().length()<1 || password.getValue().length()<1) {
   showNotification("login.invalid_credentials", 2000);
   userName.focus();
  
  // user & password credentials 
  }else if (userName.getValue().equals("user") && password.getValue().equals("password")) {
   VaadinUtils.setSessionAttribute("CURRENT_USER", userName.getValue());
   getUI().get().navigate("main");
   
  }else {
   showNotification("login.invalid_credentials", 2000);
   userName.focus();
  }
 }

 /**
  * Show notification 
  * @param i18nKey
  * @param duration
  */
 public void showNotification(String i18nKey, int duration) {
  String translatedMessage=this.getTranslation(i18nKey);
  Notification not=new Notification(translatedMessage);
  not.setDuration(duration);
  not.open();
 }
 /**
  * Change labels according to Locale
  */
 @Override
 public void changeI18nLabels() {
  lTitle.setText(getTranslation ("main.enterprise"));
  lblUserName.setText(getTranslation("login.user"));
  lblPassword.setText(getTranslation("login.password"));
  login.setText(getTranslation("login.login"));
  imageLang.setSrc("frontend/icon/flags/" + sesData.getLangEnum().name() + ".png");
  //imageLang.setSrc("frontend/icon/flags/" + lEnum.name() + ".png");  //Jetty
 }
}

Here is the result in the browser


In the next post, we are adding style.

No hay comentarios:

Publicar un comentario