Nicolas Frankel
La solution standard pour faire du web avec Java est Java EE
HTTP | Java |
HTML | API Servlet |
CSS | JSP |
JavaScript | Taglibs/Tag files |
AJAX | DOM |
Obligatoire | Facultatif |
---|---|
Java | CSS |
Vaadin | Web Component |
La v10 de Vaadin nécessite plus de compétences et d’effort CSS que les versions précédentes pour un rendu comparable |
Code en Java
Compilé en bytecode
Basé sur des composants réutilisables
Programmation évènementielle
Compatibles mobile
Java 8+
Container de servlets Java EE 6+
Servlet
UI
Route
Composants
Containers
Servlet spécifique VaadinServlet
Enregistre automatiquement une instance sous /*
Si aucune instance n’est enregistrée explicitement
The main servlet, which handles all incoming requests to the application.
The topmost component in any component hierarchy. There is one UI for every Vaadin instance in a browser window. A UI may either represent an entire browser window (or tab) or some part of a html page where a Vaadin application is embedded.
Représente le <body>
d’une page HTML
Classe d’UI spécifiée par une annotation
public class MyUI extends UI {
@Override
protected void init(VaadinRequest request) {
add(new Span("Hello world!"));
}
}
@VaadinServletConfiguration(
ui = MyUI.class,
productionMode = false
)
public class MyVaadinServlet extends VaadinServlet { }
Component is a higher level abstraction of an Element
or a hierarchy of Elements.
Classe (abstraite) de plus haut niveau héritée par tous les composants Vaadin
Disposé sur un composant parent
Ou annotée avec une annotation @Route
Label
TextField
Button
Select
Grid
etc.
A component to which the user can add and remove child components.
VerticalLayout
HorizontalLayout
FormLayout
etc.
Defines the route for components that function as navigation targets in routing.
Associe un chemin d’accès à un composant
Indiqué par l’annotation @Route
Configuré par Vaadin au démarrage de l’application
Nom de la classe
Suppression du suffixe View
En minuscules
Ou ""
pour la vue MainXXX
@Route("home")
public class MainView extends Div {
public MainView() {
setText("Hello world!");
}
}
Composant affiché
Routes paramétrées
Liens de routeur
Par défaut, le composant est affiché comme enfant de l’UI
Comment faire pour l’afficher sur un autre parent ?
@Route.layout
Configure le composant sur lequel le composant doit être affiché
Le composant doit implémenter RouterLayout
@Route(layout = ParentView.class)
public class AView extends VerticalLayout { }
public class ParentView extends Div implements RouterLayout { }
Si le parent doit lui-même avoir un parent, il existe @ParentLayout
Le parent configuré doit également implémenter RouterLayout
@Route(layout = ParentView.class)
public class AView extends VerticalLayout { }
@ParentLayout(RootLayout.class)
public class ParentView extends Div implements RouterLayout { }
public class RootLayout extends Div implements RouterLayout { }
Comment gérer les URL de type REST ?
Par exemple, person/1
@Route("person")
public class PersonView extends Div
implements HasUrlParameter<String> {
@Override
public void setParameter(BeforeEvent event,
String person) {
setText("Hello " + person + "!"); (1)
}
}
1 | person/Doe |
@Route("person")
public class PersonView extends Div
implements HasUrlParameter<String> {
@Override
public void setParameter(BeforeEvent event,
@OptionalParameter String person) {
if (person == null) {
setText("Hello nobody!"); (1)
} else {
setText("Hello " + person + "!"); (2)
}
}
}
1 | person |
2 | person/Doe |
@Route("person")
public class PersonView extends Div
implements HasUrlParameter<String> {
@Override
public void setParameter(BeforeEvent event,
@OptionalParameter String person) {
if (person.isEmpty()) {
setText("Hello nobody!"); (1)
} else {
setText("Hello " + person.split()[0] + "!"); (2)
}
}
}
1 | person |
2 | person/Doe/John |
Permet de construire un lien vers un composant
new RouterLink("Say hello", HelloView.class, "John");
public class HelloView extends Div
implements HasUrlParameter<String> {
@Override
public void setParameter(BeforeEvent event,
String name) {
setText("Hello " + name + "!");
}
}
Implémentation du pattern Observer
Présent dans tous les clients lourds :
Swing/AWT
SWT
Flex
JavaFX
Mais pas dans le web…
Tous les Component
sont des Subject
Génèrent des évènements en fonction :
Du type de composant
Du type de déclencheur
Button
génère :
FocusEvent
BlurEvent
ClickEvent
Toute classe peut implémenter Observer
Par exemple, l’UI
Du JavaScript implémente le code serveur
Une interaction client-serveur se traduit par un appel AJAX
Notion d’abonnement portée par une interface
N’importe laquelle :
Une classe anonyme
Une classe dédiée
Porte l’information du comportement avec sa déclaration
Perte de la référence sur le comportement
Couplage fort
new Button("Click me!").addClickListener(
new ComponentEventListener<ClickEvent<Button>>() {
@Override
public void onComponentEvent(ClickEvent<Button> e) {
...
}
}
);
new Button("Click me!").addClickListener(event -> {
...
});
Entièrement orienté objet
Lisible
Changement dynamique possible
Séparation des responsabilités
Nommage sémantique
Verbeux
public class SendFormBehavior
implements ComponentEventListener<ClickEvent<Button>> {
@Override
public void onComponentEvent(ClickEvent<Button> e) {
...
}
}
Couplage entre l' Observer et son sujet
Transport event occurrences from sources to subscribers, where event sources signal event occurrences to all event subscribers and event subscribers receive event occurrences.
Vaadin Spring Boot’s Event Bus
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<Country> {
public CountryComboBox(EventBus bus) {
addValueChangeListener(event -> {
bus.post(new CountryChangedEvent(event.getValue()));
});
}
}
public class CityComboBox extends ComboBox<City> {
@Subscribe
public void changeCities(CountryChangedEvent event) {
// Refresh cities
}
}
@Route
public class SampleView extends VerticalLayout {
public SampleView() {
EventBus eventBus = new EventBus();
CountryComboBox countries = new CountryComboBox(eventBus);
CityComboBox cities = new CityComboBox();
eventBus.register(cities);
add(countries, cities);
}
}
A component that supports input validation.
ComboBox combo = new ComboBox();
...
combo.setInvalid(true);
combo.setErrorMessage("Invalid selection");
Gère les erreurs inattendues
Par exemple, les exceptions
Informe l’utilisateur par l’affichage d’un composant contextuel
A generic interface for field components and other user interface objects that have a user-editable value that should be validated.
XXXRangeValidator :
Types wrapper numériques
BigInteger
& BigDecimal
Date
& DateTime
BeanValidator
RegexpValidator
EmailValidator
StringLengthValidator
public class EmailField extends TextField implements HasValidator<String> {
public EmailField() {
addValueChangeListener(event -> {
ValidationResult r = getDefaultValidator().apply(getValue(), null);
if (r.isError()) { setToInvalid(r.getErrorMessage()); }
else { resetToValid(); }
});
}
@Override
public Validator<String> getDefaultValidator() {
return new EmailValidator("Value " + getValue() + " is not an email");
}
}
Gestion évènementielle du changement d’état du modèle vers un composant graphique
Et vice-versa
Propriété p.e. email
Bean p.e Person
Liste de beans
A generic interface for field components and other user interface objects that have a user-editable value. Emits change events whenever the value is changed, either by the user or programmatically.
Connects one or more Field components to properties of a backing data type such as a bean type.
Binder<Person> binder = new Binder<>(Person.class);
binder.setBean(new Person());
TextField firstNameField = new TextField("Given name");
TextField lastNameField = new TextField("Family name");
DatePicker birthdateField = new DatePicker("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();
LocalDate birthdate = person.getBirthDate();
Mixin interface for components that displays a collection of items.
List<Person> persons = ...;
ListDataProvider<Person> provider =
new ListDataProvider<>(persons);
Grid<Person> grid = new Grid<>(Person.class);
grid.setDataProvider(provider);
grid.setColumns("firstName", "lastName", "birthdate");
Server-side component for the <vaadin-grid> element.
Indique les colonnes visibles
Mais également leur ordre
Grid<Person> grid = new Grid<>(Person.class);
grid.setColumns("firstName", "lastName");
Par défaut, inféré du nom de l’attribut
Grid<Person> grid = new Grid<>(Person.class);
grid.getColumn("firstName")
.setHeader("Prénom");
Récupère la valeur de l’attribut
Utilise le Renderer
pour la transformer en String
Affiche la String
dans la cellule
Grid<Person> grid = new Grid<>(Person.class);
grid.addColumn(
new LocalDateRenderer<>(Person::getBirthdate, "")
);
grid.addColumn(new NativeButtonRenderer<>(
"Click me!",
event -> Notification.show("Hello world!"))
);