SlideShare ist ein Scribd-Unternehmen logo
1 von 160
Downloaden Sie, um offline zu lesen
T7.A02
JDEV 2015
François ANDRE
Guillaume BRISSEBRAT
Alexandre JOURNAUX
OMP, INRA
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
LICENCE
Le contenu de cette présentation est publié sous la licence :
Creative Commons Attribution 4.0 International License
La copie de cette présentation est autorisée sous réserve du respect
des conditions de la licence (creativecommons.org/licenses/by/4.0/).
2
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CODE SOURCE
Le code source du TP est disponible à l’adresse suivante:
https://github.com/francoisandre/gwtjdev2015
Afin de pouvoir repartir sur une situation propre sur un exercice plusieurs
branches correspondant à chaque fin d’exercice sont mise à disposition.
Elles sont signalées en fin chaque branche correspond à la fin d’un exercice.
Cela permet de pouvoir passer à un nouvel exercice.
Les branches sont signalées de la manière suivante:
NomDeLaBranche
3
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MACHINE VIRTUELLE
Une machine virtuelle de type VirtualBox comportant les outils
nécessaires et le code source du TP est disponible à l’adresse
suivante:
http://jdev2015.sedoo.fr/Stagiaire%20GWT-c.ova
Afin de récuperer le code du TP effectuez la procédure suivante :
Ouvrir Eclipse
Sélectionner File > Import...
Dans la liste des types de projets, séléctionner Git > Projects from Git et appuyer sur
Next
Séléctionner Existing local repository et appuyer sur Next
Dans la liste des dépots Git, séléctionner git /home/user/git/.git et appuyer sur Next
Dans l’étape relative au Wizard appuyer directement sur Next
Appuyer sur Finish
4
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
SOMMAIRE
1. Introduction
2. Architecture
3. Premi`ere application
4. Cr´eation de l’interface
graphique
5. Bus d’´ev`enements
6. Cin´ematique de l’application
7. Communication client-serveur
8. Conclusion
5
INTRODUCTION
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
QUELQUES QUESTIONS...
Comment faire une Single Page Application ?
Où doit se situer un traitement ?
Android ou iOS ?
Des gens utilisent-ils encore IE6 ?
Comment économiser les ressources ?
Comment faire une boucle en Javascript ?
Comment déboguer ou lister les appels d’une fonction en
Javascript ?
Pourquoi ne puis-je pas faire du Swing ?
Le client-serveur, ça avait son charme, non ?
Pourquoi mon application n’est-elle toujours pas finie ?
C’est pas plus rapide en PHP ?
Google n’a-t-il pas arrêté GWT ?
7
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
FIABLILITÉ DE LA CIBLE CSS+HTML5+JAVASCRIPT
8
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE RÉPONSE POSSIBLE
GWT
9
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE IDÉE SIMPLE
Coder la partie cliente en Java
La compiler en JavaScript
10
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
AVANTAGES PRINCIPAUX
Intégré dans l’écosystème JEE
Relié à l’écosystème HTML/Javascript
11
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
REPÈRE HISTORIQUES
Chronologie succincte :
2006 v1.0
...
2009 v2.0
...
Janvier 2014 v2.6.0
Novembre 2014 v2.7.0
Futur
Évolutions WEB : HTML5, W3C Web Components ...
Évolutions Java : Support Java 8 ...
Évolutions GWT : Integration Javascript ...
12
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
PLUS D'INFORMATIONS
Site officiel : http://www.gwtproject.org/
Démonstration officielle :
http://samples.gwtproject.org/samples/Showcase/Showcase.html
Communauté
https://groups.google.com/forum/#!forum/google-web-toolkit
https://plus.google.com/communities/116543000751323604177
Conférences en ligne :
GWT Create (http://gwtcreate.com/)
Google I/O (chaîne Youtube)
Blogs :
Gwt Daily (http://www.gwtdaily.com/)
Sami Jabber (http://www.samijaber.com/)
Tutoriels :
http://courses.coreservlets.com/Course-Materials/gwt.html
13
ARCHITECTURE
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
ELÉMENTS MIS EN ŒUVRE
15
TWITTER BOOTSTRAP
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
TWITTER BOOTSTRAP
Description : Collection d’outils HTML/CSS/Javascript
Objectif : Compenser l’aspect brut des composants GWT
Rendu moderne
Site web
adaptatif (RWD)
Grande
Popularité
17
SPRING FRAMEWORK
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
SPRING FRAMEWORK
Description : Framework Java permettant la mise en place d’un
conteneur léger
Objectif : Simplification de l’architecture et fiabilisation du code
Inversion de
contrôle (IoC)
Bibliothèques
complémentaires
(accès aux
données, ...)
19
JPA : JAVA PERSISTENCE API
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
JPA : JAVA PERSISTENCE API
Description : API officielle de Mapping Objet-SGBD
Objectif : Simplifier la mise en œuvre de la persistance
Définition du mapping via annotation
Interrogation via JPQL
21
MAVEN
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MAVEN
Description : Moteur de production
Objectif : Fiabilise les étapes clés du développement (compilation,
test, génération, livraison,...)
Le fichier pom.xml : configuration globale du projet
Arborescence
/src Sources du projet
/src/main Partie principale
/src/main/java Code source
/src/main/resources Fichier de ressources (images, config, ...)
/src/main/webapp Webapp du projet
/src/test Partie test
/src/test/java Code source des tests
/src/test/resources Fichiers de ressources des tests
/target Fichiers produits (classes, .war, .jar)
Compatibilité avec les outils d’intégration continue (Jenkins...)
23
ECLIPSE
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
ECLIPSE
Description : Environnement de développement intégré (EDI)
Objectif : Édition des sources, lien avec le SCM, débogage
GWT ne nécessite pas d’EDI particulier. D’autres EDI (IntelliJ,
Netbeans, vi) peuvent être utilisés.
L’équipe Google fournit un module (plugin) pour Eclipse proposant
certaines fonctionnalités utiles :
Génération
Validation
...
Remarque:
Distribution privilégiée : Eclipse IDE for Java EE Developers
25
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
PLUGIN GWT (NAVIGATEUR)
Classical dev mode
Jusqu’à la version 2.6.0, le développement GWT - Dev Mode - repose
sur un module installé sur le navigateur (Chrome, Firefox, IE, Safari).
Ce mode est contraignant pour les développeur de GWT pour les
raisons suivantes :
Le nombre de navigateurs
Les API propriétaires sous jacentes
De plus, lorsque la taille de l’application augmente le temps de
rafraichissement devient bloquant.
Super dev mode
Depuis la version 2.4.0 il est progressivement remplacé par le Super
Dev Mode qui permet de débugger dans les navigateurs supportant le
standard SourceMaps (Chrome, Firefox).
Le plugin SDBG permet de conserver un débuggage dans Eclipse.
26
PREMIÈRE APPLICATION
EXERCICE 1 : GÉNÉRATION D'UN
SQUELETTE APPLICATIF
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
PRÉREQUIS LOGICIEL
Prérequis:
JVM (1.7 conseillée)
Maven / Ant
Eclipse avec les plugins
Egit
M2E
Plugin GWT (via Eclipse Market Place)
SDBG (update site: http://sdbg.github.io/p2)
StartExplorer (via Eclipse Market Place)
SDK GWT (2.7.0)
Chrome (avec SourceMap enabled)
29
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
GÉNÉRATION D'UN SQUELETTE APPLICATIF
Utilisation de webAppCreator (utilitaire fourni dans le SDK)
Etape 1 : Génération squelette
/home/user/Développement/gwt-2.7.0/webAppCreator -noant -maven -XnoEclipse
fr.jdev.atelier.MonApplication
Etape 2 : Import dans Eclipse
Import... > Maven > Existing Maven Projects
Etape 3 : Modification fichier pom.xml
Ajouter la version <version>$gwtVersion</version> dans les dépendances
<groupId>com.google.gwt</groupId> <dependency> :
...
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>$gwtVersion</version>
<scope>runtime</scope>
</dependency>
...
30
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
GÉNÉRATION D'UN SQUELETTE APPLICATIF
Etape 4 : Modifications des propriétés du projet
Google > Web toolkit : cocher Use Google Web Toolkit
Google > Web application :
Cocher This project has a WAR directory
Dans la zone de saisie WAR directory indiquer src/main/webapp
Décocher Launch and deploy... si nécessaire
FinExercice1
31
EXPLORATION DU SQUELETTE
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXPLORATION DU SQUELETTE
Architecture Maven classique
/src/main/java
/src/main/resources
/src/main/webapp
...
Architecture GWT classique
Package client Classes de la partie cliente (⇒ Javascript)
Package shared
Classes communes client & serveur
(⇒ Javascript & Java)
Package server
Classes de la partie serveur
(⇒ Application JEE standard)
33
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CONTRAINTES PACKAGE CLIENT & SHARED
Les classes doivent utiliser/étendre le JDK émulé par GWT
(http://www.gwtproject.org/doc/latest/RefJreEmulation.html)
Exemples :
Autorisé: Object, HashMap, ArrayList,
com.google.common.base.Strings (Guava)...
Interdit : File, StringUtils (commons-lang), ...
Les classes transitant entre client et serveur doivent être
sérialisables:
• implémenter java.io.Serializable
• implémenter com.google.gwt.user.client.rpc.IsSerializable
des beans:
• Constructeur vide
• Getters et Setters
34
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
DESCRIPTEUR DU MODULE: MONAPPLICATION.GWT.XML
Rôle
Pilotage de l’application
Position
au dessus du package client
Contenu
Nom du module <module>
Point d’entrée
<entry-point class=’fr.jdev.atelier.client.MonApplication’ />
Autres modules à importer : <inherits>
Répertoires : <source>
Paramètres divers: langues...
Remplacement dynamique des classes
<replace-with class="fr.sedoo.sssdata.client.ClientFactoryImpl">
<when-type-is class="fr.sedoo.sssdata.client.ClientFactory"/>
</replace-with>
35
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CONTENEUR HTML MONAPPLICATION.HTML
Rôle
Chargement de l’application
Position
Dans le répertoire webapp
Contenu
Page HTML classique (js, css, balises HTML...)
Chargement du module
<script type="text/javascript" language="javascript"
src="monapplication/monapplication.nocache.js"></script>
Remarque: le script nocache.js charge la compilation adéquate
du module :
La plus récente
Correspondant au navigateur du client et à sa langue
36
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
COMPILATION ET PERMUTATIONS
Lors de la compilation Javascript, GWT génère une tradution pour
chaque couple
moteur de navigateur supporté (6)
langue indiquée dans le descripteur de module
Les permutations sont une des nombreuses optimisations fournies par
GWT.
37
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
ENTRY POINT
Rôle
Équivalent de main dans les application Java
Position
Dans le package client
Conformément au fichier gwt.xml
Contenu
Implémente com.google.gwt.core.client.EntryPoint
→ public void onModuleLoad();
• Construit les éléments de l’interface utilisateur
• Optionnellement, supprime certains éléments du conteneur HTML
Exemple : suppression du contenu de l’élément d’identifiant loadingMessage
RootPanel loadingMessage = RootPanel.get("loadingMessage");
DOM.setInnerHTML(loadingMessage.getElement(), "");
• Ajoute l’interface utilisateur dans le conteneur HTML
Exemple : En vidant completement le conteneur HTML
Label myLabel = new Label("Hello JDEV");
RootPanel.get().clear();
RootPanel.get().add(myLabel);
38
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
AUTRES FICHIERS REMARQUABLES
Configuration Maven
/pom.xml
Configuration application web
/src/main/webapp/WEB-INF/web.xml
39
EXERCICE 2 : EXÉCUTION ET
DÉBOGAGE
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
LANCEMENT DE L'APPLICATION
Le lancement de l’application se fait classiquement via les menus
Debug As ou Run As
Le moteur de lancement à utiliser est Web Application ou Web
Application (GWT Super Dev Mode)
41
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
LANCEMENT DE L'APPLICATION
Lors du lancement, deux applications sont exécutées dans l’ordre
suivant :
Le serveur de complitation Java →Javascript
...
The code server is ready at http://127.0.0.1:9876
...
L’application proprement dite. Celle-ci est utilisable lors que son URL s’affiche dans
l’onglet Development
42
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
TEST DE L'APPLICATION
Le lancement de l’URL déclenche la compilation Java
→Javascript.
Une fois compilée l’application apparait normalement
43
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
TEST DE L'APPLICATION
Remarques
La première compilation suivant un démarrage de l’application est
longue
Les autres compilations sont plus rapides car incrémentales (ne
portent que sur les fichiers modifiés entre temps)
Le code java peut être vu via Chrome (via la technologie
SourceMaps)
44
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
DEBOGAGE AVEC LE PLUGIN ECLIPSE SDBG
SDBG permet d’intercepter de piloter le débogage SourceMaps
dans Eclipse
Etape 1 : Création d'un lanceur chrome
Ouvrir la fenêtres des lanceurs de débogage (Debug configurations...)
Sélectionner Launch Chrome
Cliquer sur le bouton droit et sélectionner New
Dans la fenêtre qui s’ouvre indiquer les valeurs suivantes :
Name : Mon Application SDBG
URL : http://127.0.0.1:8888/MonApplication.html
Project : sélectionner le projet MonApplication
Remarque : Dans l’onglet Common on peut cocher l’option Debug du bloc Display in
favorites menu
Cliquer sur Apply puis sur Debug
L’application doit être lancée auparavant
45
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
DEBOGAGE AVEC LE PLUGIN ECLIPSE SDBG
Etape 2 : Mise en place d'un point d'arrêt
Dans la classe FieldVerifier positionner un point d’arrêt en début de la méthode
isValidName
Dans l’application cliquer sur Send
Le point d’arrêt va se déclencher deux fois
Côté client : suite à l’appel de sendNameToServer
Côté serveur : suite à l’appel de greetServer
Remarques :
le plugin SDBG est en amélioration permanente
• Pour la gestion du rechargement à chaud
• Pour l’affichage des contenus des variables
le plugin SDBG est désactivé lorsque l’inspecteur Chrome est
activé.
46
CRÉATION DE L'INTERFACE
GRAPHIQUE
COMPOSANTS DE BASES
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
COMPOSANTS DE BASE
GWT propose un certain nombre de composants de base pour
construire les interfaces:
Widgets élémentaires: boutons, zones de texte, cases à cocher...
Panneaux de positionnement (similaires à Swing): panneaux
horizontaux, verticaux, à onglets...
Comme en Swing, ces éléments sont des classes Java et se
combinent afin de créer l’interface souhaitée.
49
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
WIDGETS ÉLÉMENTAIRES
Étendent com.google.gwt.user.client.ui.Widget
Exemples :
TextBox
TextArea
Button
RadioButton
CheckBox
DatePicker, CellList...
50
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
PANNEAUX DE POSITIONNEMENT
Panneaux classiques
(étendent com.google.gwt.user.client.ui.Panel)
Exemples :
HorizontalPanel
VerticalPanel
FlowPanel
HTMLPanel
Permet de mixer des balises HTML et des com-
posants GWT
Remarque: les panneaux héritent aussi de Widget
51
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
PANNEAUX DE POSITIONNEMENT
Panneaux dynamiques
(implémentent
com.google.gwt.user.client.ui.ProvidesResize et
com.google.gwt.user.client.ui.RequiresResize )
Exemples :
DockLayoutPanel
SplitLayoutPanel
TabLayoutPanel
52
EXERCICE 3 : YET ANOTHER TODO
LIST - UNE PREMIERE IHM
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE PREMIÈRE IHM
Etape 1 : Suppression du contenu du contenur HTML
Dans le fichier MonApplication.html vider le contenu de la balise
<body> à l’exception de la balise <noscript> (et de son cotenu).
Etape 2 : Modification de la fonction onModuleLoad
Modifier le fichier suivant MonApplication.java de la manière
suivante:
public class MonApplication implements EntryPoint {
public void onModuleLoad() {
DockLayoutPanel mainContent = new DockLayoutPanel(Unit.PX);
mainContent.getElement().getStyle().setMargin(5, Unit.PX);
mainContent.addNorth(new Label("Ma Todo List"), 25);
VerticalPanel taskForm = new VerticalPanel();
taskForm.setSpacing(5);
taskForm.add(new Label("Ma tâche"));
TextBox description = new TextBox();
description.setTitle("Description");
TextBox responsible = new TextBox();
responsible.setTitle("Responsible");
DateBox deadLine = new DateBox();
taskForm.add(description);
taskForm.add(responsible);
taskForm.add(deadLine);
mainContent.add(taskForm);
RootLayoutPanel.get().add(mainContent);
}
}
54
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE PREMIÈRE IHM
FinExercice3a
55
LIBRAIRIES COMPLÉMENTAIRES
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
LIBRAIRIES COMPLÉMENTAIRES
Solutions spécifiques en GWT :
Sencha GXT (http://www.sencha.com/products/gxt/)
Vaadin (https://vaadin.com/home)
Sencha GXT
57
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
LIBRAIRIES COMPLÉMENTAIRES
Portage de libraries Javascript :
GWTBootstrap3 (https://github.com/gwtbootstrap3)
Gwt-Openlayers (http://www.gwt-openlayers.org/)
Exemple GWTBootstrap3 :
Alert loginFirst = new Alert("You must connect to access to this page");
Remarque: un portage Javascript (Wrapping) peut occasionner un débogage plus difficile.
58
EXERCICE 3 : YET ANOTHER TODO
LIST - UNE IHM BOOTSTRAP
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE IHM BOOTSTRAP
Etape 1 : Ajout dépendance Maven
Dans le fichier pom.xml ajouter les dépendances suivantes
...
<dependency>
<artifactId>gwtbootstrap3</artifactId>
<groupId>org.gwtbootstrap3</groupId>
<version>0.9</version>
</dependency>
<dependency>
<groupId>org.gwtbootstrap3</groupId>
<artifactId>gwtbootstrap3-extras</artifactId>
<version>0.9</version>
</dependency>
...
Etape 2 : Modification du fichier MonApplication.gwt.xml
Modifier le fichier suivant MonApplication.gwt.xml ajouter la ligne
suivantes
<inherits name="org.gwtbootstrap3.GwtBootstrap3"/>
Etape 3 : Redémarrage de l'application
Une fois les modifications faites, redémarrer l’application.
60
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE IHM BOOTSTRAP
Etape 4 : Modification de la fonction onModuleLoad
Modifier le fichier suivant MonApplication.java de la manière
suivante:
package fr.jdev.atelier.client;
import org.gwtbootstrap3.client.ui.Container;
import org.gwtbootstrap3.client.ui.Heading;
import org.gwtbootstrap3.client.ui.Jumbotron;
import org.gwtbootstrap3.client.ui.TextBox;
import org.gwtbootstrap3.client.ui.constants.HeadingSize;
...
public class MonApplication implements EntryPoint {
public void onModuleLoad() {
Jumbotron jumbotron = new Jumbotron();
Container container = new Container();
Heading heading = new Heading(HeadingSize.H1);
heading.setText("Ma Todo List");
container.add(heading);
jumbotron.add(container);
VerticalPanel mainContent = new VerticalPanel();
mainContent.setWidth("100%");
VerticalPanel taskForm = new VerticalPanel();
taskForm.setSpacing(5);
taskForm.add(new Label("Ma tâche"));
TextBox description = new TextBox();
description.setPlaceholder("Description");
TextBox responsible = new TextBox();
responsible.setPlaceholder("Responsible");
DateBox deadLine = new DateBox();
taskForm.add(description);
taskForm.add(responsible);
taskForm.add(deadLine);
mainContent.add(jumbotron);
mainContent.add(taskForm);
RootPanel.get().add(mainContent);
}
}
61
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE IHM BOOTSTRAP
FinExercice3b
62
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CRÉATION DE COMPOSANTS
Par héritage d’un Widget :
Exemple: création d’une infobulle d’aide Classe :
Utilisation :
HelpTooltip aide = new HelpTooltip("mon texte d’aide");
monPanneau.add(aide);
Résultat :
63
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CRÉATION DE COMPOSANTS
Par héritage d’un Composite :
Objectif: Permet de créer un composant en combinant
plusieurs Widgets sans en exposer les méthodes.
Attention : il est nécessaire d’appeler la fonction initWidget sur
un des composants lors du constructeur.
64
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CRÉATION DE COMPOSANTS
Par implémentation de l’interface IsWidget :
Le Widget est retourné par la méthode asWidget().
65
EXERCICE 3 : YET ANOTHER TODO
LIST - CRÉATION DE COMPOSANTS
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CRÉATION DE COMPOSANTS
Etape 1 : Création du composant HelpTooltip
Créer la classe HelpTooltip suivante :
public class HelpTooltip extends Popover {
@UiConstructor
public HelpTooltip(String text) {
super();
Icon helpIcon = new Icon(IconType.QUESTION_CIRCLE);
helpIcon.setSize(IconSize.LARGE);
add(helpIcon);
setTitle("");
setContent(text);
}
public HelpTooltip(String text, Placement placement) {
this(text);
setPlacement(placement);
}
public void setText(String text) {
setContent(text);
}
}
67
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE IHM BOOTSTRAP
Etape 2 : Création du composant TaskCreationPanel
Créer la classe TaskCreationPanel suivante :
public class TaskCreationPanel implements IsWidget {
private VerticalPanel mainContainer;
private TextBox description;
private TextBox responsible;
private DateBox deadLine;
public TaskCreationPanel() {
mainContainer = new VerticalPanel();
mainContainer.setSpacing(5);
mainContainer.add(new Label("Ma tâche"));
description = new TextBox();
HorizontalPanel descriptionPanel = new HorizontalPanel();
descriptionPanel.add(description);
descriptionPanel.add(new HelpTooltip("Indiquez ici la description"));
description.setPlaceholder("Description");
responsible = new TextBox();
responsible.setPlaceholder("Responsible");
deadLine = new DateBox();
mainContainer.add(descriptionPanel);
mainContainer.add(responsible);
mainContainer.add(deadLine);
}
@Override
public Widget asWidget() {
return mainContainer;
}
}
68
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UNE IHM BOOTSTRAP
Etape 3 : Modificiation de MonApplication
Modifier la classe MonApplication de la manière suivante :
...
public void onModuleLoad() {
Jumbotron jumbotron = new Jumbotron();
Container container = new Container();
Heading heading = new Heading(HeadingSize.H1);
heading.setText("Ma Todo List");
container.add(heading);
jumbotron.add(container);
VerticalPanel mainContent = new VerticalPanel();
mainContent.setWidth("100%");
mainContent.add(jumbotron);
TaskCreationPanel taskCreationPanel = new TaskCreationPanel();
mainContent.add(taskCreationPanel);
RootPanel.get().add(mainContent);
}
...
FinExercice3c
69
UIBINDER
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UIBINDER : MOTEUR DE TEMPLATES
Rôle
Simplifier la création d’écran complexes avec un moteur de
templates
Principe
Un fichier de description, monFichier.ui.xml, permet de définir
l’écran de manière similaire à une page HTML/JSP...
Dans ce fichier les noms des balises importantes sont indiqués
via l’attribut ui:field
Une classe, monFichier.java permet de définir le comportement
dynamique associé à cet écran.
Cette classe étend Composite
Dans cette classe on retrouve le nom des attributs ui:field
indiqués dans le fichier de description
71
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UIBINDER : EXEMPLE
Descripteur : MetadataSearchViewImpl.ui.xml
72
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UIBINDER : EXEMPLE
Classe : MetadataSearchViewImpl.java
73
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UIBINDER : COMPLÉMENTS
Instantication des champs ui:field
Soit par le fichier de description lors de l’appel à initWidget
dans le constructeur :
initWidget(uiBinder.createAndBindUi(this));
Soit manuellement
• En modifiant l’annotation UiField : @UiField(provided = true)
• En instanciant les champs avant l’appel à initWidget.
Ajout de comportement sur les éléments
Via l’annotation @UiHandler
La signature de la méthode permet d’indiquer l’évènement géré
@UiHandler("searchButton")
void onSearchButtonClicked(ClickEvent event)
{
...
}
74
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UIBINDER : COMPLÉMENTS
Utilisation de Widgets personnels
La balise <ui:UiBinder> permet de définir via des espaces de
nommage les packages utilisables dans la page:
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:l="urn:import:fr.sedoo.metadata.client.ui.widget.date">
...
<l:Iso19115DateBox ui:field="startDate" />
Des paramètres peuvent être transmis dans les attributs.
Si le Widget possède plusieurs constructeurs, l’annotation
@UiConstructeur permet d’indiquer celui que UiBinder va utiliser.
75
EXERCICE 3 : YET ANOTHER TODO
LIST - UTILISATION UIBINDER
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UTILISATION UIBINDER
Etape 1 : Ajouter la classe Task
Dans le package shared ajouter la classe suivante :
public class Task implements IsSerializable {
private String description;
private String responsible;
private Date deadLine;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getResponsible() {
return responsible;
}
public void setResponsible(String responsible) {
this.responsible = responsible;
}
public Date getDeadLine() {
return deadLine;
}
public void setDeadLine(Date deadLine) {
this.deadLine = deadLine;
}
}
77
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UTILISATION UIBINDER
Etape 2 : Ajouter la classe NewTaskCreationPanel
Dans le package client ajouter la classe suivante :
public class NewTaskCreationPanel extends Composite {
@UiField
TextBox description;
@UiField
TextBox responsible;
@UiField
DateTimePicker deadLine;
private static LocalUiBinder uiBinder = GWT.create(LocalUiBinder.class);
interface LocalUiBinder extends UiBinder<Widget, NewTaskCreationPanel> {
}
public NewTaskCreationPanel() {
super();
initWidget(uiBinder.createAndBindUi(this));
}
public void reset() {
description.setText("");
responsible.setText("");
deadLine.setValue(null);
}
public Task flush() {
Task result = new Task();
result.setResponsible(responsible.getText());
result.setDescription(description.getText());
result.setDeadLine(deadLine.getValue());
return result;
}
}
78
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UTILISATION UIBINDER
Etape 3 : Ajouter le fichier NewTaskCreationPanel.ui.xml
Dans le package client ajouter le fichier NewTaskCreationPanel.ui.xml
avec le contenu suivant :
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:b="urn:import:org.gwtbootstrap3.client.ui"
xmlns:b2="urn:import:org.gwtbootstrap3.extras.datetimepicker.client.ui"
>
<g:HTMLPanel width="90%">
<h2>Enter a new task</h2>
<form class="form-horizontal" >
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Description</label>
<div class="col-sm-10">
<b:TextBox placeholder="Enter description" ui:field="description" />
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Responsible</label>
<div class="col-sm-10">
<b:TextBox placeholder="Enter responsible" ui:field="responsible"/>
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Dead line</label>
<div class="col-sm-10">
<b2:DateTimePicker ui:field="deadLine"/>
</div>
</div>
</form>
</g:HTMLPanel>
</ui:UiBinder>
79
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UTILISATION UIBINDER
Etape 4 : Modification du fichier MonApplication.gwt.xml
Dans le fichier MonApplication.gwt.xml ajouter la ligne suivantes
<inherits name="org.gwtbootstrap3.extras.datetimepicker.DateTimePicker"/>
Etape 5 : Modification de la fonction onModuleLoad
Dans le fichier MonApplication.java modifier la fonction
onModuleLoad
public void onModuleLoad() {
Jumbotron jumbotron = new Jumbotron();
Container container = new Container();
Heading heading = new Heading(HeadingSize.H1);
heading.setText("Ma Todo List");
container.add(heading);
jumbotron.add(container);
VerticalPanel mainContent = new VerticalPanel();
mainContent.setWidth("100%");
mainContent.add(jumbotron);
NewTaskCreationPanel taskCreationPanel = new NewTaskCreationPanel();
mainContent.add(taskCreationPanel);
RootPanel.get().add(mainContent);
}
80
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UTILISATION UIBINDER
FinExercice3d
81
CLIENTFACTORY
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CLIENTFACTORY
Objectif : Optimiser le temps d’instanciation des objets
complexes
Problème : Certains composants clients sont coûteux à
instancier notamment les différents éléments de l’interface
graphique.
Solution : Utiliser une Factory ayant la charge d’instancier de
manière unique - et si nécessaire - ces différents composants et
de les transmettre aux objets voulant les utiliser (Exemple: le
Presenter dans le modèle MVP) .
Remarque
Par ce mécanisme, les écrans graphiques ne sont créés qu’une seule fois. Ils sont par contre
remis à zéro (exemple : vidage des champs de saisie) lors de chaque utilisation.
Ce concept de Singleton est aussi étendu pour gérer les autres
instances uniques de l’application comme par exemple le bus
d’évènements (cf. infra). 83
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE
La mise en place de la ClientFactory et Activity est effectuée de
la manière suivante:
1. Création de l’interface (ClientFactory) et d’une ou plusieurs de ses
implémentations (ex ClientFactoryImpl,
ClientFactoryMobileImpl...) dans le package client.
2. Déclaration dans le descripteur de module
<replace-with
class="fr.jdev.atelier.client.ClientFactoryImpl">
<when-type-is class="fr.jdev.atelier.client.ClientFactory" />
</replace-with>
Dans cet exemple la classe, au moment de la compilation Java
vers Javascript, ClientFactory sera remplacée par
ClientFactoryImpl lorsqu’elle est appellée via GWT.create(). On
peut imaginer des statégies plus fines (en fonction du
périphérique client, ...)
3. Instanciation du singleton, normalement dans le onModuleLoad.
clientFactory = GWT.create(ClientFactory.class);
84
BUS D'ÉVÈNEMENTS
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
BUS D'ÉVÈNEMENTS
Objectif : Simplifier la communication entre les composants
Problème : Les interfaces des applications GWT peuvent
contenir de nombreux composants qui doivent dialoguer entre
eux. Toutefois, dans certains cas ce dialogue ne peux pas se
faire directement
Pour éviter un trop fort couplage entre les classes.
Parce que les composants cibles du dialogue ne peuvent pas être
connus du composant source.
Solution : GWT propose un bus permettant l’échange
d’évènements entre composants reposant sur un mécanisme
d’abonnement:
1. Un type d’évènement spécifique est défini.
2. Les composants cibles s’abonnent à ce type d’évènement auprès
du bus.
3. Lorsque nécessaire, le composant source instancie un évènement
et demande sa propagation sur le bus.
86
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
DÉFINITION D'UN ÉVÈNEMENT
Exemple : évènement signalant la connexion d’un utilisateur -
UserLoginEvent
Il est nécessaire de créer deux classes:
Le gestionnaire : UserLoginEventHandler
L’évènement : UserLoginEvent
Le gestionnaire
Interface qui sera implémentée par les classes écoutant
l’évènement
Doit étendre com.google.gwt.event.shared.EventHandler
87
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
DÉFINITION D'UN ÉVÈNEMENT
L’évènement
La classe doit étendre
com.google.gwt.event.shared.GwtEvent
Elle définit un attribut statique - traditionnellement nommé TYPE -
qui va identifier l’évènement et permettre de s’y abonner auprès
du bus.
88
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
ABONNEMENT ET PUBLICATION
Abonnement à un évènement
L’abonnement auprès du bus s’effectue via la méthode
addHandler en passant en paramètres le type de l’évènement et
le composant cible.
Celui-ci doit implémenter le Handler correspondant à
l’évènement :
EVENT_BUS.addHandler(UserLoginEvent.TYPE, monComposantCible);
Publication d’un évènement La diffusion d’un évènement sur le bus s’effectue de la
manière suivante :
UserLoginEvent monEvenement = new UserLoginEvent();
// Valorisation de l’objet monEvenement ...
EVENT_BUS.fireEvent(monEvenement);
89
EXERCICE 4 : AJOUT D'UN
ÉVÈNEMENT
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
AJOUT D'UN ÉVÈNEMENT
Etape 1 : Ajouter la classe NotificationEvent
Dans le package client.event ajouter la classe suivante :
public class NotificationEvent extends GwtEvent<NotificationEventHandler> {
public static final Type<NotificationEventHandler> TYPE = new Type<NotificationEventHandler>();
private String message;
public NotificationEvent(String message) {
this.setMessage(message);
}
@Override
protected void dispatch(NotificationEventHandler handler) {
handler.onNotification(this);
}
@Override
public com.google.gwt.event.shared.GwtEvent.Type<NotificationEventHandler> getAssociatedType() {
return TYPE;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
91
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
AJOUT D'UN ÉVÈNEMENT
Etape 2 : Ajouter l'interface NotificationEventHandler
Dans le package client.event ajouter l’interface suivante :
public interface NotificationEventHandler extends EventHandler {
void onNotification(NotificationEvent event);
}
Etape 3 : Ajouter l'interface ClientFactory
Dans le package client ajouter l’interface suivante :
public interface ClientFactory extends NotificationEventHandler {
EventBus getEventBus();
}
92
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
AJOUT D'UN ÉVÈNEMENT
Etape 4 : Ajouter la classe ClientFactoryImpl
Dans le package client ajouter la classe suivante :
public class ClientFactoryImpl implements ClientFactory {
private static final EventBus EVENT_BUS = new SimpleEventBus();
public ClientFactoryImpl() {
getEventBus().addHandler(NotificationEvent.TYPE, this);
}
@Override
public EventBus getEventBus() {
return EVENT_BUS;
}
@Override
public void onNotification(NotificationEvent event) {
Growl.growl(event.getMessage());
}
93
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
AJOUT D'UN ÉVÈNEMENT
Etape 5 : Modification du fichier MonApplication.gwt.xml
Modifier le fichier MonApplication.gwt.xml en ajoutant les lignes :
<inherits name="org.gwtbootstrap3.extras.growl.Growl"/>
<replace-with
class="fr.jdev.atelier.client.ClientFactoryImpl">
<when-type-is class="fr.jdev.atelier.client.ClientFactory" />
</replace-with>
94
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
AJOUT D'UN ÉVÈNEMENT
Etape 6 : Modification du fichier MonApplication.java
Modifier le fichier MonApplication.java de la manière suivante :
public class MonApplication implements EntryPoint {
private static ClientFactory clientFactory;
public static ClientFactory getClientFactory() {
if (clientFactory == null) {
clientFactory = GWT.create(ClientFactory.class);
}
return clientFactory;
}
public void onModuleLoad() {
clientFactory = getClientFactory();
Jumbotron jumbotron = new Jumbotron();
Container container = new Container();
Heading heading = new Heading(HeadingSize.H1);
heading.setText("Ma Todo List");
container.add(heading);
jumbotron.add(container);
VerticalPanel mainContent = new VerticalPanel();
mainContent.getElement().getStyle().setMargin(5, Unit.PX);
mainContent.getElement().getStyle().setBorderColor("white");
mainContent.getElement().getStyle().setBorderWidth(2, Unit.PCT);
mainContent.getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
mainContent.add(jumbotron);
NewTaskCreationPanel taskCreationPanel = new NewTaskCreationPanel();
mainContent.add(taskCreationPanel);
Button addButton = new Button("Add");
addButton.setIcon(IconType.PLUS);
addButton.setType(ButtonType.PRIMARY);
addButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
getClientFactory().getEventBus().fireEvent(new NotificationEvent("Task added..."));
}
});
mainContent.add(addButton);
mainContent.setWidth("98%");
RootPanel.get().add(mainContent);
}
}
95
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UTILISATION UIBINDER
FinExercice4
96
CINÉMATIQUE DE L'APPLICATION
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
TROIS COMPOSANTS STRUCTURANTS
La cinématique d’une application Ajax diffère d’une application
Web traditionnelle où le serveur joue un rôle de chef d’orchestre.
Les versions récentes de GWT ont introduit un certain nombre de
bonnes pratiques permettant la construction rigoureuse d’une
telle cinématique:
Gestion de l’historique
Activities and Places
Patron Model-View-Presenter
98
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
GESTION DE L'HISTORIQUE
Objectif : Permettre une gestion complète de l’historique,
notamment la navigation via les boutons Précédent/Suivant
Principe :
Chaque état de l’application est sérialisé sous forme d’une chaine
(token) ajoutée à l’URL actuelle sous forme d’un lien nommé
(c.a.d séparé par un #). Exemple :
http://sedoo.sedoo.fr/portailresif/#WelcomePlace:
Un évènement de type navigation (Précédent, Suivant,
Rafraichissement) déclenche un évènement de type
ValueChangeEvent.
99
GESTION DE L'HISTORIQUE
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
GESTION DE L'HISTORIQUE
Mise en œuvre :
Activation dans le conteneur HTML
<iframe src="javascript:’’" id="__gwt_historyFrame"
style="position:absolute;width:0;height:0;border:0"></iframe>
Une nouvelle étape dans l’historique est ajoutée en appelant
History.newItem(token)
Chaque objet voulant réagir aux évènement de l’historique s’abonne aux
History.addValueChangeHandler(). Chaque abonné devra déterminer
• si l’évènement le concerne
• comment reconstruire l’état correspondant au token.
101
ACTIVITIES AND PLACES
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
ACTIVITIES
Activity : Une activité est une fonctionnalité de l’application
effectuée par un utilisateur.
Exemples : LoginActivity, SearchActivity...
Une activité étend
com.google.gwt.activity.shared.AbstractActivity
Cycle de vie : La gestionnaire d’activité
(com.google.gwt.activity.shared.ActivityManager)
active et désactive les activités via les méthodes suivantes :
start
Invoquée lors du démarage de l’activité. A son is-
sue, l’activité doit fournir la vue lui correspondant.
mayStop
Invoquée pour savoir si l’activité en cours peut s’ar-
rêter.
onStop Invoquée lors de l’arrêt de l’activité.
onCancel
Invoquée lorsque le démarrage n’est pas termn-
iné mais que l’utilisateur a demandé le début d’une
autre activité.
103
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
PLACES
Place : Une place représente un état d’utilisation d’une activité. Il
doit pouvoir être sérialisé sous forme de token conformément au
mécanisme de gestion de l’historique.
Mise en œuvre :
Une place hérite de com.google.gwt.place.shared.Place.
Le tokenizer associé à la place hérite de
com.google.gwt.place.shared.PlaceTokenizer.
Il permet la sérialisation/désérialisation de l’état via les méthodes
suivantes :
getPlace Construit la place à partir du token.
getToken Sérialise la place sous forme de token.
Bonne pratique
A chaque instanciation d’une activité, une place va lui être transmise afin que l’activité recrée
son état.
104
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
NAVIGATION VIA LES PLACES
Les places sont le meilleur moyen de naviguer au sein d’une
application GWT.
Le mécanisme est le suivant:
1. Instanciation et valoriastion de la place souhaitée
2. Récupération de l’instance du PlaceController (Cf.
ClientFactory)
3. Appel de la méthode PlaceController.goTo(place)
4. Si la place souhaitée n’est pas la place en cours, l’activité
correspondante à la place est instanciée (cf. page suivante).
5. La méthode start de l’activité est appelée.
Remarques
Ce mécanisme est également celui utilisé lors de l’analyse d’une URL pointant sur une
place de l’application.
Le PlaceController utilise la méthode equals pour comparer place actuelle et
destination. Le cas échéant il peut être nécessaire de surcharger cette méthode
105
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
NAVIGATION VIA LES PLACES
La correspondance entre Place et Activity est effectuée de la
manière suivante:
1. Le PlaceController envoie un évènement de changement de
place (PlaceChangeEvent)
2. L’évènement est reçu par le gestionnaire d’activités
(ActivityManager)
3. Le gestionnaire d’activités utilise son ActivityMapper qui lui
indique l’activité à démarrer via la méthode
Activity getActivity(Place place);
La classe ActivityMapper est donc le composant central du
mécanisme.
Exemple
public Activity getActivity(Place place) {
if (place instanceof WelcomePlace)
{
return new WelcomeActivity((WelcomePlace) place, clientFactory);
}
...
}
106
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
NAVIGATION VIA LES PLACES
Activité A ActivityManager ActivityMapper Activité B PlaceController EventBus ClientFactory
évènement
crééPlaceB()
getPlaceController()
goTo(placeB)()
fireEvent(placeChangeRequestEvent(placeB))
onPlaceChangeRequest(PlaceChangeRequestEvent)(placeB)
mayStop()
fireEvent(placeChangeEvent(placeB))
onPlaceChange(placeB)
getActivity(placeB)
nouvelle activité B
onStop()
start()
107
PATRON MODEL-VIEW-PRESENTER
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
PATRON MODEL-VIEW-PRESENTER
GWT étend le traditionnel modèle MVC avec le patron MVP dans
lequel le Presenter tient le rôle central.
Nom Situation Rôle
Model Côté serveur Récupère les données (via les DAO).
View Côté client
Affichage des données transmises par le Presenter.
Transmet au Presenter les évènements importants
(exemple: click sur des boutons,...)
Presenter Côté client
Mobilise le Model et transmet les données à la vue.
Réagit aux évènements transmis par la vue afin nota-
ment de dialoguer avec le Model ou changer de Place
Stratégie
L’objectif est de postionner un maximum d’intelligence au niveau du Presenter afin
que celui-ci puisse fonctionner indifféremment avec plusieurs implémentations de View
(exemple: View pour un écran d’ordinateur de grande taille, View pour un mobile, View
ficitve pour les tests...).
La View est donc dépourvue de traitements outre ceux spécifiques à son
implémentation. Ceci permet de l’exclure plus ou moins de la chaine de test.
109
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
DIAGRAMME MVP
Presenter
ModelView
110
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
INTÉGRATION AVEC LE MODÈLE ACTIVITIES AND PLACES
L’activity joue le rôle du Presenter
111
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE D'UNE VIEW
Une View doit être définie sous forme d’une Interface qui étend
com.google.gwt.user.client.ui.IsWidget.
Le Presenter ne doit connaître que cette Interface.
Si la View doit pouvoir transmettre des informations au
Presenter, l’usage veut que celui-ci soit défini comme une
sous-interface de la View. Dans ce cas:
La View doit définir une methode setPresenter correspondante.
L’Activity doit implémenter le Presenter.
112
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
RÉCUPÉRATION DE LA VIEW PAR LE PRESENTER
Le lien entre une View et l’implémentation à utiliser dans le
contexte courant est fait par la ClientFactory.
Ceci permet d’envisager la mise en place de plusieurs
implémentations de ClientFactory:
pour les mobiles
pour les tests
...
113
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CINÉMATIQUE D'UTILISATION
Classiquement, la cinématique d’utilisation est la suivante:
1. L’Activity récupère l’instance de la View auprès de la
ClientFactory (dans sa méthode start)
2. Si nécessaire, utilise la méthode setPresenter de la View pour
permettre une communication View ⇒ Presenter.
3. L’Activity remet à zéro l’instance de la View (qui a peut être servi
au préalable)
4. L’Activity recherche auprès du Model les informations
nécessaires
5. L’Activity les transmet à la vue qui les positionne.
6. L’Activity affiche la vue via la commande
containerWidget.setWidget(view.asWidget());
114
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CINÉMATIQUE D'UTILISATION
ActivityManager MonActivité MaVue MonModèle ClientFactory
start()
getMaVue()
instance de MaVue
setPresenter(this)
reset()
chargeInformations()
afficheInformations()
affiche la vue
115
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
COMMUNICATION PRESENTER - MODEL
La communication entre le Presenter et le Model s’effectue via le
mécanisme GWT-RPC décrit dans la section suivante.
116
EXERCICE 5 : MISE EN PLACE MVP
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 1 : Modification du fichier MonApplication.gwt.xml
Dans le fichier MonApplication.gwt.xml ajouter les lignes suivantes :
<inherits name="com.google.gwt.activity.Activity" />
<inherits name="com.google.gwt.place.Place" />
Etape 2 : Modification du fichier Task.java
Dans le fichier Task.java ajouter les lignes suivantes :
private String uuid;
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
118
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 3 : Modification du fichier ClientFactory.java
Dans le fichier ClientFactory.java ajouter les lignes suivantes :
PlaceController getPlaceController();
WelcomeView getWelcomeView();
TaskConsultView getTaskConsultView();
TaskListView getTaskListView();
119
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 4 : Modification du fichier ClientFactoryImpl.java
Modifier le fichier ClientFactoryImpl.java de la manière suivante :
public class ClientFactoryImpl implements ClientFactory {
private static final EventBus EVENT_BUS = new SimpleEventBus();
private static final PlaceController PLACE_CONTROLLER = new PlaceController(EVENT_BUS);
WelcomeView welcomeView = new WelcomeViewImpl();
TaskListView taskListView = new TaskListViewImpl();
public ClientFactoryImpl() {
getEventBus().addHandler(NotificationEvent.TYPE, this);
}
@Override
public EventBus getEventBus() {
return EVENT_BUS;
}
@Override
public void onNotification(NotificationEvent event) {
Growl.growl(event.getMessage());
}
@Override
public PlaceController getPlaceController() {
return PLACE_CONTROLLER;
}
@Override
public WelcomeView getWelcomeView() {
return welcomeView;
}
@Override
public TaskConsultView getTaskConsultView() {
return null;
}
@Override
public TaskListView getTaskListView() {
return taskListView;
}
}
120
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 5 : Création de la classe WelcomePlace.java
Dans le package client.place ajouter la classe suivante :
public class WelcomePlace extends Place {
public static class Tokenizer implements PlaceTokenizer<WelcomePlace> {
public WelcomePlace getPlace(String token) {
return new WelcomePlace();
}
public String getToken(WelcomePlace place) {
return "";
}
}
}
121
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 6 : Création de la classe TaskListPlace.java
Dans le package client.place ajouter la classe suivante :
public class TaskListPlace extends Place {
public TaskListPlace() {
}
public static class Tokenizer implements PlaceTokenizer<TaskListPlace> {
public TaskListPlace getPlace(String token) {
return new TaskListPlace();
}
public String getToken(TaskListPlace place) {
return "";
}
}
}
122
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 7 : Création de la classe TaskConsultPlace.java
Dans le package client.place ajouter la classe suivante :
public class TaskConsultPlace extends Place {
private String taskUuid;
public TaskConsultPlace() {
}
public String getTaskUuid() {
return taskUuid;
}
public void setTaskUuid(String taskUuid) {
this.taskUuid = taskUuid;
}
public static class Tokenizer implements PlaceTokenizer<TaskConsultPlace> {
public TaskConsultPlace getPlace(String token) {
TaskConsultPlace place = new TaskConsultPlace();
place.setTaskUuid(token);
return place;
}
public String getToken(TaskConsultPlace place) {
return "";
}
}
}
123
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 8 : Création de la classe AppActivityMapper.java
Dans le package client.mvp ajouter la classe suivante :
public class AppActivityMapper implements ActivityMapper {
private ClientFactory clientFactory;
public AppActivityMapper(ClientFactory clientFactory) {
super();
this.clientFactory = clientFactory;
}
@Override
public Activity getActivity(Place place) {
if (place instanceof TaskConsultPlace) {
return new TaskConsultActivity((TaskConsultPlace) place, clientFactory);
} else if (place instanceof TaskListPlace) {
return new TaskListActivity((TaskListPlace) place, clientFactory);
} else {
return new WelcomeActivity(new WelcomePlace(), clientFactory);
}
}
}
124
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 9 : Création de la classe AppPlaceHistoryMapper.java
Dans le package client.mvp ajouter la classe suivante :
@WithTokenizers({ WelcomePlace.Tokenizer.class, TaskConsultPlace.Tokenizer.class, TaskListPlace.Tokenizer.class })
public interface AppPlaceHistoryMapper extends PlaceHistoryMapper {
}
125
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 10 : Création de la classe WelcomeActivity.java
Dans le package client.activity ajouter la classe suivante :
public class WelcomeActivity extends AbstractActivity implements Presenter {
private ClientFactory clientFactory;
private WelcomeView welcomeView;
public WelcomeActivity(WelcomePlace place, ClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
@Override
public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) {
welcomeView = clientFactory.getWelcomeView();
welcomeView.setPresenter(this);
welcomeView.reset();
containerWidget.setWidget(welcomeView.asWidget());
}
@Override
public void addTask(Task task) {
Window.alert("A coder dans le prochain exercice");
}
@Override
public void showList() {
clientFactory.getPlaceController().goTo(new TaskListPlace());
}
}
126
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 11 : Création de la classe TaskListActivity.java
Dans le package client.activity ajouter la classe suivante :
public class TaskListActivity extends AbstractActivity implements Presenter {
private ClientFactory clientFactory;
private TaskListView taskListView;
public TaskListActivity(TaskListPlace place, ClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
@Override
public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) {
taskListView = clientFactory.getTaskListView();
taskListView.reset();
containerWidget.setWidget(taskListView.asWidget());
}
@Override
public void display(String taskUuid) {
TaskConsultPlace taskConsultPlace = new TaskConsultPlace();
taskConsultPlace.setTaskUuid(taskUuid);
clientFactory.getPlaceController().goTo(taskConsultPlace);
}
}
127
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 12 : Création de la classe TaskConsultActivity.java
Dans le package client.activity ajouter la classe suivante :
public class TaskConsultActivity extends AbstractActivity {
private ClientFactory clientFactory;
private TaskConsultView taskConsultView;
private String taskUuid;
public TaskConsultActivity(TaskConsultPlace place, ClientFactory clientFactory) {
this.clientFactory = clientFactory;
taskUuid = place.getTaskUuid();
}
@Override
public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) {
taskConsultView = clientFactory.getTaskConsultView();
taskConsultView.reset();
containerWidget.setWidget(taskConsultView.asWidget());
}
}
128
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 13 : Création de la classe WelcomeView.java
Dans le package client.view ajouter la classe suivante :
public interface WelcomeView extends IsWidget {
void reset();
void setRecentTask(ArrayList<Task> tasks);
void setPresenter(Presenter presenter);
public interface Presenter {
void addTask(Task task);
void showList();
}
}
129
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 14 : Création de la classe TaskListView.java
Dans le package client.view ajouter la classe suivante :
public interface TaskListView extends IsWidget {
void reset();
void displayTasks(ArrayList<Task> tasks);
void setPresenter(Presenter presenter);
public interface Presenter {
void display(String taskUuid);
}
}
130
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 15 : Création de la classe TaskConsultView.java
Dans le package client.view ajouter la classe suivante :
public interface TaskConsultView extends IsWidget {
void reset();
void display(Task task);
}
131
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 16 : Création de la classe WelcomeViewImpl.java
Dans le package client.view ajouter la classe suivante :
public class WelcomeViewImpl extends VerticalPanel implements WelcomeView {
private NewTaskCreationPanel taskCreationPanel;
private Presenter presenter;
public WelcomeViewImpl() {
super();
getElement().getStyle().setMargin(5, Unit.PX);
getElement().getStyle().setBorderColor("white");
getElement().getStyle().setBorderWidth(2, Unit.PCT);
getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
taskCreationPanel = new NewTaskCreationPanel();
add(taskCreationPanel);
Button addButton = new Button("Add");
addButton.setIcon(IconType.PLUS);
addButton.setType(ButtonType.PRIMARY);
addButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
presenter.addTask(taskCreationPanel.flush());
}
});
add(addButton);
Button taskListButton = new Button("View all");
taskListButton.getElement().getStyle().setMarginTop(5, Unit.PX);
taskListButton.setIcon(IconType.LIST);
taskListButton.setType(ButtonType.PRIMARY);
taskListButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
presenter.showList();
}
});
add(taskListButton);
setWidth("98%");
}
@Override
public void reset() {
taskCreationPanel.reset();
}
@Override
public void setRecentTask(ArrayList<Task> tasks) {
}
@Override
public void setPresenter(Presenter presenter) {
this.presenter = presenter;
}
}
132
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 17 : Création de la classe TaskListViewImpl.java
Dans le package client.view ajouter la classe suivante :
public class TaskListViewImpl extends VerticalPanel implements TaskListView {
private Presenter presenter;
public TaskListViewImpl() {
super();
getElement().getStyle().setMargin(5, Unit.PX);
getElement().getStyle().setBorderColor("white");
getElement().getStyle().setBorderWidth(2, Unit.PCT);
getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
Heading title = new Heading(HeadingSize.H2);
title.setText("Task List");
add(title);
}
@Override
public void reset() {
}
@Override
public void setPresenter(Presenter presenter) {
this.presenter = presenter;
}
@Override
public void displayTasks(ArrayList<Task> tasks) {
}
}
133
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE MVP
Etape 18 : Modification de la classe MonApplication.java
Modifier la classe MonApplication.java de la manière suivante :
public class MonApplication implements EntryPoint {
private static ClientFactory clientFactory;
private ContentPanel dynamicPanel = new ContentPanel();
private Div staticContentPanel;
public static ClientFactory getClientFactory() {
if (clientFactory == null) {
clientFactory = GWT.create(ClientFactory.class);
}
return clientFactory;
}
public void onModuleLoad() {
clientFactory = getClientFactory();
initGui();
PlaceController placeController = getClientFactory().getPlaceController();
// Start ActivityManager for the main widget with our ActivityMapper
ActivityMapper activityMapper = new AppActivityMapper(getClientFactory());
ActivityManager activityManager = new ActivityManager(activityMapper, getClientFactory().getEventBus());
activityManager.setDisplay(dynamicPanel);
// Start PlaceHistoryHandler with our PlaceHistoryMapper
AppPlaceHistoryMapper historyMapper = GWT.create(AppPlaceHistoryMapper.class);
PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper);
historyHandler.register(placeController, getClientFactory().getEventBus(), new WelcomePlace());
historyHandler.handleCurrentHistory();
}
private void initGui() {
staticContentPanel = new Div();
Jumbotron jumbotron = new Jumbotron();
Container container = new Container();
Heading heading = new Heading(HeadingSize.H1);
heading.setText("Ma Todo List");
container.add(heading);
jumbotron.add(container);
staticContentPanel.add(jumbotron);
staticContentPanel.add(dynamicPanel);
RootPanel.get().add(staticContentPanel);
}
private class ContentPanel extends VerticalPanel implements AcceptsOneWidget {
public ContentPanel() {
super();
setWidth("100%");
}
@Override
public void setWidget(IsWidget w) {
if (w != null) {
clear();
add(w.asWidget());
}
}
}
134
COMMUNICATION CLIENT-SERVEUR
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
GWT-RPC
GWT-RPC (Remote Procedure Call) est un mécanisme simple de
communication client/serveur.
La mise en place d’un service RPC - par exemple MonService - passe
par la création de trois classes:
Côté client
MonService : Définit l’interface du service
MonServiceAsync : Équivalent asynchrone de l’interface
MonService
Côté serveur
MonServiceImpl : Servlet implémentant le service (accès aux
DAO...)
Rappel
Les objets pouvant transiter entre le serveur et le client doivent
être situés dans le package shared
être des beans sérialisables
136
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
GWT-RPC
137
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE CÔTÉ CLIENT
Interface MonService
L’interface doit étendre
com.google.gwt.user.client.rpc.RemoteService.
L’annotation @RemoteServiceRelativePath va permettre
d’associer la partie cliente à la servlet correspondante.
138
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE CÔTÉ CLIENT
Interface MonServiceAsync
Cette classe reprend les méthodes de MonService en leur
rajoutant un aspect asynchrone (via les AsyncCallback ).
Elle peut être générée automatiquement à partir de MonService
(Eclipse propose cette possibilité via le QuickFix Create
asynchronous RemoteService ... )
Elle permet une communication asynchrone afin de ne pas
bloquer le navigateur. C’est uniquement cette classe qui sera
utilisée concrètement.
139
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
MISE EN PLACE CÔTÉ SERVEUR
Classe MonServiceImpl
Elle étend com.google.gwt.user.server.rpc.RemoteServiceServlet.
Elle implémente MonService.
Fichier web.xml
La classe MonServiceImpl est une servlet. Elle doit être
déclarée et mappée correctement dans le fichier web.xml. Ce
mapping doit correspondre à la valeur indiquée pour l’annotation
@RemoteServiceRelativePath
140
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
UTILISATION DU SERVICE
Typiquement, un service RPC doit être utilisé par le Presenter.
Instanciation
Elle utilise le mécanisme GWT.create afin de créer la classe
MonServiceAsync:
private final MonServiceAsync MON_SERVICE = GWT.create(MonService.class);
Utilisation
Les appels asynchrones nécessitent la mise en place - souvent anonyme - de classes de
CallBack qui permettent de définir les traitements à effectuer en cas de réussite ou de
succès.
141
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
ASPECT ASYNCHRONE DES ÉCHANGES
Les appels du client vers le serveur sont asynchrones. Il faut donc
bien veiller à faire en sorte que les traitements dépendants du résultat
(exemple : mise à jour de l’IHM) soient positionnés dans les fonctions
de callBack (onSuccess et onFailure) et non à la suite de l’appel.
142
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
LIMITATIONS DE GWT-RPC
RPC est un mécanisme assez simple qui contient certaines
limitations. La principale est l’utilisation d’interfaces de type List
ou Set pour les types d’échanges.
Celle-ci est totalement possible. Toutefois, lors de la compilation
en Javascript, une traduction pour chaque implémentation
concrète présente dans l’émulation du JRE (ArrayList, Vector...
)va être ajoutée, alourdissant ainsi le code généré.
Ainsi, les types concrets doivent être privilégiés à ce niveau.
Le mécanisme RequestFactory propose par rapport à RPC un
certain nombre d’améliorations permettant d’avoir des échanges
plus optimisés entre le client et le serveur.
143
EXERCICE 6 : MISE EN PLACE
GWT-RPC
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 1 : Ajout/modification de la classe TaskListPanel.java
Ajouter/Modifier la classe suivante :
public class TaskListPanel extends VerticalPanel {
private DetailPresenter presenter;
public TaskListPanel() {
super();
setWidth("100%");
}
public void reset() {
clear();
}
public void setTasks(ArrayList<Task> tasks) {
reset();
int i = 0;
Grid grid = new Grid(tasks.size(), 4);
grid.setWidth("100%");
for (Task task : tasks) {
grid.setWidget(i, 0, new Label(task.getDescription()));
grid.setWidget(i, 1, new Label(task.getResponsible()));
grid.setWidget(i, 2, new Label(task.getDeadLine().toString()));
Button detailButton = new Button("Detail");
detailButton.setType(ButtonType.PRIMARY);
detailButton.setSize(ButtonSize.SMALL);
final String uuid = task.getUuid();
detailButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
TaskConsultPlace taskConsultPlace = new TaskConsultPlace();
taskConsultPlace.setTaskUuid(uuid);
MonApplication.getClientFactory().getPlaceController().goTo(taskConsultPlace);
}
});
grid.setWidget(i, 3, detailButton);
i++;
}
add(grid);
}
public void setPresenter(DetailPresenter presenter) {
this.presenter = presenter;
}
} 145
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 2 : Ajout/modification de la classe TaskConsultActivity.java
Ajouter/Modifier la classe suivante dans le package client.activity:
public class TaskConsultActivity extends AbstractActivity {
private ClientFactory clientFactory;
private TaskConsultView taskConsultView;
private String taskUuid;
private static final TaskServiceAsync TASK_SERVICE = GWT.create(TaskService.class);
public TaskConsultActivity(TaskConsultPlace place, ClientFactory clientFactory) {
this.clientFactory = clientFactory;
taskUuid = place.getTaskUuid();
}
@Override
public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) {
taskConsultView = clientFactory.getTaskConsultView();
taskConsultView.reset();
containerWidget.setWidget(taskConsultView.asWidget());
TASK_SERVICE.findByUuid(taskUuid, new AsyncCallback<Task>() {
@Override
public void onSuccess(Task result) {
taskConsultView.display(result);
}
@Override
public void onFailure(Throwable caught) {
Window.alert("KO");
}
});
}
}
146
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 3 : Ajout/modification de la classe TaskListActivity.java
Ajouter/Modifier la classe suivante dans le package client.activity:
public class TaskListActivity extends AbstractActivity implements Presenter {
private ClientFactory clientFactory;
private TaskListView taskListView;
private static final TaskServiceAsync TASK_SERVICE = GWT.create(TaskService.class);
public TaskListActivity(TaskListPlace place, ClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
@Override
public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) {
taskListView = clientFactory.getTaskListView();
taskListView.setPresenter(this);
taskListView.reset();
containerWidget.setWidget(taskListView.asWidget());
findAll();
}
private void findAll() {
TASK_SERVICE.findAll(new AsyncCallback<ArrayList<Task>>() {
@Override
public void onSuccess(ArrayList<Task> result) {
taskListView.displayTasks(result);
}
@Override
public void onFailure(Throwable caught) {
Window.alert("KO");
}
});
}
@Override
public void display(String taskUuid) {
TaskConsultPlace taskConsultPlace = new TaskConsultPlace();
taskConsultPlace.setTaskUuid(taskUuid);
clientFactory.getPlaceController().goTo(taskConsultPlace);
}
}
147
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 4 : Ajout/modification de la classe WelcomeActivity.java
Ajouter/Modifier la classe suivante dans le package client.activity:
public class WelcomeActivity extends AbstractActivity implements Presenter {
private ClientFactory clientFactory;
private WelcomeView welcomeView;
private static final TaskServiceAsync TASK_SERVICE = GWT.create(TaskService.class);
public WelcomeActivity(WelcomePlace place, ClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
@Override
public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) {
welcomeView = clientFactory.getWelcomeView();
welcomeView.setPresenter(this);
welcomeView.reset();
containerWidget.setWidget(welcomeView.asWidget());
findLatest();
}
private void findLatest() {
TASK_SERVICE.findLatest(new AsyncCallback<ArrayList<Task>>() {
@Override
public void onSuccess(ArrayList<Task> result) {
welcomeView.setRecentTask(result);
}
@Override
public void onFailure(Throwable caught) {
Window.alert("KO");
}
});
}
@Override
public void addTask(Task task) {
TASK_SERVICE.save(task, new AsyncCallback<Task>() {
@Override
public void onSuccess(Task result) {
clientFactory.getEventBus().fireEvent(new NotificationEvent("Saved"));
findLatest();
}
@Override
public void onFailure(Throwable caught) {
Window.alert("KO");
}
});
}
@Override
public void showList() {
clientFactory.getPlaceController().goTo(new TaskListPlace());
}
@Override
public void display(String taskUuid) {
TaskConsultPlace taskConsultPlace = new TaskConsultPlace();
taskConsultPlace.setTaskUuid(taskUuid);
clientFactory.getPlaceController().goTo(taskConsultPlace);
}
}
148
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 5 : Ajout/modification de la classe TaskConsultPlace.java
Ajouter/Modifier la classe suivante dans le package client.place:
public class TaskConsultPlace extends Place {
private String taskUuid;
public TaskConsultPlace() {
}
public String getTaskUuid() {
return taskUuid;
}
public void setTaskUuid(String taskUuid) {
this.taskUuid = taskUuid;
}
public static class Tokenizer implements PlaceTokenizer<TaskConsultPlace> {
public TaskConsultPlace getPlace(String token) {
TaskConsultPlace place = new TaskConsultPlace();
place.setTaskUuid(token);
return place;
}
public String getToken(TaskConsultPlace place) {
return place.getTaskUuid();
}
}
}
149
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 6 : Ajout/modification de la classe TaskService.java
Ajouter/Modifier la classe suivante dans le package client.service:
@RemoteServiceRelativePath("tasks")
public interface TaskService extends RemoteService {
Task save(Task task);
ArrayList<Task> findLatest();
ArrayList<Task> findAll();
Task findByUuid(String uuid);
}
150
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 7 : Ajout/modification de la classe TaskServiceAsync.java
Ajouter/Modifier la classe suivante dans le package client.service:
public interface TaskServiceAsync {
void findAll(AsyncCallback<ArrayList<Task>> callback);
void findLatest(AsyncCallback<ArrayList<Task>> callback);
void save(Task task, AsyncCallback<Task> callback);
void findByUuid(String uuid, AsyncCallback<Task> callback);
}
Etape 8 : Ajout/modification de la classe DetailPresenter.java
Ajouter/Modifier la classe suivante dans le package client.view:
public interface DetailPresenter {
void display(String taskUuid);
}
151
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 9 : Ajout/modification de la classe TaskConsultViewImpl.java
Ajouter/Modifier la classe suivante dans le package client.view:
public class TaskConsultViewImpl extends VerticalPanel implements TaskConsultView {
public TaskConsultViewImpl() {
}
@Override
public void reset() {
clear();
}
@Override
public void display(Task task) {
add(new Label(task.getDescription()));
add(new Label(task.getResponsible()));
add(new Label(task.getDeadLine().toString()));
}
}
152
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 10 : Ajout/modification de la classe TaskListView.java
Ajouter/Modifier la classe suivante dans le package client.view:
public interface TaskListView extends IsWidget {
void reset();
void displayTasks(ArrayList<Task> tasks);
void setPresenter(Presenter presenter);
public interface Presenter extends DetailPresenter {
}
}
153
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 11 : Ajout/modification de la classe TaskListViewImpl.java
Ajouter/Modifier la classe suivante dans le package client.view:
public class TaskListViewImpl extends VerticalPanel implements TaskListView {
private Presenter presenter;
private TaskListPanel taskListPanel;
public TaskListViewImpl() {
super();
setWidth("100%");
getElement().getStyle().setMargin(5, Unit.PX);
getElement().getStyle().setBorderColor("white");
getElement().getStyle().setBorderWidth(2, Unit.PCT);
getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
Heading title = new Heading(HeadingSize.H2);
title.setText("Task List");
add(title);
taskListPanel = new TaskListPanel();
add(taskListPanel);
}
@Override
public void reset() {
taskListPanel.reset();
}
@Override
public void setPresenter(Presenter presenter) {
this.presenter = presenter;
taskListPanel.setPresenter(presenter);
}
@Override
public void displayTasks(ArrayList<Task> tasks) {
taskListPanel.reset();
taskListPanel.setTasks(tasks);
}
}
154
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 12 : Ajout/modification de la classe WelcomeView.java
Ajouter/Modifier la classe suivante dans le package client.view:
public interface WelcomeView extends IsWidget {
void reset();
void setRecentTask(ArrayList<Task> tasks);
void setPresenter(Presenter presenter);
public interface Presenter extends DetailPresenter {
void addTask(Task task);
void showList();
}
}
155
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 13 : Ajout/modification de la classe WelcomeViewImpl.java
Ajouter/Modifier la classe suivante dans le package client.view:
public class WelcomeViewImpl extends VerticalPanel implements WelcomeView {
private NewTaskCreationPanel taskCreationPanel;
private TaskListPanel taskListPanel;
private Presenter presenter;
public WelcomeViewImpl() {
super();
getElement().getStyle().setMargin(5, Unit.PX);
getElement().getStyle().setBorderColor("white");
getElement().getStyle().setBorderWidth(2, Unit.PCT);
getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
taskCreationPanel = new NewTaskCreationPanel();
add(taskCreationPanel);
Button addButton = new Button("Add");
addButton.setIcon(IconType.PLUS);
addButton.setType(ButtonType.PRIMARY);
addButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
presenter.addTask(taskCreationPanel.flush());
}
});
add(addButton);
add(new Heading(HeadingSize.H2, "Latest"));
taskListPanel = new TaskListPanel();
add(taskListPanel);
Button taskListButton = new Button("View all");
taskListButton.getElement().getStyle().setMarginTop(5, Unit.PX);
taskListButton.setIcon(IconType.LIST);
taskListButton.setType(ButtonType.PRIMARY);
taskListButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
presenter.showList();
}
});
add(taskListButton);
setWidth("98%");
}
@Override
public void reset() {
taskCreationPanel.reset();
taskListPanel.reset();
}
@Override
public void setRecentTask(ArrayList<Task> tasks) {
taskListPanel.setTasks(tasks);
}
@Override
public void setPresenter(Presenter presenter) {
this.presenter = presenter;
taskListPanel.setPresenter(presenter);
}
}
156
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 14 : Ajout/modification de la classe TaskServiceImpl.java
Ajouter/Modifier la classe suivante dans le package server.service:
public class TaskServiceImpl extends RemoteServiceServlet implements TaskService {
ArrayList<Task> tasks = new ArrayList<>();
public TaskServiceImpl() {
fakeInit();
}
private void fakeInit() {
for (int i = 0; i < 10; i++) {
save(createTask(i));
}
}
@Override
public Task save(Task task) {
task.setUuid(UUID.randomUUID().toString());
tasks.add(task);
return task;
}
@Override
public ArrayList<Task> findLatest() {
int maxElementCount = 5;
int taskCount = tasks.size();
if (taskCount < maxElementCount) {
maxElementCount = taskCount;
}
ArrayList<Task> aux = new ArrayList<Task>(tasks.subList(taskCount - maxElementCount, taskCount));
Collections.reverse(aux);
return aux;
}
@Override
public ArrayList<Task> findAll() {
ArrayList<Task> aux = new ArrayList<Task>(tasks);
Collections.reverse(aux);
return aux;
}
public Task createTask(int count) {
Task result = new Task();
result.setResponsible("Resp. " + count);
result.setDescription("Description. " + count);
result.setDeadLine(new Date());
return result;
}
@Override
public Task findByUuid(String uuid) {
for (Task task : tasks) {
if (task.getUuid().compareTo(uuid) == 0) {
return task;
}
}
return null;
}
}
157
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
EXERCICE 6 : MISE EN PLACE GWT-RPC
Etape 15 : Modification du fichier web.xml
Modifier le fichier web.xml de la manière suivante:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee">
<!-- Servlets -->
<servlet>
<servlet-name>taskServlet</servlet-name>
<servlet-class>fr.jdev.atelier.server.service.TaskServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>taskServlet</servlet-name>
<url-pattern>/monapplication/tasks</url-pattern>
</servlet-mapping>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>MonApplication.html</welcome-file>
</welcome-file-list>
</web-app>
158
CONCLUSION
Introduction Architecture Premi`ere application
Cr´eation de l’interface
graphique Bus d’´ev`enements
Cin´ematique de l’appli-
cation
Communication
client-serveur
Conclusion
CONCLUSION
Le framework GWT est extrêmement riche, d’autres
fonctionnalités restent à aborder :
Mise en place du multilinguisme (I18n)
Optimisation des ressources Image et Style
Optimisation des échanges Client/Serveur (RequestFactory)
Inversion de contrôle côté client (GIN)
Chargement du code client par tranche (Code spliting)
Data Binding (Framework Editor)
...
De plus la mise en œuvre d’un projet GWT peut également
nécessiter la connaissance de technologies complémentaires :
Architecture REST (SOAP)
Responsive Design
Git & Gitflow
...
160

