Les fondations de Vaadin v8

This documentation applies to version 8 of the framework!

Pourquoi Vaadin ?

La solution standard pour faire du web avec Java est Java EE

Le Web avec Java EE

HTTP

Java

HTML

API Servlet

CSS

JSP

JavaScript

Taglibs/Tag files

AJAX

DOM

Le Web avec Vaadin

ObligatoireFacultatif

Java

Vaadin

SASS

GWT

Quelques principes

  • Le code est en Java

    • Compilé en bytecode

  • Basé sur des composants

  • Programmation évènementielle

Contraintes

  • Java 8+

  • Container de servlets Java EE 6+

Architecture générale

architecture

Composants

Interface de plus haut niveau implémentée par tous les composants Vaadin

UI

  • Représente l’intégralité d’une fenêtre de navigateur

  • Une instance par fenêtre (ou tab)

  • UI utilisée spécifiée par un paramètre de servlet

Appel d’UI.init()

  • Au chargement de la page

  • A chaque refresh

    • Sauf si l’UI est annotée avec @PreserveOnRefresh

ui

Notion de composant

Disposés sur leur container parent via un layout

component

Composants disponibles

  • Label

  • TextField

  • Button

  • Select

  • Grid

  • etc.

Samplers

sampler6

Containers et layouts

Container :

Comprend un ou des composants enfants

Layout :

Container spécialisé qui dispose ses composants enfant selon une stratégie

layout

Layouts disponibles

  • VerticalLayout

  • HorizontalLayout

  • GridLayout

  • FormLayout

  • etc.

Programmation Evènementielle

  • Implémentation du pattern Observer

  • Présent dans tous les clients lourds :

    • Swing/AWT

    • SWT

    • Flex

  • Mais pas dans le web

observer

Qui est Subject ?

  • Tous les Component sont des Subject

  • Génèrent des évènements en fonction :

    • Du type de composant

    • Du type de déclencheur

Exemple

  • Button génère :

    • FocusEvent

    • BlurEvent

    • ClickEvent

Qui est Observer ?

  • Toute classe peut implémenter Observer

    • p.e. l’UI

Côté client

  • Du JavaScript implémente le code serveur

  • Une interaction client-serveur se traduit par un appel Ajax

Implémentation du clic

click event

Architecture des abonnés

  • Notion d’abonnement portée par une interface

  • N’importe laquelle :

    • L’UI

    • Une classe anonyme

    • Une classe dédiée

UI abonné

Avantages

Tous les évènements sont traités dans une unique classe

Désavantages

Si plusieurs objets génèrent le même événement, il faut pouvoir les différencier via des if

public class MyUI implements ClickListener {

  private Button button1;
  private Button button2;

  @Override
  public void buttonClick(ClickEvent e) {

    if (e.getSource() == button1) ...
    else if (e.getSource() == button2) ...
  }
}

Classe anonyme abonnée

Avantages

Porte l’information du comportement avec sa déclaration

Désavantages
  • Perte de la référence sur le comportement

  • Couplage fort