Weitere ähnliche Inhalte

Was ist angesagt?

Sybase Connect Atelier Power Builderv2
Sybase Connect Atelier Power Builderv2Sybase Connect Atelier Power Builderv2
Sybase Connect Atelier Power Builderv2
apratt72
 

Was ist angesagt? (20)

Java Fx
Java FxJava Fx
Java Fx
 
Java Fx Rapport
Java Fx RapportJava Fx Rapport
Java Fx Rapport
 
10 tips pour améliorer les performances de vos applications Windows 8
10 tips pour améliorer les performances de vos applications Windows 810 tips pour améliorer les performances de vos applications Windows 8
10 tips pour améliorer les performances de vos applications Windows 8
 
Rich Ajax Platform
Rich Ajax PlatformRich Ajax Platform
Rich Ajax Platform
 
Support cours angular
Support cours angularSupport cours angular
Support cours angular
 
Outillage pour Windows 8 XAML
Outillage pour Windows 8 XAMLOutillage pour Windows 8 XAML
Outillage pour Windows 8 XAML
 
Application de gestion des projets en J2EE (Spring-Hibernate) avec architectu...
Application de gestion des projets en J2EE (Spring-Hibernate) avec architectu...Application de gestion des projets en J2EE (Spring-Hibernate) avec architectu...
Application de gestion des projets en J2EE (Spring-Hibernate) avec architectu...
 
Quoi de neuf dans ASP.NET 4.5
Quoi de neuf dans ASP.NET 4.5Quoi de neuf dans ASP.NET 4.5
Quoi de neuf dans ASP.NET 4.5
 
Asp.net Présentation de L'application "Organizer"
Asp.net Présentation de L'application "Organizer"Asp.net Présentation de L'application "Organizer"
Asp.net Présentation de L'application "Organizer"
 
Booster votre application Windows Phone 8
Booster votre application Windows Phone 8Booster votre application Windows Phone 8
Booster votre application Windows Phone 8
 
Application Spring MVC/IOC & Hibernate
Application Spring MVC/IOC & HibernateApplication Spring MVC/IOC & Hibernate
Application Spring MVC/IOC & Hibernate
 
GWT Principes & Techniques
GWT Principes & TechniquesGWT Principes & Techniques
GWT Principes & Techniques
 
Sybase Connect Atelier Power Builderv2
Sybase Connect Atelier Power Builderv2Sybase Connect Atelier Power Builderv2
Sybase Connect Atelier Power Builderv2
 
Les nouveautés du Framework .NET 4.5
Les nouveautés du Framework .NET 4.5Les nouveautés du Framework .NET 4.5
Les nouveautés du Framework .NET 4.5
 
Introduction a Android
Introduction a AndroidIntroduction a Android
Introduction a Android
 