button.addClickListener(new ClickListener() {

  @Override
  public void buttonClick(ClickEvent e) {
    ...
  }
}

Classe dédiée abonnée

Avantages
  • Entièrement orienté objet

  • Lisible

  • Changement dynamique possible

  • Séparation des responsabilités

  • Nommage sémantique

Désavantage

Verbeux

public class SendFormBehavior implements ClickListener() {

  @Override
  public void buttonClick(ClickEvent e) {
    ...
  }
}

Problématique liées au pattern Observer

Couplage entre l’Observer et son objet

Event Bus

Transport event occurrences from sources to subscribers, where event sources signal event occurrences to all event subscribers and event subscribers receive event occurrences.
https://en.wikipedia.org/wiki/Event_monitoring
— Wikipedia
eventbus
eventbus annotation
eventbus payload

Implémentations existantes

Exemple de cas d’utilisation

  • Une liste déroulante pour les pays

  • Une liste déroulante pour les villes

    • Uniquement pour les villes du pays

public class CountryComboBox extends ComboBox {

    public CountryComboBox(EventBus bus) {
        addValueChangeListener(event -> {
            bus.post(new CountryChangedEvent(event.getValue()));
        });
    }
}
public class CityComboBox extends ComboBox {

    @Subscribe
    public void changeCities(CountryChangedEvent event) {
        // Refresh cities
    }
}
public class EventBusUI extends UI {

    public void init(VaadinRequest request) {
        EventBus bus = new EventBus();
        CountryComboBox countries = new CountryComboBox(bus);
        CityComboBox cities = new CityComboBox();
        bus.register(cities);
        // Layout components & set content
    }
}

Erreurs

error

Mettre un composant en erreur

c.setComponentError(ErrorMessage)

Exceptions inattendues

error handler

Notifications

notification

Humanized message Error message Tray message Warning message

Comment valider ?

validatable

Validateurs disponibles

  • XXXRangeValidator :

    • Date, Double & Integer

  • RegexpValidator

  • EmailValidator

  • StringLengthValidator

  • NullValidator

  • CompositeValidator

Exemple d’utilisation d’un Validator

TextField email = TextField(”Email");
email.addValidator(new EmailValidator());

Navigation

Users often need to have direct links to specific views. The Navigator can be used for most cases of navigation.
https://vaadin.com/docs/framework/advanced/advanced-navigator.html
— Vaadin documentation

Modèle

Navigator

Gère la navigation

View

Composant affichable

navigator

Exemple d’utilisation

public class NavigatorUI extends UI {

    @Override
    protected void init(VaadinRequest request) {
        Navigator navigator = new Navigator(this, this);
        setNavigator(navigator);
        navigator.addView("", new InitialView());
        navigator.addView("other", new OtherView());
    }
}

Data Binding

  • Gestion évènementielle du changement d’état du modèle vers un composant graphique

  • Et vice-versa

Niveaux de data binding

  • Propriété p.e. email

  • Bean p.e Person

  • Liste de beans

Has Value

A generic interface for field components and other user interface objects that have a user-editable value.
https://vaadin.com/api/8.1.4/com/vaadin/data/HasValue.html
— Vaadin Javadocs
hasvalue

Binder

Defines how the values in a business object should be bound to the fields shown in the user interface. Binder takes care of reading values from the BO and converting the user’s data between the format expected by the BO and the format expected by the field.
https://vaadin.com/docs/framework/v8/datamodel/datamodel-forms.html
— Vaadin documentation
binder

Exemple

Binder<Person> binder = new Binder<>(Person.class);
TextField firstNameField = new TextField("Give name");
TextField lastNameField = new TextField("Family name");
DateField birthDateField = new DateField("Date of birth");
binder.bind(firstNameField, "firstName");
binder.bind(lastNameField, "lastName");
binder.bind(birthDateField, "birthDate");

// User interaction

Person person = binder.getBean();
String firstName = person.getFirstName();
String lastName = person.getLastName();
Date birthdate = person.getBirthDate();
Exemple de formulaire

Has Items

A component that displays a collection of items.
https://vaadin.com/api/8.1.4/com/vaadin/data/HasItems.html
— Vaadin Javadocs
hasitems

Exemple

List<Person> persons = ...;
ListDataProvider<Person> provider = new ListDataProvider<>(persons);
Grid<Person> grid = new Grid<>(Person.class);
grid.setDataProvider(provider);
grid.setHeaderVisible(true);
grid.setColumns("firstName", "lastName", "birthDate");

Spécialisations de Data Provider

  • BackendDataProvider

  • HierarchicalDataProvider

  • ConfigurableFilterDataProvider

data provider

Grid

Composant dédié à l’affichage de données tabulées

grid

Affichage des colonnes

  • Indique les colonnes visibles

  • Mais également leur ordre

Grid<Person> grid = new Grid<>(Person.class);
grid.setColumns("firstName", "lastName");

Libellé de l’en-tête de colonne

Par défaut, inféré du nom de l’attribut

Grid<Person> grid = new Grid<>(Person.class);
grid.getColumn("firstName").setCaption("Given Name");

Libellé de la cellule

  • Récupère la valeur de l’attribut

  • Utilise le Renderer pour la transformer en String

  • Affiche la String dans la cellule

Exemple : formatage de date

Grid<Person> grid = new Grid<>(Person.class);
Column<Person, ?> column = grid.getColumn("birthDate");
Renderer renderer = new LocalDateRenderer("EE dd MMM yy");
column.setRenderer(renderer);

Exemple : rendu HTML

Grid<Person> grid = new Grid<>(Person.class);
Column<Person, ?> column = grid.getColumn("biography");
Renderer renderer = new HtmlRenderer();
column.setRenderer(renderer);

Exemple : ajout de bouton

Grid<Person> grid = new Grid<>(Person.class);
Column<Person, String> column =
    grid.addColumn(person -> person.getFirstName());
ButtonRenderer<String> buttonRenderer =
    new ButtonRenderer<>(event -> Notification.show("Shown"));
column.setRenderer(buttonRenderer);
Exemple de Grid

Intégration avec CDI

Via l’addon Vaadin CDI

Avantages

  • Pas de servlet enfant

    • Ni création

    • Ni référencement

  • Pas de référencement explicite de(s) UI(s)

  • Pas d’enregistrement explicite des Views

Référencement de l’UI

  • Via l’annotation @CDIUI

  • Chemin indiqué par la valeur :

    • @CDIUI("")

    • @CDIUI("fun")

    • @CDIUI :

      • Inféré en fonction du nom de la classe sans le suffixe UI

@CDIUI("main")
public class MyUI extends UI {

    public void init(VaadinRequest request) {
        // Do something here
    }
}

Enregistrement de Views

  • Via l’annotation @CDIView

  • Clé d’enregistrement dans le Navigator indiqué par la valeur :

    • @CDIView("")

  • Enregistré dans un ViewProvider

    • Doit être associé au Navigator

@CDIView("hello")
public class MyView extends HorizontalLayout
                    implements View() { }

@CDIUI("") public class MyUI extends UI {

    @Inject
    private ViewProvider viewProvider;

    public void init(VaadinRequest request) {
        Navigator navigator = new Navigator(this, this);
        navigator.addProvider(viewProvider);
        navigator.navigateTo("hello");
    }
}