CV REBAI Hamida
CV REBAI HamidaCV REBAI Hamida
CV REBAI Hamida
 
Silverlight 3.MSDays EPITA 11/06/2009
Silverlight 3.MSDays EPITA 11/06/2009Silverlight 3.MSDays EPITA 11/06/2009
Silverlight 3.MSDays EPITA 11/06/2009
 
20091020 - Normandy Jug - Builders Battle
20091020 - Normandy Jug - Builders Battle20091020 - Normandy Jug - Builders Battle
20091020 - Normandy Jug - Builders Battle
 
JavaFX et le JDK9
JavaFX et le JDK9JavaFX et le JDK9
JavaFX et le JDK9
 
Cv ines ouaz
Cv ines ouazCv ines ouaz
Cv ines ouaz
 

Andere mochten auch (7)

Panorama citation des donnees
Panorama citation des donneesPanorama citation des donnees
Panorama citation des donnees
 
Recommandations rda sur la citation des données
Recommandations rda sur la citation des donnéesRecommandations rda sur la citation des données
Recommandations rda sur la citation des données
 
Présentation normes OGC
Présentation normes OGCPrésentation normes OGC
Présentation normes OGC
 
Cas d'utilisation de la citation de données
Cas d'utilisation de la citation de donnéesCas d'utilisation de la citation de données
Cas d'utilisation de la citation de données
 
Paul valery et les Web components
Paul valery et les Web componentsPaul valery et les Web components
Paul valery et les Web components
 
Service WEB de type REST avec Java
Service WEB de type REST avec JavaService WEB de type REST avec Java
Service WEB de type REST avec Java
 
Tutoriel GIT
Tutoriel GITTutoriel GIT
Tutoriel GIT
 

Ähnlich wie TP GWT JDEV 2015

Gtug2 Mobile app with web technlogy
Gtug2 Mobile app with web technlogyGtug2 Mobile app with web technlogy
Gtug2 Mobile app with web technlogy
Sacha Leprêtre
 
Techdays 2012 : Mise en place d'une démarche ALM avec Visual Studio pour Wind...
Techdays 2012 : Mise en place d'une démarche ALM avec Visual Studio pour Wind...Techdays 2012 : Mise en place d'une démarche ALM avec Visual Studio pour Wind...
Techdays 2012 : Mise en place d'une démarche ALM avec Visual Studio pour Wind...
vlabatut
 
Bureau Metier - Version 20061010
Bureau Metier - Version 20061010Bureau Metier - Version 20061010
Bureau Metier - Version 20061010
Didier Girard
 

Ähnlich wie TP GWT JDEV 2015 (20)

Liste des stages 07 02 2017
Liste des stages 07 02 2017Liste des stages 07 02 2017
Liste des stages 07 02 2017
 
developpement web framework cms developpement brute
developpement web framework cms developpement brutedeveloppement web framework cms developpement brute
developpement web framework cms developpement brute
 
CV_Bilel CHAOUADI
CV_Bilel CHAOUADICV_Bilel CHAOUADI
CV_Bilel CHAOUADI
 
Architecturez vos applications mobiles avec Azure et Xamarin
Architecturez vos applications mobiles avec Azure et XamarinArchitecturez vos applications mobiles avec Azure et Xamarin
Architecturez vos applications mobiles avec Azure et Xamarin
 
Visual studio 2017 Launch keynote - Afterworks@Noumea
Visual studio 2017 Launch keynote - Afterworks@NoumeaVisual studio 2017 Launch keynote - Afterworks@Noumea
Visual studio 2017 Launch keynote - Afterworks@Noumea
 
Gdd07 Gwt Dig
Gdd07 Gwt DigGdd07 Gwt Dig
Gdd07 Gwt Dig
 
Introduction à web assembly
Introduction à web assemblyIntroduction à web assembly
Introduction à web assembly
 
De A à Z : Choisir une architecture pour sa solution applicative
De A à Z : Choisir une architecture pour sa solution applicativeDe A à Z : Choisir une architecture pour sa solution applicative
De A à Z : Choisir une architecture pour sa solution applicative
 
Gtug2 Mobile app with web technlogy
Gtug2 Mobile app with web technlogyGtug2 Mobile app with web technlogy
Gtug2 Mobile app with web technlogy
 
Techdays 2012 : Mise en place d'une démarche ALM avec Visual Studio pour Wind...
Techdays 2012 : Mise en place d'une démarche ALM avec Visual Studio pour Wind...Techdays 2012 : Mise en place d'une démarche ALM avec Visual Studio pour Wind...
Techdays 2012 : Mise en place d'une démarche ALM avec Visual Studio pour Wind...
 
02 - [ASP.NET Core] ASP.NET Core MVC
02 - [ASP.NET Core] ASP.NET Core MVC 02 - [ASP.NET Core] ASP.NET Core MVC
02 - [ASP.NET Core] ASP.NET Core MVC
 
Concept de l’Intégration Continue
Concept de l’Intégration ContinueConcept de l’Intégration Continue
Concept de l’Intégration Continue
 
Support JEE Spring Inversion de Controle IOC et Spring MVC
Support JEE Spring Inversion de Controle IOC et Spring MVCSupport JEE Spring Inversion de Controle IOC et Spring MVC
Support JEE Spring Inversion de Controle IOC et Spring MVC
 
Ma présentation PFE : Application Android & Site Web
Ma présentation PFE : Application Android & Site WebMa présentation PFE : Application Android & Site Web
Ma présentation PFE : Application Android & Site Web
 
Bureau Metier - Version 20061010
Bureau Metier - Version 20061010Bureau Metier - Version 20061010
Bureau Metier - Version 20061010
 
Google Web Toolkit 1.5 Presentation Web Creative Common
Google Web Toolkit 1.5 Presentation Web Creative CommonGoogle Web Toolkit 1.5 Presentation Web Creative Common
Google Web Toolkit 1.5 Presentation Web Creative Common
 
Silverlight
SilverlightSilverlight
Silverlight
 
Framework .net overview
Framework .net overviewFramework .net overview
Framework .net overview
 
Nouveautés de App-V 5.0 et intégration avec System Center 2012
Nouveautés de App-V 5.0 et intégration avec System Center 2012Nouveautés de App-V 5.0 et intégration avec System Center 2012
Nouveautés de App-V 5.0 et intégration avec System Center 2012
 
Ingénieur en développement logiciel
Ingénieur en développement logicielIngénieur en développement logiciel
Ingénieur en développement logiciel
 

TP GWT JDEV 2015

  • 1. T7.A02 JDEV 2015 François ANDRE Guillaume BRISSEBRAT Alexandre JOURNAUX OMP, INRA
  • 2. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion LICENCE Le contenu de cette présentation est publié sous la licence : Creative Commons Attribution 4.0 International License La copie de cette présentation est autorisée sous réserve du respect des conditions de la licence (creativecommons.org/licenses/by/4.0/). 2
  • 3. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CODE SOURCE Le code source du TP est disponible à l’adresse suivante: https://github.com/francoisandre/gwtjdev2015 Afin de pouvoir repartir sur une situation propre sur un exercice plusieurs branches correspondant à chaque fin d’exercice sont mise à disposition. Elles sont signalées en fin chaque branche correspond à la fin d’un exercice. Cela permet de pouvoir passer à un nouvel exercice. Les branches sont signalées de la manière suivante: NomDeLaBranche 3
  • 4. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MACHINE VIRTUELLE Une machine virtuelle de type VirtualBox comportant les outils nécessaires et le code source du TP est disponible à l’adresse suivante: http://jdev2015.sedoo.fr/Stagiaire%20GWT-c.ova Afin de récuperer le code du TP effectuez la procédure suivante : Ouvrir Eclipse Sélectionner File > Import... Dans la liste des types de projets, séléctionner Git > Projects from Git et appuyer sur Next Séléctionner Existing local repository et appuyer sur Next Dans la liste des dépots Git, séléctionner git /home/user/git/.git et appuyer sur Next Dans l’étape relative au Wizard appuyer directement sur Next Appuyer sur Finish 4
  • 5. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion SOMMAIRE 1. Introduction 2. Architecture 3. Premi`ere application 4. Cr´eation de l’interface graphique 5. Bus d’´ev`enements 6. Cin´ematique de l’application 7. Communication client-serveur 8. Conclusion 5
  • 7. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion QUELQUES QUESTIONS... Comment faire une Single Page Application ? Où doit se situer un traitement ? Android ou iOS ? Des gens utilisent-ils encore IE6 ? Comment économiser les ressources ? Comment faire une boucle en Javascript ? Comment déboguer ou lister les appels d’une fonction en Javascript ? Pourquoi ne puis-je pas faire du Swing ? Le client-serveur, ça avait son charme, non ? Pourquoi mon application n’est-elle toujours pas finie ? C’est pas plus rapide en PHP ? Google n’a-t-il pas arrêté GWT ? 7
  • 8. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion FIABLILITÉ DE LA CIBLE CSS+HTML5+JAVASCRIPT 8
  • 9. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE RÉPONSE POSSIBLE GWT 9
  • 10. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE IDÉE SIMPLE Coder la partie cliente en Java La compiler en JavaScript 10
  • 11. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion AVANTAGES PRINCIPAUX Intégré dans l’écosystème JEE Relié à l’écosystème HTML/Javascript 11
  • 12. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion REPÈRE HISTORIQUES Chronologie succincte : 2006 v1.0 ... 2009 v2.0 ... Janvier 2014 v2.6.0 Novembre 2014 v2.7.0 Futur Évolutions WEB : HTML5, W3C Web Components ... Évolutions Java : Support Java 8 ... Évolutions GWT : Integration Javascript ... 12
  • 13. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion PLUS D'INFORMATIONS Site officiel : http://www.gwtproject.org/ Démonstration officielle : http://samples.gwtproject.org/samples/Showcase/Showcase.html Communauté https://groups.google.com/forum/#!forum/google-web-toolkit https://plus.google.com/communities/116543000751323604177 Conférences en ligne : GWT Create (http://gwtcreate.com/) Google I/O (chaîne Youtube) Blogs : Gwt Daily (http://www.gwtdaily.com/) Sami Jabber (http://www.samijaber.com/) Tutoriels : http://courses.coreservlets.com/Course-Materials/gwt.html 13
  • 15. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion ELÉMENTS MIS EN ŒUVRE 15
  • 17. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion TWITTER BOOTSTRAP Description : Collection d’outils HTML/CSS/Javascript Objectif : Compenser l’aspect brut des composants GWT Rendu moderne Site web adaptatif (RWD) Grande Popularité 17
  • 19. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion SPRING FRAMEWORK Description : Framework Java permettant la mise en place d’un conteneur léger Objectif : Simplification de l’architecture et fiabilisation du code Inversion de contrôle (IoC) Bibliothèques complémentaires (accès aux données, ...) 19
  • 20. JPA : JAVA PERSISTENCE API
  • 21. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion JPA : JAVA PERSISTENCE API Description : API officielle de Mapping Objet-SGBD Objectif : Simplifier la mise en œuvre de la persistance Définition du mapping via annotation Interrogation via JPQL 21
  • 22. MAVEN
  • 23. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MAVEN Description : Moteur de production Objectif : Fiabilise les étapes clés du développement (compilation, test, génération, livraison,...) Le fichier pom.xml : configuration globale du projet Arborescence /src Sources du projet /src/main Partie principale /src/main/java Code source /src/main/resources Fichier de ressources (images, config, ...) /src/main/webapp Webapp du projet /src/test Partie test /src/test/java Code source des tests /src/test/resources Fichiers de ressources des tests /target Fichiers produits (classes, .war, .jar) Compatibilité avec les outils d’intégration continue (Jenkins...) 23
  • 25. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion ECLIPSE Description : Environnement de développement intégré (EDI) Objectif : Édition des sources, lien avec le SCM, débogage GWT ne nécessite pas d’EDI particulier. D’autres EDI (IntelliJ, Netbeans, vi) peuvent être utilisés. L’équipe Google fournit un module (plugin) pour Eclipse proposant certaines fonctionnalités utiles : Génération Validation ... Remarque: Distribution privilégiée : Eclipse IDE for Java EE Developers 25
  • 26. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion PLUGIN GWT (NAVIGATEUR) Classical dev mode Jusqu’à la version 2.6.0, le développement GWT - Dev Mode - repose sur un module installé sur le navigateur (Chrome, Firefox, IE, Safari). Ce mode est contraignant pour les développeur de GWT pour les raisons suivantes : Le nombre de navigateurs Les API propriétaires sous jacentes De plus, lorsque la taille de l’application augmente le temps de rafraichissement devient bloquant. Super dev mode Depuis la version 2.4.0 il est progressivement remplacé par le Super Dev Mode qui permet de débugger dans les navigateurs supportant le standard SourceMaps (Chrome, Firefox). Le plugin SDBG permet de conserver un débuggage dans Eclipse. 26
  • 28. EXERCICE 1 : GÉNÉRATION D'UN SQUELETTE APPLICATIF
  • 29. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion PRÉREQUIS LOGICIEL Prérequis: JVM (1.7 conseillée) Maven / Ant Eclipse avec les plugins Egit M2E Plugin GWT (via Eclipse Market Place) SDBG (update site: http://sdbg.github.io/p2) StartExplorer (via Eclipse Market Place) SDK GWT (2.7.0) Chrome (avec SourceMap enabled) 29
  • 30. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion GÉNÉRATION D'UN SQUELETTE APPLICATIF Utilisation de webAppCreator (utilitaire fourni dans le SDK) Etape 1 : Génération squelette /home/user/Développement/gwt-2.7.0/webAppCreator -noant -maven -XnoEclipse fr.jdev.atelier.MonApplication Etape 2 : Import dans Eclipse Import... > Maven > Existing Maven Projects Etape 3 : Modification fichier pom.xml Ajouter la version <version>$gwtVersion</version> dans les dépendances <groupId>com.google.gwt</groupId> <dependency> : ... <dependency> <groupId>com.google.gwt</groupId> <artifactId>gwt-servlet</artifactId> <version>$gwtVersion</version> <scope>runtime</scope> </dependency> ... 30
  • 31. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion GÉNÉRATION D'UN SQUELETTE APPLICATIF Etape 4 : Modifications des propriétés du projet Google > Web toolkit : cocher Use Google Web Toolkit Google > Web application : Cocher This project has a WAR directory Dans la zone de saisie WAR directory indiquer src/main/webapp Décocher Launch and deploy... si nécessaire FinExercice1 31
  • 33. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXPLORATION DU SQUELETTE Architecture Maven classique /src/main/java /src/main/resources /src/main/webapp ... Architecture GWT classique Package client Classes de la partie cliente (⇒ Javascript) Package shared Classes communes client & serveur (⇒ Javascript & Java) Package server Classes de la partie serveur (⇒ Application JEE standard) 33
  • 34. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CONTRAINTES PACKAGE CLIENT & SHARED Les classes doivent utiliser/étendre le JDK émulé par GWT (http://www.gwtproject.org/doc/latest/RefJreEmulation.html) Exemples : Autorisé: Object, HashMap, ArrayList, com.google.common.base.Strings (Guava)... Interdit : File, StringUtils (commons-lang), ... Les classes transitant entre client et serveur doivent être sérialisables: • implémenter java.io.Serializable • implémenter com.google.gwt.user.client.rpc.IsSerializable des beans: • Constructeur vide • Getters et Setters 34
  • 35. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion DESCRIPTEUR DU MODULE: MONAPPLICATION.GWT.XML Rôle Pilotage de l’application Position au dessus du package client Contenu Nom du module <module> Point d’entrée <entry-point class=’fr.jdev.atelier.client.MonApplication’ /> Autres modules à importer : <inherits> Répertoires : <source> Paramètres divers: langues... Remplacement dynamique des classes <replace-with class="fr.sedoo.sssdata.client.ClientFactoryImpl"> <when-type-is class="fr.sedoo.sssdata.client.ClientFactory"/> </replace-with> 35
  • 36. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CONTENEUR HTML MONAPPLICATION.HTML Rôle Chargement de l’application Position Dans le répertoire webapp Contenu Page HTML classique (js, css, balises HTML...) Chargement du module <script type="text/javascript" language="javascript" src="monapplication/monapplication.nocache.js"></script> Remarque: le script nocache.js charge la compilation adéquate du module : La plus récente Correspondant au navigateur du client et à sa langue 36
  • 37. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion COMPILATION ET PERMUTATIONS Lors de la compilation Javascript, GWT génère une tradution pour chaque couple moteur de navigateur supporté (6) langue indiquée dans le descripteur de module Les permutations sont une des nombreuses optimisations fournies par GWT. 37
  • 38. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion ENTRY POINT Rôle Équivalent de main dans les application Java Position Dans le package client Conformément au fichier gwt.xml Contenu Implémente com.google.gwt.core.client.EntryPoint → public void onModuleLoad(); • Construit les éléments de l’interface utilisateur • Optionnellement, supprime certains éléments du conteneur HTML Exemple : suppression du contenu de l’élément d’identifiant loadingMessage RootPanel loadingMessage = RootPanel.get("loadingMessage"); DOM.setInnerHTML(loadingMessage.getElement(), ""); • Ajoute l’interface utilisateur dans le conteneur HTML Exemple : En vidant completement le conteneur HTML Label myLabel = new Label("Hello JDEV"); RootPanel.get().clear(); RootPanel.get().add(myLabel); 38
  • 39. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion AUTRES FICHIERS REMARQUABLES Configuration Maven /pom.xml Configuration application web /src/main/webapp/WEB-INF/web.xml 39
  • 40. EXERCICE 2 : EXÉCUTION ET DÉBOGAGE
  • 41. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion LANCEMENT DE L'APPLICATION Le lancement de l’application se fait classiquement via les menus Debug As ou Run As Le moteur de lancement à utiliser est Web Application ou Web Application (GWT Super Dev Mode) 41
  • 42. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion LANCEMENT DE L'APPLICATION Lors du lancement, deux applications sont exécutées dans l’ordre suivant : Le serveur de complitation Java →Javascript ... The code server is ready at http://127.0.0.1:9876 ... L’application proprement dite. Celle-ci est utilisable lors que son URL s’affiche dans l’onglet Development 42
  • 43. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion TEST DE L'APPLICATION Le lancement de l’URL déclenche la compilation Java →Javascript. Une fois compilée l’application apparait normalement 43
  • 44. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion TEST DE L'APPLICATION Remarques La première compilation suivant un démarrage de l’application est longue Les autres compilations sont plus rapides car incrémentales (ne portent que sur les fichiers modifiés entre temps) Le code java peut être vu via Chrome (via la technologie SourceMaps) 44
  • 45. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion DEBOGAGE AVEC LE PLUGIN ECLIPSE SDBG SDBG permet d’intercepter de piloter le débogage SourceMaps dans Eclipse Etape 1 : Création d'un lanceur chrome Ouvrir la fenêtres des lanceurs de débogage (Debug configurations...) Sélectionner Launch Chrome Cliquer sur le bouton droit et sélectionner New Dans la fenêtre qui s’ouvre indiquer les valeurs suivantes : Name : Mon Application SDBG URL : http://127.0.0.1:8888/MonApplication.html Project : sélectionner le projet MonApplication Remarque : Dans l’onglet Common on peut cocher l’option Debug du bloc Display in favorites menu Cliquer sur Apply puis sur Debug L’application doit être lancée auparavant 45
  • 46. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion DEBOGAGE AVEC LE PLUGIN ECLIPSE SDBG Etape 2 : Mise en place d'un point d'arrêt Dans la classe FieldVerifier positionner un point d’arrêt en début de la méthode isValidName Dans l’application cliquer sur Send Le point d’arrêt va se déclencher deux fois Côté client : suite à l’appel de sendNameToServer Côté serveur : suite à l’appel de greetServer Remarques : le plugin SDBG est en amélioration permanente • Pour la gestion du rechargement à chaud • Pour l’affichage des contenus des variables le plugin SDBG est désactivé lorsque l’inspecteur Chrome est activé. 46
  • 49. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion COMPOSANTS DE BASE GWT propose un certain nombre de composants de base pour construire les interfaces: Widgets élémentaires: boutons, zones de texte, cases à cocher... Panneaux de positionnement (similaires à Swing): panneaux horizontaux, verticaux, à onglets... Comme en Swing, ces éléments sont des classes Java et se combinent afin de créer l’interface souhaitée. 49
  • 50. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion WIDGETS ÉLÉMENTAIRES Étendent com.google.gwt.user.client.ui.Widget Exemples : TextBox TextArea Button RadioButton CheckBox DatePicker, CellList... 50
  • 51. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion PANNEAUX DE POSITIONNEMENT Panneaux classiques (étendent com.google.gwt.user.client.ui.Panel) Exemples : HorizontalPanel VerticalPanel FlowPanel HTMLPanel Permet de mixer des balises HTML et des com- posants GWT Remarque: les panneaux héritent aussi de Widget 51
  • 52. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion PANNEAUX DE POSITIONNEMENT Panneaux dynamiques (implémentent com.google.gwt.user.client.ui.ProvidesResize et com.google.gwt.user.client.ui.RequiresResize ) Exemples : DockLayoutPanel SplitLayoutPanel TabLayoutPanel 52
  • 53. EXERCICE 3 : YET ANOTHER TODO LIST - UNE PREMIERE IHM
  • 54. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE PREMIÈRE IHM Etape 1 : Suppression du contenu du contenur HTML Dans le fichier MonApplication.html vider le contenu de la balise <body> à l’exception de la balise <noscript> (et de son cotenu). Etape 2 : Modification de la fonction onModuleLoad Modifier le fichier suivant MonApplication.java de la manière suivante: public class MonApplication implements EntryPoint { public void onModuleLoad() { DockLayoutPanel mainContent = new DockLayoutPanel(Unit.PX); mainContent.getElement().getStyle().setMargin(5, Unit.PX); mainContent.addNorth(new Label("Ma Todo List"), 25); VerticalPanel taskForm = new VerticalPanel(); taskForm.setSpacing(5); taskForm.add(new Label("Ma tâche")); TextBox description = new TextBox(); description.setTitle("Description"); TextBox responsible = new TextBox(); responsible.setTitle("Responsible"); DateBox deadLine = new DateBox(); taskForm.add(description); taskForm.add(responsible); taskForm.add(deadLine); mainContent.add(taskForm); RootLayoutPanel.get().add(mainContent); } } 54
  • 55. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE PREMIÈRE IHM FinExercice3a 55
  • 57. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion LIBRAIRIES COMPLÉMENTAIRES Solutions spécifiques en GWT : Sencha GXT (http://www.sencha.com/products/gxt/) Vaadin (https://vaadin.com/home) Sencha GXT 57
  • 58. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion LIBRAIRIES COMPLÉMENTAIRES Portage de libraries Javascript : GWTBootstrap3 (https://github.com/gwtbootstrap3) Gwt-Openlayers (http://www.gwt-openlayers.org/) Exemple GWTBootstrap3 : Alert loginFirst = new Alert("You must connect to access to this page"); Remarque: un portage Javascript (Wrapping) peut occasionner un débogage plus difficile. 58
  • 59. EXERCICE 3 : YET ANOTHER TODO LIST - UNE IHM BOOTSTRAP
  • 60. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE IHM BOOTSTRAP Etape 1 : Ajout dépendance Maven Dans le fichier pom.xml ajouter les dépendances suivantes ... <dependency> <artifactId>gwtbootstrap3</artifactId> <groupId>org.gwtbootstrap3</groupId> <version>0.9</version> </dependency> <dependency> <groupId>org.gwtbootstrap3</groupId> <artifactId>gwtbootstrap3-extras</artifactId> <version>0.9</version> </dependency> ... Etape 2 : Modification du fichier MonApplication.gwt.xml Modifier le fichier suivant MonApplication.gwt.xml ajouter la ligne suivantes <inherits name="org.gwtbootstrap3.GwtBootstrap3"/> Etape 3 : Redémarrage de l'application Une fois les modifications faites, redémarrer l’application. 60
  • 61. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE IHM BOOTSTRAP Etape 4 : Modification de la fonction onModuleLoad Modifier le fichier suivant MonApplication.java de la manière suivante: package fr.jdev.atelier.client; import org.gwtbootstrap3.client.ui.Container; import org.gwtbootstrap3.client.ui.Heading; import org.gwtbootstrap3.client.ui.Jumbotron; import org.gwtbootstrap3.client.ui.TextBox; import org.gwtbootstrap3.client.ui.constants.HeadingSize; ... public class MonApplication implements EntryPoint { public void onModuleLoad() { Jumbotron jumbotron = new Jumbotron(); Container container = new Container(); Heading heading = new Heading(HeadingSize.H1); heading.setText("Ma Todo List"); container.add(heading); jumbotron.add(container); VerticalPanel mainContent = new VerticalPanel(); mainContent.setWidth("100%"); VerticalPanel taskForm = new VerticalPanel(); taskForm.setSpacing(5); taskForm.add(new Label("Ma tâche")); TextBox description = new TextBox(); description.setPlaceholder("Description"); TextBox responsible = new TextBox(); responsible.setPlaceholder("Responsible"); DateBox deadLine = new DateBox(); taskForm.add(description); taskForm.add(responsible); taskForm.add(deadLine); mainContent.add(jumbotron); mainContent.add(taskForm); RootPanel.get().add(mainContent); } } 61
  • 62. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE IHM BOOTSTRAP FinExercice3b 62
  • 63. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CRÉATION DE COMPOSANTS Par héritage d’un Widget : Exemple: création d’une infobulle d’aide Classe : Utilisation : HelpTooltip aide = new HelpTooltip("mon texte d’aide"); monPanneau.add(aide); Résultat : 63
  • 64. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CRÉATION DE COMPOSANTS Par héritage d’un Composite : Objectif: Permet de créer un composant en combinant plusieurs Widgets sans en exposer les méthodes. Attention : il est nécessaire d’appeler la fonction initWidget sur un des composants lors du constructeur. 64
  • 65. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CRÉATION DE COMPOSANTS Par implémentation de l’interface IsWidget : Le Widget est retourné par la méthode asWidget(). 65
  • 66. EXERCICE 3 : YET ANOTHER TODO LIST - CRÉATION DE COMPOSANTS
  • 67. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CRÉATION DE COMPOSANTS Etape 1 : Création du composant HelpTooltip Créer la classe HelpTooltip suivante : public class HelpTooltip extends Popover { @UiConstructor public HelpTooltip(String text) { super(); Icon helpIcon = new Icon(IconType.QUESTION_CIRCLE); helpIcon.setSize(IconSize.LARGE); add(helpIcon); setTitle(""); setContent(text); } public HelpTooltip(String text, Placement placement) { this(text); setPlacement(placement); } public void setText(String text) { setContent(text); } } 67
  • 68. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE IHM BOOTSTRAP Etape 2 : Création du composant TaskCreationPanel Créer la classe TaskCreationPanel suivante : public class TaskCreationPanel implements IsWidget { private VerticalPanel mainContainer; private TextBox description; private TextBox responsible; private DateBox deadLine; public TaskCreationPanel() { mainContainer = new VerticalPanel(); mainContainer.setSpacing(5); mainContainer.add(new Label("Ma tâche")); description = new TextBox(); HorizontalPanel descriptionPanel = new HorizontalPanel(); descriptionPanel.add(description); descriptionPanel.add(new HelpTooltip("Indiquez ici la description")); description.setPlaceholder("Description"); responsible = new TextBox(); responsible.setPlaceholder("Responsible"); deadLine = new DateBox(); mainContainer.add(descriptionPanel); mainContainer.add(responsible); mainContainer.add(deadLine); } @Override public Widget asWidget() { return mainContainer; } } 68
  • 69. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UNE IHM BOOTSTRAP Etape 3 : Modificiation de MonApplication Modifier la classe MonApplication de la manière suivante : ... public void onModuleLoad() { Jumbotron jumbotron = new Jumbotron(); Container container = new Container(); Heading heading = new Heading(HeadingSize.H1); heading.setText("Ma Todo List"); container.add(heading); jumbotron.add(container); VerticalPanel mainContent = new VerticalPanel(); mainContent.setWidth("100%"); mainContent.add(jumbotron); TaskCreationPanel taskCreationPanel = new TaskCreationPanel(); mainContent.add(taskCreationPanel); RootPanel.get().add(mainContent); } ... FinExercice3c 69
  • 71. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UIBINDER : MOTEUR DE TEMPLATES Rôle Simplifier la création d’écran complexes avec un moteur de templates Principe Un fichier de description, monFichier.ui.xml, permet de définir l’écran de manière similaire à une page HTML/JSP... Dans ce fichier les noms des balises importantes sont indiqués via l’attribut ui:field Une classe, monFichier.java permet de définir le comportement dynamique associé à cet écran. Cette classe étend Composite Dans cette classe on retrouve le nom des attributs ui:field indiqués dans le fichier de description 71
  • 72. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UIBINDER : EXEMPLE Descripteur : MetadataSearchViewImpl.ui.xml 72
  • 73. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UIBINDER : EXEMPLE Classe : MetadataSearchViewImpl.java 73
  • 74. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UIBINDER : COMPLÉMENTS Instantication des champs ui:field Soit par le fichier de description lors de l’appel à initWidget dans le constructeur : initWidget(uiBinder.createAndBindUi(this)); Soit manuellement • En modifiant l’annotation UiField : @UiField(provided = true) • En instanciant les champs avant l’appel à initWidget. Ajout de comportement sur les éléments Via l’annotation @UiHandler La signature de la méthode permet d’indiquer l’évènement géré @UiHandler("searchButton") void onSearchButtonClicked(ClickEvent event) { ... } 74
  • 75. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UIBINDER : COMPLÉMENTS Utilisation de Widgets personnels La balise <ui:UiBinder> permet de définir via des espaces de nommage les packages utilisables dans la page: <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:l="urn:import:fr.sedoo.metadata.client.ui.widget.date"> ... <l:Iso19115DateBox ui:field="startDate" /> Des paramètres peuvent être transmis dans les attributs. Si le Widget possède plusieurs constructeurs, l’annotation @UiConstructeur permet d’indiquer celui que UiBinder va utiliser. 75
  • 76. EXERCICE 3 : YET ANOTHER TODO LIST - UTILISATION UIBINDER
  • 77. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UTILISATION UIBINDER Etape 1 : Ajouter la classe Task Dans le package shared ajouter la classe suivante : public class Task implements IsSerializable { private String description; private String responsible; private Date deadLine; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getResponsible() { return responsible; } public void setResponsible(String responsible) { this.responsible = responsible; } public Date getDeadLine() { return deadLine; } public void setDeadLine(Date deadLine) { this.deadLine = deadLine; } } 77
  • 78. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UTILISATION UIBINDER Etape 2 : Ajouter la classe NewTaskCreationPanel Dans le package client ajouter la classe suivante : public class NewTaskCreationPanel extends Composite { @UiField TextBox description; @UiField TextBox responsible; @UiField DateTimePicker deadLine; private static LocalUiBinder uiBinder = GWT.create(LocalUiBinder.class); interface LocalUiBinder extends UiBinder<Widget, NewTaskCreationPanel> { } public NewTaskCreationPanel() { super(); initWidget(uiBinder.createAndBindUi(this)); } public void reset() { description.setText(""); responsible.setText(""); deadLine.setValue(null); } public Task flush() { Task result = new Task(); result.setResponsible(responsible.getText()); result.setDescription(description.getText()); result.setDeadLine(deadLine.getValue()); return result; } } 78
  • 79. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UTILISATION UIBINDER Etape 3 : Ajouter le fichier NewTaskCreationPanel.ui.xml Dans le package client ajouter le fichier NewTaskCreationPanel.ui.xml avec le contenu suivant : <!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:b="urn:import:org.gwtbootstrap3.client.ui" xmlns:b2="urn:import:org.gwtbootstrap3.extras.datetimepicker.client.ui" > <g:HTMLPanel width="90%"> <h2>Enter a new task</h2> <form class="form-horizontal" > <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">Description</label> <div class="col-sm-10"> <b:TextBox placeholder="Enter description" ui:field="description" /> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">Responsible</label> <div class="col-sm-10"> <b:TextBox placeholder="Enter responsible" ui:field="responsible"/> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">Dead line</label> <div class="col-sm-10"> <b2:DateTimePicker ui:field="deadLine"/> </div> </div> </form> </g:HTMLPanel> </ui:UiBinder> 79
  • 80. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UTILISATION UIBINDER Etape 4 : Modification du fichier MonApplication.gwt.xml Dans le fichier MonApplication.gwt.xml ajouter la ligne suivantes <inherits name="org.gwtbootstrap3.extras.datetimepicker.DateTimePicker"/> Etape 5 : Modification de la fonction onModuleLoad Dans le fichier MonApplication.java modifier la fonction onModuleLoad public void onModuleLoad() { Jumbotron jumbotron = new Jumbotron(); Container container = new Container(); Heading heading = new Heading(HeadingSize.H1); heading.setText("Ma Todo List"); container.add(heading); jumbotron.add(container); VerticalPanel mainContent = new VerticalPanel(); mainContent.setWidth("100%"); mainContent.add(jumbotron); NewTaskCreationPanel taskCreationPanel = new NewTaskCreationPanel(); mainContent.add(taskCreationPanel); RootPanel.get().add(mainContent); } 80
  • 81. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UTILISATION UIBINDER FinExercice3d 81
  • 83. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CLIENTFACTORY Objectif : Optimiser le temps d’instanciation des objets complexes Problème : Certains composants clients sont coûteux à instancier notamment les différents éléments de l’interface graphique. Solution : Utiliser une Factory ayant la charge d’instancier de manière unique - et si nécessaire - ces différents composants et de les transmettre aux objets voulant les utiliser (Exemple: le Presenter dans le modèle MVP) . Remarque Par ce mécanisme, les écrans graphiques ne sont créés qu’une seule fois. Ils sont par contre remis à zéro (exemple : vidage des champs de saisie) lors de chaque utilisation. Ce concept de Singleton est aussi étendu pour gérer les autres instances uniques de l’application comme par exemple le bus d’évènements (cf. infra). 83
  • 84. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE La mise en place de la ClientFactory et Activity est effectuée de la manière suivante: 1. Création de l’interface (ClientFactory) et d’une ou plusieurs de ses implémentations (ex ClientFactoryImpl, ClientFactoryMobileImpl...) dans le package client. 2. Déclaration dans le descripteur de module <replace-with class="fr.jdev.atelier.client.ClientFactoryImpl"> <when-type-is class="fr.jdev.atelier.client.ClientFactory" /> </replace-with> Dans cet exemple la classe, au moment de la compilation Java vers Javascript, ClientFactory sera remplacée par ClientFactoryImpl lorsqu’elle est appellée via GWT.create(). On peut imaginer des statégies plus fines (en fonction du périphérique client, ...) 3. Instanciation du singleton, normalement dans le onModuleLoad. clientFactory = GWT.create(ClientFactory.class); 84
  • 86. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion BUS D'ÉVÈNEMENTS Objectif : Simplifier la communication entre les composants Problème : Les interfaces des applications GWT peuvent contenir de nombreux composants qui doivent dialoguer entre eux. Toutefois, dans certains cas ce dialogue ne peux pas se faire directement Pour éviter un trop fort couplage entre les classes. Parce que les composants cibles du dialogue ne peuvent pas être connus du composant source. Solution : GWT propose un bus permettant l’échange d’évènements entre composants reposant sur un mécanisme d’abonnement: 1. Un type d’évènement spécifique est défini. 2. Les composants cibles s’abonnent à ce type d’évènement auprès du bus. 3. Lorsque nécessaire, le composant source instancie un évènement et demande sa propagation sur le bus. 86
  • 87. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion DÉFINITION D'UN ÉVÈNEMENT Exemple : évènement signalant la connexion d’un utilisateur - UserLoginEvent Il est nécessaire de créer deux classes: Le gestionnaire : UserLoginEventHandler L’évènement : UserLoginEvent Le gestionnaire Interface qui sera implémentée par les classes écoutant l’évènement Doit étendre com.google.gwt.event.shared.EventHandler 87
  • 88. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion DÉFINITION D'UN ÉVÈNEMENT L’évènement La classe doit étendre com.google.gwt.event.shared.GwtEvent Elle définit un attribut statique - traditionnellement nommé TYPE - qui va identifier l’évènement et permettre de s’y abonner auprès du bus. 88
  • 89. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion ABONNEMENT ET PUBLICATION Abonnement à un évènement L’abonnement auprès du bus s’effectue via la méthode addHandler en passant en paramètres le type de l’évènement et le composant cible. Celui-ci doit implémenter le Handler correspondant à l’évènement : EVENT_BUS.addHandler(UserLoginEvent.TYPE, monComposantCible); Publication d’un évènement La diffusion d’un évènement sur le bus s’effectue de la manière suivante : UserLoginEvent monEvenement = new UserLoginEvent(); // Valorisation de l’objet monEvenement ... EVENT_BUS.fireEvent(monEvenement); 89
  • 90. EXERCICE 4 : AJOUT D'UN ÉVÈNEMENT
  • 91. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion AJOUT D'UN ÉVÈNEMENT Etape 1 : Ajouter la classe NotificationEvent Dans le package client.event ajouter la classe suivante : public class NotificationEvent extends GwtEvent<NotificationEventHandler> { public static final Type<NotificationEventHandler> TYPE = new Type<NotificationEventHandler>(); private String message; public NotificationEvent(String message) { this.setMessage(message); } @Override protected void dispatch(NotificationEventHandler handler) { handler.onNotification(this); } @Override public com.google.gwt.event.shared.GwtEvent.Type<NotificationEventHandler> getAssociatedType() { return TYPE; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } 91
  • 92. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion AJOUT D'UN ÉVÈNEMENT Etape 2 : Ajouter l'interface NotificationEventHandler Dans le package client.event ajouter l’interface suivante : public interface NotificationEventHandler extends EventHandler { void onNotification(NotificationEvent event); } Etape 3 : Ajouter l'interface ClientFactory Dans le package client ajouter l’interface suivante : public interface ClientFactory extends NotificationEventHandler { EventBus getEventBus(); } 92
  • 93. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion AJOUT D'UN ÉVÈNEMENT Etape 4 : Ajouter la classe ClientFactoryImpl Dans le package client ajouter la classe suivante : public class ClientFactoryImpl implements ClientFactory { private static final EventBus EVENT_BUS = new SimpleEventBus(); public ClientFactoryImpl() { getEventBus().addHandler(NotificationEvent.TYPE, this); } @Override public EventBus getEventBus() { return EVENT_BUS; } @Override public void onNotification(NotificationEvent event) { Growl.growl(event.getMessage()); } 93
  • 94. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion AJOUT D'UN ÉVÈNEMENT Etape 5 : Modification du fichier MonApplication.gwt.xml Modifier le fichier MonApplication.gwt.xml en ajoutant les lignes : <inherits name="org.gwtbootstrap3.extras.growl.Growl"/> <replace-with class="fr.jdev.atelier.client.ClientFactoryImpl"> <when-type-is class="fr.jdev.atelier.client.ClientFactory" /> </replace-with> 94
  • 95. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion AJOUT D'UN ÉVÈNEMENT Etape 6 : Modification du fichier MonApplication.java Modifier le fichier MonApplication.java de la manière suivante : public class MonApplication implements EntryPoint { private static ClientFactory clientFactory; public static ClientFactory getClientFactory() { if (clientFactory == null) { clientFactory = GWT.create(ClientFactory.class); } return clientFactory; } public void onModuleLoad() { clientFactory = getClientFactory(); Jumbotron jumbotron = new Jumbotron(); Container container = new Container(); Heading heading = new Heading(HeadingSize.H1); heading.setText("Ma Todo List"); container.add(heading); jumbotron.add(container); VerticalPanel mainContent = new VerticalPanel(); mainContent.getElement().getStyle().setMargin(5, Unit.PX); mainContent.getElement().getStyle().setBorderColor("white"); mainContent.getElement().getStyle().setBorderWidth(2, Unit.PCT); mainContent.getElement().getStyle().setBorderStyle(BorderStyle.SOLID); mainContent.add(jumbotron); NewTaskCreationPanel taskCreationPanel = new NewTaskCreationPanel(); mainContent.add(taskCreationPanel); Button addButton = new Button("Add"); addButton.setIcon(IconType.PLUS); addButton.setType(ButtonType.PRIMARY); addButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { getClientFactory().getEventBus().fireEvent(new NotificationEvent("Task added...")); } }); mainContent.add(addButton); mainContent.setWidth("98%"); RootPanel.get().add(mainContent); } } 95
  • 96. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UTILISATION UIBINDER FinExercice4 96
  • 98. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion TROIS COMPOSANTS STRUCTURANTS La cinématique d’une application Ajax diffère d’une application Web traditionnelle où le serveur joue un rôle de chef d’orchestre. Les versions récentes de GWT ont introduit un certain nombre de bonnes pratiques permettant la construction rigoureuse d’une telle cinématique: Gestion de l’historique Activities and Places Patron Model-View-Presenter 98
  • 99. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion GESTION DE L'HISTORIQUE Objectif : Permettre une gestion complète de l’historique, notamment la navigation via les boutons Précédent/Suivant Principe : Chaque état de l’application est sérialisé sous forme d’une chaine (token) ajoutée à l’URL actuelle sous forme d’un lien nommé (c.a.d séparé par un #). Exemple : http://sedoo.sedoo.fr/portailresif/#WelcomePlace: Un évènement de type navigation (Précédent, Suivant, Rafraichissement) déclenche un évènement de type ValueChangeEvent. 99
  • 101. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion GESTION DE L'HISTORIQUE Mise en œuvre : Activation dans le conteneur HTML <iframe src="javascript:’’" id="__gwt_historyFrame" style="position:absolute;width:0;height:0;border:0"></iframe> Une nouvelle étape dans l’historique est ajoutée en appelant History.newItem(token) Chaque objet voulant réagir aux évènement de l’historique s’abonne aux History.addValueChangeHandler(). Chaque abonné devra déterminer • si l’évènement le concerne • comment reconstruire l’état correspondant au token. 101
  • 103. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion ACTIVITIES Activity : Une activité est une fonctionnalité de l’application effectuée par un utilisateur. Exemples : LoginActivity, SearchActivity... Une activité étend com.google.gwt.activity.shared.AbstractActivity Cycle de vie : La gestionnaire d’activité (com.google.gwt.activity.shared.ActivityManager) active et désactive les activités via les méthodes suivantes : start Invoquée lors du démarage de l’activité. A son is- sue, l’activité doit fournir la vue lui correspondant. mayStop Invoquée pour savoir si l’activité en cours peut s’ar- rêter. onStop Invoquée lors de l’arrêt de l’activité. onCancel Invoquée lorsque le démarrage n’est pas termn- iné mais que l’utilisateur a demandé le début d’une autre activité. 103
  • 104. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion PLACES Place : Une place représente un état d’utilisation d’une activité. Il doit pouvoir être sérialisé sous forme de token conformément au mécanisme de gestion de l’historique. Mise en œuvre : Une place hérite de com.google.gwt.place.shared.Place. Le tokenizer associé à la place hérite de com.google.gwt.place.shared.PlaceTokenizer. Il permet la sérialisation/désérialisation de l’état via les méthodes suivantes : getPlace Construit la place à partir du token. getToken Sérialise la place sous forme de token. Bonne pratique A chaque instanciation d’une activité, une place va lui être transmise afin que l’activité recrée son état. 104
  • 105. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion NAVIGATION VIA LES PLACES Les places sont le meilleur moyen de naviguer au sein d’une application GWT. Le mécanisme est le suivant: 1. Instanciation et valoriastion de la place souhaitée 2. Récupération de l’instance du PlaceController (Cf. ClientFactory) 3. Appel de la méthode PlaceController.goTo(place) 4. Si la place souhaitée n’est pas la place en cours, l’activité correspondante à la place est instanciée (cf. page suivante). 5. La méthode start de l’activité est appelée. Remarques Ce mécanisme est également celui utilisé lors de l’analyse d’une URL pointant sur une place de l’application. Le PlaceController utilise la méthode equals pour comparer place actuelle et destination. Le cas échéant il peut être nécessaire de surcharger cette méthode 105
  • 106. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion NAVIGATION VIA LES PLACES La correspondance entre Place et Activity est effectuée de la manière suivante: 1. Le PlaceController envoie un évènement de changement de place (PlaceChangeEvent) 2. L’évènement est reçu par le gestionnaire d’activités (ActivityManager) 3. Le gestionnaire d’activités utilise son ActivityMapper qui lui indique l’activité à démarrer via la méthode Activity getActivity(Place place); La classe ActivityMapper est donc le composant central du mécanisme. Exemple public Activity getActivity(Place place) { if (place instanceof WelcomePlace) { return new WelcomeActivity((WelcomePlace) place, clientFactory); } ... } 106
  • 107. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion NAVIGATION VIA LES PLACES Activité A ActivityManager ActivityMapper Activité B PlaceController EventBus ClientFactory évènement crééPlaceB() getPlaceController() goTo(placeB)() fireEvent(placeChangeRequestEvent(placeB)) onPlaceChangeRequest(PlaceChangeRequestEvent)(placeB) mayStop() fireEvent(placeChangeEvent(placeB)) onPlaceChange(placeB) getActivity(placeB) nouvelle activité B onStop() start() 107
  • 109. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion PATRON MODEL-VIEW-PRESENTER GWT étend le traditionnel modèle MVC avec le patron MVP dans lequel le Presenter tient le rôle central. Nom Situation Rôle Model Côté serveur Récupère les données (via les DAO). View Côté client Affichage des données transmises par le Presenter. Transmet au Presenter les évènements importants (exemple: click sur des boutons,...) Presenter Côté client Mobilise le Model et transmet les données à la vue. Réagit aux évènements transmis par la vue afin nota- ment de dialoguer avec le Model ou changer de Place Stratégie L’objectif est de postionner un maximum d’intelligence au niveau du Presenter afin que celui-ci puisse fonctionner indifféremment avec plusieurs implémentations de View (exemple: View pour un écran d’ordinateur de grande taille, View pour un mobile, View ficitve pour les tests...). La View est donc dépourvue de traitements outre ceux spécifiques à son implémentation. Ceci permet de l’exclure plus ou moins de la chaine de test. 109
  • 110. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion DIAGRAMME MVP Presenter ModelView 110
  • 111. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion INTÉGRATION AVEC LE MODÈLE ACTIVITIES AND PLACES L’activity joue le rôle du Presenter 111
  • 112. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE D'UNE VIEW Une View doit être définie sous forme d’une Interface qui étend com.google.gwt.user.client.ui.IsWidget. Le Presenter ne doit connaître que cette Interface. Si la View doit pouvoir transmettre des informations au Presenter, l’usage veut que celui-ci soit défini comme une sous-interface de la View. Dans ce cas: La View doit définir une methode setPresenter correspondante. L’Activity doit implémenter le Presenter. 112
  • 113. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion RÉCUPÉRATION DE LA VIEW PAR LE PRESENTER Le lien entre une View et l’implémentation à utiliser dans le contexte courant est fait par la ClientFactory. Ceci permet d’envisager la mise en place de plusieurs implémentations de ClientFactory: pour les mobiles pour les tests ... 113
  • 114. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CINÉMATIQUE D'UTILISATION Classiquement, la cinématique d’utilisation est la suivante: 1. L’Activity récupère l’instance de la View auprès de la ClientFactory (dans sa méthode start) 2. Si nécessaire, utilise la méthode setPresenter de la View pour permettre une communication View ⇒ Presenter. 3. L’Activity remet à zéro l’instance de la View (qui a peut être servi au préalable) 4. L’Activity recherche auprès du Model les informations nécessaires 5. L’Activity les transmet à la vue qui les positionne. 6. L’Activity affiche la vue via la commande containerWidget.setWidget(view.asWidget()); 114
  • 115. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CINÉMATIQUE D'UTILISATION ActivityManager MonActivité MaVue MonModèle ClientFactory start() getMaVue() instance de MaVue setPresenter(this) reset() chargeInformations() afficheInformations() affiche la vue 115
  • 116. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion COMMUNICATION PRESENTER - MODEL La communication entre le Presenter et le Model s’effectue via le mécanisme GWT-RPC décrit dans la section suivante. 116
  • 117. EXERCICE 5 : MISE EN PLACE MVP
  • 118. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 1 : Modification du fichier MonApplication.gwt.xml Dans le fichier MonApplication.gwt.xml ajouter les lignes suivantes : <inherits name="com.google.gwt.activity.Activity" /> <inherits name="com.google.gwt.place.Place" /> Etape 2 : Modification du fichier Task.java Dans le fichier Task.java ajouter les lignes suivantes : private String uuid; public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } 118
  • 119. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 3 : Modification du fichier ClientFactory.java Dans le fichier ClientFactory.java ajouter les lignes suivantes : PlaceController getPlaceController(); WelcomeView getWelcomeView(); TaskConsultView getTaskConsultView(); TaskListView getTaskListView(); 119
  • 120. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 4 : Modification du fichier ClientFactoryImpl.java Modifier le fichier ClientFactoryImpl.java de la manière suivante : public class ClientFactoryImpl implements ClientFactory { private static final EventBus EVENT_BUS = new SimpleEventBus(); private static final PlaceController PLACE_CONTROLLER = new PlaceController(EVENT_BUS); WelcomeView welcomeView = new WelcomeViewImpl(); TaskListView taskListView = new TaskListViewImpl(); public ClientFactoryImpl() { getEventBus().addHandler(NotificationEvent.TYPE, this); } @Override public EventBus getEventBus() { return EVENT_BUS; } @Override public void onNotification(NotificationEvent event) { Growl.growl(event.getMessage()); } @Override public PlaceController getPlaceController() { return PLACE_CONTROLLER; } @Override public WelcomeView getWelcomeView() { return welcomeView; } @Override public TaskConsultView getTaskConsultView() { return null; } @Override public TaskListView getTaskListView() { return taskListView; } } 120
  • 121. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 5 : Création de la classe WelcomePlace.java Dans le package client.place ajouter la classe suivante : public class WelcomePlace extends Place { public static class Tokenizer implements PlaceTokenizer<WelcomePlace> { public WelcomePlace getPlace(String token) { return new WelcomePlace(); } public String getToken(WelcomePlace place) { return ""; } } } 121
  • 122. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 6 : Création de la classe TaskListPlace.java Dans le package client.place ajouter la classe suivante : public class TaskListPlace extends Place { public TaskListPlace() { } public static class Tokenizer implements PlaceTokenizer<TaskListPlace> { public TaskListPlace getPlace(String token) { return new TaskListPlace(); } public String getToken(TaskListPlace place) { return ""; } } } 122
  • 123. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 7 : Création de la classe TaskConsultPlace.java Dans le package client.place ajouter la classe suivante : public class TaskConsultPlace extends Place { private String taskUuid; public TaskConsultPlace() { } public String getTaskUuid() { return taskUuid; } public void setTaskUuid(String taskUuid) { this.taskUuid = taskUuid; } public static class Tokenizer implements PlaceTokenizer<TaskConsultPlace> { public TaskConsultPlace getPlace(String token) { TaskConsultPlace place = new TaskConsultPlace(); place.setTaskUuid(token); return place; } public String getToken(TaskConsultPlace place) { return ""; } } } 123
  • 124. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 8 : Création de la classe AppActivityMapper.java Dans le package client.mvp ajouter la classe suivante : public class AppActivityMapper implements ActivityMapper { private ClientFactory clientFactory; public AppActivityMapper(ClientFactory clientFactory) { super(); this.clientFactory = clientFactory; } @Override public Activity getActivity(Place place) { if (place instanceof TaskConsultPlace) { return new TaskConsultActivity((TaskConsultPlace) place, clientFactory); } else if (place instanceof TaskListPlace) { return new TaskListActivity((TaskListPlace) place, clientFactory); } else { return new WelcomeActivity(new WelcomePlace(), clientFactory); } } } 124
  • 125. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 9 : Création de la classe AppPlaceHistoryMapper.java Dans le package client.mvp ajouter la classe suivante : @WithTokenizers({ WelcomePlace.Tokenizer.class, TaskConsultPlace.Tokenizer.class, TaskListPlace.Tokenizer.class }) public interface AppPlaceHistoryMapper extends PlaceHistoryMapper { } 125
  • 126. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 10 : Création de la classe WelcomeActivity.java Dans le package client.activity ajouter la classe suivante : public class WelcomeActivity extends AbstractActivity implements Presenter { private ClientFactory clientFactory; private WelcomeView welcomeView; public WelcomeActivity(WelcomePlace place, ClientFactory clientFactory) { this.clientFactory = clientFactory; } @Override public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) { welcomeView = clientFactory.getWelcomeView(); welcomeView.setPresenter(this); welcomeView.reset(); containerWidget.setWidget(welcomeView.asWidget()); } @Override public void addTask(Task task) { Window.alert("A coder dans le prochain exercice"); } @Override public void showList() { clientFactory.getPlaceController().goTo(new TaskListPlace()); } } 126
  • 127. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 11 : Création de la classe TaskListActivity.java Dans le package client.activity ajouter la classe suivante : public class TaskListActivity extends AbstractActivity implements Presenter { private ClientFactory clientFactory; private TaskListView taskListView; public TaskListActivity(TaskListPlace place, ClientFactory clientFactory) { this.clientFactory = clientFactory; } @Override public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) { taskListView = clientFactory.getTaskListView(); taskListView.reset(); containerWidget.setWidget(taskListView.asWidget()); } @Override public void display(String taskUuid) { TaskConsultPlace taskConsultPlace = new TaskConsultPlace(); taskConsultPlace.setTaskUuid(taskUuid); clientFactory.getPlaceController().goTo(taskConsultPlace); } } 127
  • 128. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 12 : Création de la classe TaskConsultActivity.java Dans le package client.activity ajouter la classe suivante : public class TaskConsultActivity extends AbstractActivity { private ClientFactory clientFactory; private TaskConsultView taskConsultView; private String taskUuid; public TaskConsultActivity(TaskConsultPlace place, ClientFactory clientFactory) { this.clientFactory = clientFactory; taskUuid = place.getTaskUuid(); } @Override public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) { taskConsultView = clientFactory.getTaskConsultView(); taskConsultView.reset(); containerWidget.setWidget(taskConsultView.asWidget()); } } 128
  • 129. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 13 : Création de la classe WelcomeView.java Dans le package client.view ajouter la classe suivante : public interface WelcomeView extends IsWidget { void reset(); void setRecentTask(ArrayList<Task> tasks); void setPresenter(Presenter presenter); public interface Presenter { void addTask(Task task); void showList(); } } 129
  • 130. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 14 : Création de la classe TaskListView.java Dans le package client.view ajouter la classe suivante : public interface TaskListView extends IsWidget { void reset(); void displayTasks(ArrayList<Task> tasks); void setPresenter(Presenter presenter); public interface Presenter { void display(String taskUuid); } } 130
  • 131. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 15 : Création de la classe TaskConsultView.java Dans le package client.view ajouter la classe suivante : public interface TaskConsultView extends IsWidget { void reset(); void display(Task task); } 131
  • 132. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 16 : Création de la classe WelcomeViewImpl.java Dans le package client.view ajouter la classe suivante : public class WelcomeViewImpl extends VerticalPanel implements WelcomeView { private NewTaskCreationPanel taskCreationPanel; private Presenter presenter; public WelcomeViewImpl() { super(); getElement().getStyle().setMargin(5, Unit.PX); getElement().getStyle().setBorderColor("white"); getElement().getStyle().setBorderWidth(2, Unit.PCT); getElement().getStyle().setBorderStyle(BorderStyle.SOLID); taskCreationPanel = new NewTaskCreationPanel(); add(taskCreationPanel); Button addButton = new Button("Add"); addButton.setIcon(IconType.PLUS); addButton.setType(ButtonType.PRIMARY); addButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { presenter.addTask(taskCreationPanel.flush()); } }); add(addButton); Button taskListButton = new Button("View all"); taskListButton.getElement().getStyle().setMarginTop(5, Unit.PX); taskListButton.setIcon(IconType.LIST); taskListButton.setType(ButtonType.PRIMARY); taskListButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { presenter.showList(); } }); add(taskListButton); setWidth("98%"); } @Override public void reset() { taskCreationPanel.reset(); } @Override public void setRecentTask(ArrayList<Task> tasks) { } @Override public void setPresenter(Presenter presenter) { this.presenter = presenter; } } 132
  • 133. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 17 : Création de la classe TaskListViewImpl.java Dans le package client.view ajouter la classe suivante : public class TaskListViewImpl extends VerticalPanel implements TaskListView { private Presenter presenter; public TaskListViewImpl() { super(); getElement().getStyle().setMargin(5, Unit.PX); getElement().getStyle().setBorderColor("white"); getElement().getStyle().setBorderWidth(2, Unit.PCT); getElement().getStyle().setBorderStyle(BorderStyle.SOLID); Heading title = new Heading(HeadingSize.H2); title.setText("Task List"); add(title); } @Override public void reset() { } @Override public void setPresenter(Presenter presenter) { this.presenter = presenter; } @Override public void displayTasks(ArrayList<Task> tasks) { } } 133
  • 134. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE MVP Etape 18 : Modification de la classe MonApplication.java Modifier la classe MonApplication.java de la manière suivante : public class MonApplication implements EntryPoint { private static ClientFactory clientFactory; private ContentPanel dynamicPanel = new ContentPanel(); private Div staticContentPanel; public static ClientFactory getClientFactory() { if (clientFactory == null) { clientFactory = GWT.create(ClientFactory.class); } return clientFactory; } public void onModuleLoad() { clientFactory = getClientFactory(); initGui(); PlaceController placeController = getClientFactory().getPlaceController(); // Start ActivityManager for the main widget with our ActivityMapper ActivityMapper activityMapper = new AppActivityMapper(getClientFactory()); ActivityManager activityManager = new ActivityManager(activityMapper, getClientFactory().getEventBus()); activityManager.setDisplay(dynamicPanel); // Start PlaceHistoryHandler with our PlaceHistoryMapper AppPlaceHistoryMapper historyMapper = GWT.create(AppPlaceHistoryMapper.class); PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper); historyHandler.register(placeController, getClientFactory().getEventBus(), new WelcomePlace()); historyHandler.handleCurrentHistory(); } private void initGui() { staticContentPanel = new Div(); Jumbotron jumbotron = new Jumbotron(); Container container = new Container(); Heading heading = new Heading(HeadingSize.H1); heading.setText("Ma Todo List"); container.add(heading); jumbotron.add(container); staticContentPanel.add(jumbotron); staticContentPanel.add(dynamicPanel); RootPanel.get().add(staticContentPanel); } private class ContentPanel extends VerticalPanel implements AcceptsOneWidget { public ContentPanel() { super(); setWidth("100%"); } @Override public void setWidget(IsWidget w) { if (w != null) { clear(); add(w.asWidget()); } } } 134
  • 136. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion GWT-RPC GWT-RPC (Remote Procedure Call) est un mécanisme simple de communication client/serveur. La mise en place d’un service RPC - par exemple MonService - passe par la création de trois classes: Côté client MonService : Définit l’interface du service MonServiceAsync : Équivalent asynchrone de l’interface MonService Côté serveur MonServiceImpl : Servlet implémentant le service (accès aux DAO...) Rappel Les objets pouvant transiter entre le serveur et le client doivent être situés dans le package shared être des beans sérialisables 136
  • 137. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion GWT-RPC 137
  • 138. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE CÔTÉ CLIENT Interface MonService L’interface doit étendre com.google.gwt.user.client.rpc.RemoteService. L’annotation @RemoteServiceRelativePath va permettre d’associer la partie cliente à la servlet correspondante. 138
  • 139. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE CÔTÉ CLIENT Interface MonServiceAsync Cette classe reprend les méthodes de MonService en leur rajoutant un aspect asynchrone (via les AsyncCallback ). Elle peut être générée automatiquement à partir de MonService (Eclipse propose cette possibilité via le QuickFix Create asynchronous RemoteService ... ) Elle permet une communication asynchrone afin de ne pas bloquer le navigateur. C’est uniquement cette classe qui sera utilisée concrètement. 139
  • 140. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion MISE EN PLACE CÔTÉ SERVEUR Classe MonServiceImpl Elle étend com.google.gwt.user.server.rpc.RemoteServiceServlet. Elle implémente MonService. Fichier web.xml La classe MonServiceImpl est une servlet. Elle doit être déclarée et mappée correctement dans le fichier web.xml. Ce mapping doit correspondre à la valeur indiquée pour l’annotation @RemoteServiceRelativePath 140
  • 141. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion UTILISATION DU SERVICE Typiquement, un service RPC doit être utilisé par le Presenter. Instanciation Elle utilise le mécanisme GWT.create afin de créer la classe MonServiceAsync: private final MonServiceAsync MON_SERVICE = GWT.create(MonService.class); Utilisation Les appels asynchrones nécessitent la mise en place - souvent anonyme - de classes de CallBack qui permettent de définir les traitements à effectuer en cas de réussite ou de succès. 141
  • 142. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion ASPECT ASYNCHRONE DES ÉCHANGES Les appels du client vers le serveur sont asynchrones. Il faut donc bien veiller à faire en sorte que les traitements dépendants du résultat (exemple : mise à jour de l’IHM) soient positionnés dans les fonctions de callBack (onSuccess et onFailure) et non à la suite de l’appel. 142
  • 143. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion LIMITATIONS DE GWT-RPC RPC est un mécanisme assez simple qui contient certaines limitations. La principale est l’utilisation d’interfaces de type List ou Set pour les types d’échanges. Celle-ci est totalement possible. Toutefois, lors de la compilation en Javascript, une traduction pour chaque implémentation concrète présente dans l’émulation du JRE (ArrayList, Vector... )va être ajoutée, alourdissant ainsi le code généré. Ainsi, les types concrets doivent être privilégiés à ce niveau. Le mécanisme RequestFactory propose par rapport à RPC un certain nombre d’améliorations permettant d’avoir des échanges plus optimisés entre le client et le serveur. 143
  • 144. EXERCICE 6 : MISE EN PLACE GWT-RPC
  • 145. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 1 : Ajout/modification de la classe TaskListPanel.java Ajouter/Modifier la classe suivante : public class TaskListPanel extends VerticalPanel { private DetailPresenter presenter; public TaskListPanel() { super(); setWidth("100%"); } public void reset() { clear(); } public void setTasks(ArrayList<Task> tasks) { reset(); int i = 0; Grid grid = new Grid(tasks.size(), 4); grid.setWidth("100%"); for (Task task : tasks) { grid.setWidget(i, 0, new Label(task.getDescription())); grid.setWidget(i, 1, new Label(task.getResponsible())); grid.setWidget(i, 2, new Label(task.getDeadLine().toString())); Button detailButton = new Button("Detail"); detailButton.setType(ButtonType.PRIMARY); detailButton.setSize(ButtonSize.SMALL); final String uuid = task.getUuid(); detailButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { TaskConsultPlace taskConsultPlace = new TaskConsultPlace(); taskConsultPlace.setTaskUuid(uuid); MonApplication.getClientFactory().getPlaceController().goTo(taskConsultPlace); } }); grid.setWidget(i, 3, detailButton); i++; } add(grid); } public void setPresenter(DetailPresenter presenter) { this.presenter = presenter; } } 145
  • 146. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 2 : Ajout/modification de la classe TaskConsultActivity.java Ajouter/Modifier la classe suivante dans le package client.activity: public class TaskConsultActivity extends AbstractActivity { private ClientFactory clientFactory; private TaskConsultView taskConsultView; private String taskUuid; private static final TaskServiceAsync TASK_SERVICE = GWT.create(TaskService.class); public TaskConsultActivity(TaskConsultPlace place, ClientFactory clientFactory) { this.clientFactory = clientFactory; taskUuid = place.getTaskUuid(); } @Override public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) { taskConsultView = clientFactory.getTaskConsultView(); taskConsultView.reset(); containerWidget.setWidget(taskConsultView.asWidget()); TASK_SERVICE.findByUuid(taskUuid, new AsyncCallback<Task>() { @Override public void onSuccess(Task result) { taskConsultView.display(result); } @Override public void onFailure(Throwable caught) { Window.alert("KO"); } }); } } 146
  • 147. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 3 : Ajout/modification de la classe TaskListActivity.java Ajouter/Modifier la classe suivante dans le package client.activity: public class TaskListActivity extends AbstractActivity implements Presenter { private ClientFactory clientFactory; private TaskListView taskListView; private static final TaskServiceAsync TASK_SERVICE = GWT.create(TaskService.class); public TaskListActivity(TaskListPlace place, ClientFactory clientFactory) { this.clientFactory = clientFactory; } @Override public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) { taskListView = clientFactory.getTaskListView(); taskListView.setPresenter(this); taskListView.reset(); containerWidget.setWidget(taskListView.asWidget()); findAll(); } private void findAll() { TASK_SERVICE.findAll(new AsyncCallback<ArrayList<Task>>() { @Override public void onSuccess(ArrayList<Task> result) { taskListView.displayTasks(result); } @Override public void onFailure(Throwable caught) { Window.alert("KO"); } }); } @Override public void display(String taskUuid) { TaskConsultPlace taskConsultPlace = new TaskConsultPlace(); taskConsultPlace.setTaskUuid(taskUuid); clientFactory.getPlaceController().goTo(taskConsultPlace); } } 147
  • 148. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 4 : Ajout/modification de la classe WelcomeActivity.java Ajouter/Modifier la classe suivante dans le package client.activity: public class WelcomeActivity extends AbstractActivity implements Presenter { private ClientFactory clientFactory; private WelcomeView welcomeView; private static final TaskServiceAsync TASK_SERVICE = GWT.create(TaskService.class); public WelcomeActivity(WelcomePlace place, ClientFactory clientFactory) { this.clientFactory = clientFactory; } @Override public void start(AcceptsOneWidget containerWidget, final EventBus eventBus) { welcomeView = clientFactory.getWelcomeView(); welcomeView.setPresenter(this); welcomeView.reset(); containerWidget.setWidget(welcomeView.asWidget()); findLatest(); } private void findLatest() { TASK_SERVICE.findLatest(new AsyncCallback<ArrayList<Task>>() { @Override public void onSuccess(ArrayList<Task> result) { welcomeView.setRecentTask(result); } @Override public void onFailure(Throwable caught) { Window.alert("KO"); } }); } @Override public void addTask(Task task) { TASK_SERVICE.save(task, new AsyncCallback<Task>() { @Override public void onSuccess(Task result) { clientFactory.getEventBus().fireEvent(new NotificationEvent("Saved")); findLatest(); } @Override public void onFailure(Throwable caught) { Window.alert("KO"); } }); } @Override public void showList() { clientFactory.getPlaceController().goTo(new TaskListPlace()); } @Override public void display(String taskUuid) { TaskConsultPlace taskConsultPlace = new TaskConsultPlace(); taskConsultPlace.setTaskUuid(taskUuid); clientFactory.getPlaceController().goTo(taskConsultPlace); } } 148
  • 149. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 5 : Ajout/modification de la classe TaskConsultPlace.java Ajouter/Modifier la classe suivante dans le package client.place: public class TaskConsultPlace extends Place { private String taskUuid; public TaskConsultPlace() { } public String getTaskUuid() { return taskUuid; } public void setTaskUuid(String taskUuid) { this.taskUuid = taskUuid; } public static class Tokenizer implements PlaceTokenizer<TaskConsultPlace> { public TaskConsultPlace getPlace(String token) { TaskConsultPlace place = new TaskConsultPlace(); place.setTaskUuid(token); return place; } public String getToken(TaskConsultPlace place) { return place.getTaskUuid(); } } } 149
  • 150. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 6 : Ajout/modification de la classe TaskService.java Ajouter/Modifier la classe suivante dans le package client.service: @RemoteServiceRelativePath("tasks") public interface TaskService extends RemoteService { Task save(Task task); ArrayList<Task> findLatest(); ArrayList<Task> findAll(); Task findByUuid(String uuid); } 150
  • 151. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 7 : Ajout/modification de la classe TaskServiceAsync.java Ajouter/Modifier la classe suivante dans le package client.service: public interface TaskServiceAsync { void findAll(AsyncCallback<ArrayList<Task>> callback); void findLatest(AsyncCallback<ArrayList<Task>> callback); void save(Task task, AsyncCallback<Task> callback); void findByUuid(String uuid, AsyncCallback<Task> callback); } Etape 8 : Ajout/modification de la classe DetailPresenter.java Ajouter/Modifier la classe suivante dans le package client.view: public interface DetailPresenter { void display(String taskUuid); } 151
  • 152. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 9 : Ajout/modification de la classe TaskConsultViewImpl.java Ajouter/Modifier la classe suivante dans le package client.view: public class TaskConsultViewImpl extends VerticalPanel implements TaskConsultView { public TaskConsultViewImpl() { } @Override public void reset() { clear(); } @Override public void display(Task task) { add(new Label(task.getDescription())); add(new Label(task.getResponsible())); add(new Label(task.getDeadLine().toString())); } } 152
  • 153. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 10 : Ajout/modification de la classe TaskListView.java Ajouter/Modifier la classe suivante dans le package client.view: public interface TaskListView extends IsWidget { void reset(); void displayTasks(ArrayList<Task> tasks); void setPresenter(Presenter presenter); public interface Presenter extends DetailPresenter { } } 153
  • 154. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 11 : Ajout/modification de la classe TaskListViewImpl.java Ajouter/Modifier la classe suivante dans le package client.view: public class TaskListViewImpl extends VerticalPanel implements TaskListView { private Presenter presenter; private TaskListPanel taskListPanel; public TaskListViewImpl() { super(); setWidth("100%"); getElement().getStyle().setMargin(5, Unit.PX); getElement().getStyle().setBorderColor("white"); getElement().getStyle().setBorderWidth(2, Unit.PCT); getElement().getStyle().setBorderStyle(BorderStyle.SOLID); Heading title = new Heading(HeadingSize.H2); title.setText("Task List"); add(title); taskListPanel = new TaskListPanel(); add(taskListPanel); } @Override public void reset() { taskListPanel.reset(); } @Override public void setPresenter(Presenter presenter) { this.presenter = presenter; taskListPanel.setPresenter(presenter); } @Override public void displayTasks(ArrayList<Task> tasks) { taskListPanel.reset(); taskListPanel.setTasks(tasks); } } 154
  • 155. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 12 : Ajout/modification de la classe WelcomeView.java Ajouter/Modifier la classe suivante dans le package client.view: public interface WelcomeView extends IsWidget { void reset(); void setRecentTask(ArrayList<Task> tasks); void setPresenter(Presenter presenter); public interface Presenter extends DetailPresenter { void addTask(Task task); void showList(); } } 155
  • 156. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 13 : Ajout/modification de la classe WelcomeViewImpl.java Ajouter/Modifier la classe suivante dans le package client.view: public class WelcomeViewImpl extends VerticalPanel implements WelcomeView { private NewTaskCreationPanel taskCreationPanel; private TaskListPanel taskListPanel; private Presenter presenter; public WelcomeViewImpl() { super(); getElement().getStyle().setMargin(5, Unit.PX); getElement().getStyle().setBorderColor("white"); getElement().getStyle().setBorderWidth(2, Unit.PCT); getElement().getStyle().setBorderStyle(BorderStyle.SOLID); taskCreationPanel = new NewTaskCreationPanel(); add(taskCreationPanel); Button addButton = new Button("Add"); addButton.setIcon(IconType.PLUS); addButton.setType(ButtonType.PRIMARY); addButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { presenter.addTask(taskCreationPanel.flush()); } }); add(addButton); add(new Heading(HeadingSize.H2, "Latest")); taskListPanel = new TaskListPanel(); add(taskListPanel); Button taskListButton = new Button("View all"); taskListButton.getElement().getStyle().setMarginTop(5, Unit.PX); taskListButton.setIcon(IconType.LIST); taskListButton.setType(ButtonType.PRIMARY); taskListButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { presenter.showList(); } }); add(taskListButton); setWidth("98%"); } @Override public void reset() { taskCreationPanel.reset(); taskListPanel.reset(); } @Override public void setRecentTask(ArrayList<Task> tasks) { taskListPanel.setTasks(tasks); } @Override public void setPresenter(Presenter presenter) { this.presenter = presenter; taskListPanel.setPresenter(presenter); } } 156
  • 157. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 14 : Ajout/modification de la classe TaskServiceImpl.java Ajouter/Modifier la classe suivante dans le package server.service: public class TaskServiceImpl extends RemoteServiceServlet implements TaskService { ArrayList<Task> tasks = new ArrayList<>(); public TaskServiceImpl() { fakeInit(); } private void fakeInit() { for (int i = 0; i < 10; i++) { save(createTask(i)); } } @Override public Task save(Task task) { task.setUuid(UUID.randomUUID().toString()); tasks.add(task); return task; } @Override public ArrayList<Task> findLatest() { int maxElementCount = 5; int taskCount = tasks.size(); if (taskCount < maxElementCount) { maxElementCount = taskCount; } ArrayList<Task> aux = new ArrayList<Task>(tasks.subList(taskCount - maxElementCount, taskCount)); Collections.reverse(aux); return aux; } @Override public ArrayList<Task> findAll() { ArrayList<Task> aux = new ArrayList<Task>(tasks); Collections.reverse(aux); return aux; } public Task createTask(int count) { Task result = new Task(); result.setResponsible("Resp. " + count); result.setDescription("Description. " + count); result.setDeadLine(new Date()); return result; } @Override public Task findByUuid(String uuid) { for (Task task : tasks) { if (task.getUuid().compareTo(uuid) == 0) { return task; } } return null; } } 157
  • 158. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion EXERCICE 6 : MISE EN PLACE GWT-RPC Etape 15 : Modification du fichier web.xml Modifier le fichier web.xml de la manière suivante: <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"> <!-- Servlets --> <servlet> <servlet-name>taskServlet</servlet-name> <servlet-class>fr.jdev.atelier.server.service.TaskServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>taskServlet</servlet-name> <url-pattern>/monapplication/tasks</url-pattern> </servlet-mapping> <!-- Default page to serve --> <welcome-file-list> <welcome-file>MonApplication.html</welcome-file> </welcome-file-list> </web-app> 158
  • 160. Introduction Architecture Premi`ere application Cr´eation de l’interface graphique Bus d’´ev`enements Cin´ematique de l’appli- cation Communication client-serveur Conclusion CONCLUSION Le framework GWT est extrêmement riche, d’autres fonctionnalités restent à aborder : Mise en place du multilinguisme (I18n) Optimisation des ressources Image et Style Optimisation des échanges Client/Serveur (RequestFactory) Inversion de contrôle côté client (GIN) Chargement du code client par tranche (Code spliting) Data Binding (Framework Editor) ... De plus la mise en œuvre d’un projet GWT peut également nécessiter la connaissance de technologies complémentaires : Architecture REST (SOAP) Responsive Design Git & Gitflow ... 160