1. GWT (Google Web Toolkit)
réalisation facile d'applications
Web riches en Java
Présentation au JUG Montréal
par
Claude Coulombe
JUG Montréal 14 avril 2011
2. But
Dans cette présentation vous verrez comment
le Google Web Toolkit (GWT) permet le
développement rapide et facile d'applications
Web 2.0 et AJAX.
http://code.google.com/webtoolkit/
JUG Montréal 14 avril 2011
3. Web 1.0 – Cliquez & attendez!
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
4. Web 2.0 – « L'expérience-utilisateur »
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
5. Ajax – Une véritable percée!
AJAX
Le premier à utiliser le terme AJAX
fut Jesse James Garrett en février 2005
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
6. Ajax – Une véritable percée!
Ajax (Asynchronous JavaScript & XML)
Fini le pénible rechargement de pages!
Réalise des requêtes asynchrones au serveur et
fait la mise-à-jour de la page Web sans faire de
chargement complet
Applications Web plus réactives et plus
dynamiques
Objet XMLHttpRequest inventé par M$
Basé sur du code-client en JavaScript
Aujourd'hui, Ajax désigne les technologies Web du
fureteur : JavaScript, HTML/DOM, CSS
JUG Montréal 14 avril 2011
7. Créer des applications Web riches
Applications Web semblables à des applications
bureautiques en exécution locale (Desktop Like)
Interfaces rapides et réactives
Ouverture de plusieurs fenêtres à la fois dans le
navigateur
Déplacement des fenêtres dans le navigateur,
redimensionnement et défilement des fenêtres
Glisser et déposer des contenus
JUG Montréal 14 avril 2011
8. Pourquoi pas JavaScript ?
Euh!..., tout allait bien...
JavaScript tenait le coup...
puis soudain...
juste une p'tite refacto de rien
… la catastrophe !?!@;&$!!??
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
9. Pourquoi pas JavaScript ?
Problèmes de portabilité, incompatibilités des fureteurs, fuites de mémoire
& longs chargements
Pas de typage statique des variables en JavaSript
Le type d'une variable peut changer lorsqu'une nouvelle valeur lui est
affectée (typage dynamique). var unNombre = 2; unNombre = "deux";
Sensible à la moindre coquille, sensible à la casse
formulaire.montnat = document.getElementById(''montant'');
Quelques subtilités : null vs undefined vs false vs ""
Débogage à l'exécution pas à la compilation
Support inégal des outils et IDEs
Problème de sécurité XSS (injection de scripts)
Rareté des « programmeurs experts » en JavaScript
JUG Montréal 14 avril 2011
10. Pourquoi pas JavaScript ?
Made in
Ja vaScript
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
11. Pourquoi pas JavaScript ?
Excellente pour l'écriture rapide de petites applications, la souplesse de
JavaScript devient un handicap pour l'écriture de gros logiciels et de
logiciels complexes
Le typage dynamique représente une source importante d'erreurs pour de
gros logiciels
Pas d'espace de nommage (collision de variables), manque de modularité
et de capacité à grandir, pas un véritable langage à objets
Mise au point et réutilisation difficiles
Normal, car JS n'a pas été conçu pour de gros logiciels, mais juste pour
mettre un peu d'interactivité dans une page web
On peut voir le JavaScript comme le langage d'assemblage (assembleur)
du fureteur
JUG Montréal 14 avril 2011
12. Et si on utilisait Java...
Java
* Source Clipart : http://www.clipart.com
JUG Montréal * Source image : http://www.sun.com 14 avril 2011
13. Et si on utilisait Java...
Le langage du génie logiciel
Véritable langage de POO
Typage statique => trouver les erreurs à la compilation pas à l'exécution
Espace de nommage, (Package) => moins de risque de collision
Éprouvé dans la réalisation de logiciels / systèmes complexes
Multiplateforme - “Write Once, Run Anywhere” - Windows, Linux, OS X
Multiples langages dans la JVM : Scala, Groovy, Jruby, Jython, JavaScript...
Riche écosystème, nombreux outils et EDIs
+ bibliothèques et socles d'applications
+ outils en logiciels libres dont Java lui-même
puissants EDIs* (Eclipse, NetBeans ou IntelliJ)
débogueur / éditeur de code / refactorisation / analyse du code
Langage le plus répandu > 6 millions de développeurs
Abondante documentation sur le Web, + livres et + cours & formations
JUG Montréal 14 avril 2011
15. Qu'est-ce que GWT ?
En mai 2006 Google lance son Google Web Toolkit
Bruce Johnson & Joel Webber
Boîte à outils Ajax pour des applications Web riches
« orientées client »
Développement rapide d'applications Web riches par des
programmeurs Java ou pour de gros projets où JavaScript
montre ses limites
Transcompilateur (cross-compiler) de Java à JavaScript
Bon à la fois pour enrichir des applications Web avec des
composants Ajax et pour créer des applications similaires à
des applications bureautiques classiques (desktop-like) mais
qui tournent dans un fureteur Web
Logiciel libre (licence Apache 2)
JUG Montréal 14 avril 2011
16. GWT - Du pur Java!
Plus de 6 millions de développeurs Java
“Write Once, Run Anywhere”
Windows, Linux, Mac OS X
Véritable langage de POO
Utilise un EDI* Java usuel
Débogage du code-client avec EDI
Communication client-server d'objets Java
Code-client plus léger que des applets Java
* EDI : environnement de développement
intégré (en anglais IDE)
JUG Montréal * Source image : http://www.sun.com 14 avril 2011
17. GWT = Ajax + Génie Logiciel
Support du cycle de vie complet du logiciel
Outil interactif de construction d'IU ( GWT Designer)
Outil de construction d'IU déclaratif XML ( UiBinder)
Outil de mesure des performances ( Speed Tracer)
Plugiciel pour Eclipse
Support au débogage
Mise au point & débogage en mode dev
Cycle : édition / test / débogage /
Restructuration / refactorisation (refactoring)
Détection d'erreurs à la compilation
Journalisation (logging)
Patrons de conception OO éprouvés
Composite / MVC / MVP / commande / bus d'événements
Support de JUnit
Support de AppEngine et autres APIs de Google
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
19. GWT en « mode dev » - Développement
JUG Montréal * Source : http://www.google.com 14 avril 2011
20. GWT en « mode dev » - Développement
Dans Eclipse, une application GWT peut
s'exécuter en « mode dev » (“Development Mode”)
Mode”)
En « mode dev », la JVM exécute le code GWT
comme du bytecode Java à l'intérieur d'une
fenêtre de navigateur Web
Le « mode dev » facilite la mise-au-point :
Éditer le code-source
Rafraîchir
Examiner les résultats
JUG Montréal 14 avril 2011
21. GWT en « mode Web » - Déploiement
Une fois testé en « mode dev », vous pouvez
compiler votre code source Java en JavaScript et
déployer votre application Web
Une application Web GWT qui a été déployée est
dite en « mode Web »
Une fois compilé le code-client est uniquement du
pur JavaScript et du HTML
Afin de déployer votre application Web en
production, vous déplacez les fichiers du
répertoire « war » sur le serveur Web, i.e. Tomcat
JUG Montréal 14 avril 2011
23. GWT Designer
Éditeur graphique interactif d'IU
Racheté par Google de la société Instantiations
Entièrement intégré à Eclipse via un plugiciel
Génération de code bidirectionnelle
Alternance entre la vue Source et la vue Design
Palette de composants avec glisser-déposer
Vue Structure avec l'arbre des composants et un
panneau pour l'édition des propriétés
I18N
Création de composants réutilisables (Composite)
JUG Montréal 14 avril 2011
25. UiBinder
Outil de conception d'interface-utilisateur à partir d'une
représentation XML, sans programmation
Facilite le découplage entre la disposition du contenu en
XML, le code du comportement en Java et l'apparence
gouvernée par des feuilles de style CSS
<!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">
<g:HTMLPanel width="450px" height="300px">
<g:VerticalPanel width="450px" height="300px" horizontalAlignment="ALIGN_CENTER">
<g:Cell horizontalAlignment="ALIGN_CENTER">
<g:Label styleName="{style.titreJeu}" text="Jeux des trois portes (Monty Hall Problem)" width="450px" height="20px"
horizontalAlignment="ALIGN_CENTER"/>
</g:Cell>
<g:Cell horizontalAlignment="ALIGN_CENTER">
JUG Montréal 14 avril 2011
26. Speed Tracer (extension dans Chrome)
JUG Montréal * Source : http://www.google.com 14 avril 2011
27. Comprendre GWT
GWT
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
28. Application GWT – Client & Serveur
Le code (en Java ou tout autre
langage) qui s'exécute sur le
serveur est responsable de la
logique de l'application.
L'application Web utilise le
serveur pour charger ou
sauvegarder des données.
Le code-client en JavaScript
est transmis sur le réseau
vers un ordinateur-client, où
il s'exécute dans un fureteur
Web
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
29. Structure d'un projet GWT
MaPremiereAppli/
src/
PaquetConfig/
MaPremiereAppli.gwt.xml
PaquetClient
MonPremierService.java
MonPremierServiceAsync.java
MaPremiereAppli.java
PaquetServeur
MaPremiereAppli.java
META-INF/
jdoconfig.xml
log4j.properties
war/
mapremierappligwt/
… résultats compilation en JS ...
WEB-INF/
lib/
...App Engine JARs...
appengine-web.xml
logging.properties
web.xml
MaPremiereAppli.css
MaPremiereAppli.html
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
30. GWT – Structure bibliothèque & API
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
31. Vue d'ensemble de l'architecture GWT
Trans
compilateur
Interface Java à Bibliothèque
Native JavaScript d'émulation
JavaScript JRE
JSNI
GWT API
Bibliothèque
Communication
IUG avec le serveur
Analyseur Gestion de Intégration
Widgets & RPC & Ajax XML l'historique à JUnit
Panels
JUG Montréal * Source : http://www.google.com 14 avril 2011
32. GWT – Structure bibliothèque & API
La structure du gwt-user.jar Note : Transcompilateur GWT
Trans
dans gwt-dev-windows.jar
compilateur
Interface Java à Bibliothèque
Native JavaScript d'émulation
JavaScript
JRE
JSNI
GWT API
Bibliothèque
Communication
IUG Analyseur Gestion de Intégration
avec le serveur
Widgets & XML l'historique à JUnit
RPC & Ajax
Panels
JUG Montréal 14 avril 2011
33. Transcompilateur Java à JavaScript
Java
Write Once...
JavaScript
Run Everywhere!
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
34. Transcompilateur Java à JavaScript
Transcompilateur GWT prend du code-client en Java et
produit du code JavaScript optimisé
JavaScript devient le code assembleur du fureteur
Élimination du code non-utilisé dans les bibliothèques,
inférence de type, retrait du polymorphisme,
compression “agressive” du code, « Obfuscation »
Le JavaScript produit est généralement plus rapide que
du JavaScript écrit à la main*
Emploi de la liaison différée (“Deferred Binding”) pour
produire du code JavaScript optimal pour chaque
fureteur (i.e. génère du code spécifique à chaque
fureteur)
« Ne payez que pour ce que vous utilisez »
JUG Montréal * Note : sauf si code < 100 lignes 14 avril 2011
35. Transcompilateur Java à JavaScript
Code Java
MonProjet
.java Code
JavaScript
MonProjet.js
Ressources
MonProjet. html
MonProjet.css,
RessourcesMonPr
.png, .jpg, .gif
Transcompilateur ojet.
html
MonProjet.css,
Configuration .png, .jpg, .gif
Module
MonProjet.gwt
.xml
Autres .jar
gwt-user.jar gwt-dev.jar Compatibles
avec GWT
JUG Montréal 14 avril 2011
36. Transcompilateur Java à JavaScript
Du JavaScript plus rapide que du code écrit à la main !!!
Ainsi, ceci
public static void onModuleLoad() {
Button b = (new Button()).Button();
b.setText("Java vers JavaScript");
}
après compilation, donnera quelque chose comme cela...
function onModuleLoad(){
var b;
b = $Button(new Button());
$setInnerText(b.element, 'Java vers JavaScript');
}
JUG Montréal 14 avril 2011
37. Transcompilateur- Liaison différée
Générer du code optimal et spécifique à chaque fureteur
Copyright Google 2008
« Ne payez que pour ce que vous utilisez »
JUG Montréal * Source : http://www.google.com 14 avril 2011
38. Transcompilateur – Code optimisé!
Copyright Google 2008
« Ne payez que pour ce que vous utilisez »
JUG Montréal * Source : http://www.google.com 14 avril 2011
39. Emulation – JRE (Java Runtime Environment)
Le transcompilateur de GWT fournit l'émulation en
JavaScript d'un sous-ensemble du langage Java (JRE)
généralement utilisé pour la programmation de base
java.lang, java.util, java.io, java.sql
Restriction pour le code client
devant être traduit en JavaScript.
Aucune restriction n'est imposée
du côté du code serveur : Java
(JSP/JSF/Servlet), PHP,
ASP .NET, Perl, RoR, Python, Perl, ...
JUG Montréal * Source image : http://www.sun.com 14 avril 2011
40. Pourquoi pas JavaScript?
Made in
Ja vaScript
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
41. JSNI : JavaScript Native Interface
Intégration facile avec des bibliothèques JavaScript
externes grâce au JavaScript Native Interface (JSNI)
Interagir directement avec JavaScript (accès natif) à partir
de Java et vice-versa
Inclusion automatique des bibliothèques JavaScript
JavaScript Overlay pour simplifier l'intégration de
prototypes JavaScript dans GWT
// Déclaration d'une méthode JavaScript en Java...
native String inverserNomPrenom(String nom)
/*-{
// Implémentation en JavaScript
var re = /(w+)s(w+)/;
return name.replace(re, '$2, $1');
}-*/;
JUG Montréal 14 avril 2011
42. JSNI : JavaScript Type Overlay
JavaScript Type Overlay pour simplifier l'intégration de prototypes
JavaScript dans GWT
Une structure de données JSON (JavaScript Object Notation)
var electionsJSON = [
{ "Prenom" : "Gilles", "NomFamille" : "Duceppe" }, { "Prenom" : "Michael", "NomFamille" : "Ignatieff" },
{ "Prenom" : "Jack", "NomFamille" : "Layton" }, { "Prenom" : "Stephen", "NomFamille" : "Harper" }
];
// Un type Overlay JavaScript
class Politiciens extends JavaScriptObject {
// Un type Overlay JS a toujours un constructeur protected, à zéro argument
protected Politiciens() { }
// Les méthodes dans un Overlay JavaScript sont en JSNI
public final native String getPrenom() /*-{ return this.Prenom; }-*/;
public final native String getNomFamille() /*-{ return this.NomFamille; }-*/;
// Notez, toutefois, que toutes les méthodes ne sont pas obligatoirement en JSNI
public final String getNomComplet() {
return getPrenom() + " " + getNomFamille();
}
}
JUG Montréal * Source : http://googlewebtoolkit.blogspot.com 14 avril 2011
43. JSNI : Type Overlay JavaScript
// Obtenir un prototype JavaScript pour l'Overlay
class MonModuleEntryPoint implements EntryPoint {
public void onModuleLoad() {
Politiciens p = getPremierPoliticien();
// Youppi! Maintenant j'ai un prototype JavaScript qui est aussi un Politicien
Window.alert("Bonjour, " + p.getPrenom());
}
// Utilisation de JSNI pour obtenir le prototype JSON que nous désirons
// Le prototype JSON object reçoit un type Java implicitement
// en se basant sur le type retourné par la méthode
private native Politiciens getPremierPoliticien() /*-{
// Obtenir une référence au premier Politicien dans le tableau JSON
return $wnd.electionsJSON[0];
}-*/;
}
JUG Montréal * Source : http://googlewebtoolkit.blogspot.com 14 avril 2011
44. Génie logiciel pour les applications Web
riches & Ajax
Support du cycle de vie complet du logiciel
Patrons de conception OO éprouvés
EDIs* Java matures
Cycle : édition / test / débogage /
Restructuration (refactoring)
Support au débogage
Détection d'erreurs à la compilation
Mise au point & débogage en mode hôte
Journalisation (logging)
Support de JUnit
* EDI : environnement de développement
intégré (en anglais IDE)
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
46. IU – Programmation par événements
Essentiellement de la programmation par événements
Une méthode ou procédure s'exécute quand un
événement est déclenché
Dans une IU, un événement est déclenché chaque fois
que l'utilisateur clique sur la souris, appuie sur une
touche du clavier, sélectionne un élément dans un
menu, ouvre ou ferme une fenêtre, etc.
À chaque composant de l'IU appelé aussi contrôle ou
widget (comme un bouton, un menu, etc.) est associé
un ou plusieurs gestionnaires d'événements (Listener
ou Handler) qui peuvent comporter des paramètres
JUG Montréal 14 avril 2011
47. IU - Gestion des événements
GWT utilise le concept de gestionnaire d'événement
(handler interface) pour traiter les événements
Semblable à d'autres bibliothèques Java pour la
programmation d'IU comme SWING
Le gestionnaire via l'interface “handler interface”
définit une ou plusieurs méthodes que le widget
appelle en réaction à un événement
Button unBouton = new Button("Cliquez moi!");
unBouton.addClickHandler( new ClickHandler() {
public void onClick(ClickEvent event) {
Window.alert("Bouton cliqué!");
}
});
JUG Montréal 14 avril 2011
48. IU – Exemples d'événements
OnClick – déclenché quand l'usager clique un élément
OnBlur – déclenché quand un élément perd le focus du clavier
OnChange - déclenché quand le contenu de la saisie change
OnFocus – déclenché quand un élément reçoit le focus clavier
OnKeyDown – déclenché quand l'usager appuie sur une touche
OnKeyUp – déclenché quand l'usager relâche une touche
OnKeyPress – déclenché quand un caractère est généré
OnMouseOver – déclenché quand la souris passe au-dessus
OnMouseMove – déclenché quand la souris entre dans la zone
OnMouseOut – déclenché quand la souris sort de la zone
OnScroll – déclenché quand un élément avec défilement bouge
OnLoad – déclenché quand un élément termine de se charger
OnDblClick – déclenché quand l'usager double-clique
JUG Montréal 14 avril 2011
49. IU – Bibliothèque de composants
Éléments statiques: étiquette (Label), HTML, Image, hyperlien (Hyperlink), champ
caché (Hidden)
Widgets (E/S) : bouton (Button), bouton poussoir (PushButton), bouton à bascule
(ToggleButton), case à cocher (CheckBox), bouton radio (RadioButton), menu déroulant
(ListBox), zone de texte (TextBox), zone de texte avec suggestions ( SuggestBox), zone
d'entrée de mot de passe ( PasswordTextBox), zone de texte multiligne (TextArea), zone
d'édition de texte enrichi ( RichTextArea)
Widgets complexes : arbre ( Tree), barre de menus (MenuBar), téléversement de
fichiers (FileUpload)
Panneaux de disposition simple : panneau en file ( FlowPanel), panneau horizontal
(Horizontal Panel), panneau vertical (VerticalPanel), panneau à coulisse
(HorizontalSplitPanel, VerticalSplitPanel), panneau HTML (HTMLPanel), panneau
superposé (DeckPanel)
Panneaux de disposition complexe : table flexible* ( FlexTable), grille (Grid), panneau
polyptyque* (DockPanel), panneau à onglets (TabPanel), panneau en pile (StackPanel)
Panneaux conteneurs simples : panneau composite ou composite ( Composite) panneau
simple (SimplePanel), panneau à barre de défilement ( ScrollPanel), panneau de focus
(FocusPanel)
Panneaux conteneurs complexes : panneau de formulaire ( FormPanel), panneau à
dévoilement* (DisclosurePanel), panneau surprise* (PopupPanel), boîte de dialogue
(DialogBox)
JUG Montréal http://gwt.google.com/samples/Showcase/Showcase.html 14 avril 2011
50. Interface Utilisateur - Panneaux
DisclosurePanel
VerticalPanel HorizontalSplitPanel
HorizontalPanel
VerticalSplitPanel
FlowPanel
DockPanel
TabPanel
PopupPanel
JUG Montréal http://gwt.google.com/samples/Showcase/Showcase.html 14 avril 2011
51. Interface Utilisateur – Bouton simple
Bouton (Button)
// Création d'un bouton qui réagit à un clic grâce à un récepteur de clic
Button bouton = new Button("Cliquez-moi", new ClickListener() {
public void onClick(Widget sender) {
Window.alert("Bonjour GWT");
}
});
JUG Montréal 14 avril 2011
52. Interface Utilisateur – Case à cocher
Case à cocher (CheckBox)
// Création d'une case à cocher
CheckBox caseResidentMtl = new CheckBox("Résident de Montréal");
// La case est cochée par défaut
caseResidentMtl.setChecked(true);
// Attacher un récepteur de clic à la case
caseResidentMtl.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
boolean estMontrealais = ((CheckBox) sender).isChecked();
Window.alert( (estMontrealais ? "" : "non") + " Montréalais");
}
});
JUG Montréal 14 avril 2011
53. Interface Utilisateur – Bouton radio
Bouton radio (RadioButton)
// Création d'un groupe de boutons radio
RadioButton rbBleu = new RadioButton("groupeRbCouleurs", "bleu");
RadioButton rbBlanc = new RadioButton("groupeRbCouleurs", "blanc");
RadioButton rbRouge = new RadioButton("groupeRbCouleurs", "rouge");
// Cocher le bouton bleu par défaut
rbBleu.setChecked(true);
// Ajouter le groupe de boutons radio à un panneau
FlowPanel panneau = new FlowPanel();
panneau.add(rbBleu);
panneau.add(rbBlanc);
panneau.add(rbRouge);
JUG Montréal 14 avril 2011
54. Interface Utilisateur – Boîte de texte
• Boîte de texte (TextBox)
TextBox zoneSaisie = new TextBox();
// Interdire la saisie de texte non numérique
zoneSaisie.addKeyboardListener(new KeyboardListenerAdapter() {
public void onKeyPress(Widget emetteur, char codeCar, int modifiers) {
if ((!Character.isDigit(codeCar)) && (codeCar != (char) KEY_TAB)
&& (codeCar != (char) KEY_BACKSPACE) && (codeCar != (char) KEY_DELETE)
&& (codeCar != (char) KEY_ENTER) && (codeCar != (char) KEY_HOME)
&& (codeCar != (char) KEY_END) && (codeCar != (char) KEY_LEFT)
&& (codeCar != (char) KEY_UP) && (codeCar != (char) KEY_RIGHT)
&& (codeCar != (char) KEY_DOWN)) {
// Annuler l'événement KeyPress
( (TextBox) emetteur ).cancelKey();
}
}
});
JUG Montréal 14 avril 2011
55. Interface Utilisateur – Liste déroulante
• Liste déroulante (ListBox)
// Créer une liste, et lui ajouter quelques items
ListBox listeChoix = new ListBox();
listeChoix.addItem("Pied-De-Vent");
listeChoix.addItem("Notre-Dame-des-Neiges");
listeChoix.addItem("Migneron");
listeChoix.addItem("Riopelle de l'Isle");
listeChoix.addItem("Bleu Bénédictin");
// Faire assez de place pour les 6 items
listeChoix.setVisibleItemCount(6);
// Ajouter un gestionnaire sur les événements de sélection
listeChoix.addChangeHandler(new ChangeHandler() {
public void onChange(ChangeEvent event) {
alert(listeChoix.getSelectedIndex().getValue());
}
});
JUG Montréal 14 avril 2011
56. Interface Utilisateur – Arbre
• Arbre (Tree) : une hiérarchie déployable de widgets
TreeItem tronc = new TreeItem("Racine");
tronc.addItem("item 0");
tronc.addItem("item 1");
tronc.addItem("item 2");
// Ajouter une case à cocher à l'arbre
TreeItem item = new TreeItem(new CheckBox("item 3"));
tronc.addItem(item);
Tree arbre = new Tree();
arbre.addItem(tronc);
JUG Montréal 14 avril 2011
57. Interface Utilisateur – Éditeur de textes
Éditeur de textes riche (RichTextArea)
// Crée la zone d'édition et sa barre de menu
RichTextArea editeur = new RichTextArea();
editeur.setSize("100%", "14em");
RichTextToolbar barreMenu =
new RichTextToolbar(editeur);
barreMenu.setWidth("100%");
// Ajoutez les composants à un panneau
Grid panneauGrille = new Grid(2, 1);
panneauGrille.setStyleName("editeur");
panneauGrille.setWidget(0, 0, barreMenu);
panneauGrille.setWidget(1, 0, editeur);
JUG Montréal 14 avril 2011
58. Support des CSS
Séparation du code et de la présentation
Code Java :
public ListWidget(String Item) {
...
setStyleName(“gwt-ListWidget”);
}
Fichier CSS :
.gwt-ListWidget {
background-color:black;
color:lime;
}
JUG Montréal 14 avril 2011
59. Support des CSS - conseils
Code Java : (usage de CSS primaire et dépendant)
MonPetitWidget monPW = new MonPetitWidget();
monPW.setStylePrimaryName("monPetitWidget");
monPW.addStyleDependentName("selected");
Fichier CSS :
.monpetitWidget {
background-color:black;
color:lime;
}
.monPetitWidget .monPetitWidget-selected {
color:red;
}
Permet de faire varier facilement l'apparence en fonction de l'état
Note : Ne pas utiliser les CSS pour la disposition
(ex. .monPetitWidget { position: absolute; } )
JUG Montréal 14 avril 2011
61. I18N
Le transcompilateur GWT utilise la liaison différée
(« Deferred Binding ») pour générer une version
différente de l'application Web pour chaque langue
Par exemple, puisque GWT supporte 5 navigateurs
différents, si votre application doit fonctionner en
3 langues, le transcompilateur de GWT produira
15 versions différentes de votre application au
moment de la compilation
À l'exécution, GWT choisira la bonne version de
l'application à montrer à l'utilisateur
JUG Montréal 14 avril 2011
62. I18N – mécanismes de localisation
“Constants” pour des chaînes constantes et des réglages
“Messages” pour les chaînes avec des arguments
“DateTimeFormat” pour les dates et l'heure
“NumberFormat” pour les nombres et les unités de mesure
Pas de processus dynamique (tout est statique et fait à la
compilation), sinon il faut développer son propre mécanisme
JUG Montréal 14 avril 2011
63. Gestion de l'historique du navigateur
La gestion de l'historique du navigateur s'occupe des
boutons « avancer » et « reculer » et des liens
Une API simple de gestion de l'historique basée sur
une pile de jetons
– Lorsque l'application démarre, la pile est vide
– Lorsque l'utilisateur clique sur quelque chose
• Vous pouvez ajouter des jetons sur la pile
History.newItem(“nouveauJeton”)
• Classe Hyperlink ajoute des jetons automatiquement
– Vous pouvez aussi réagir aux événements “History
events” en utilisant un HistoryListener
History.addHistoryListener(controle)
JUG Montréal 14 avril 2011
65. Ajax – Diagramme de collaboration
JUG Montréal Source : J.J. Garrett 2005 - http://www.adaptivepath.com/ideas/essays/archives/000385.php 14 avril 2011
66. Ajax – Diagramme de séquence
En mode synchrone, le fureteur est gelé en attendant
la réponse du serveur.
En mode asynchrone, l'exécution dans le fureteur sur le
poste client se poursuit sans attendre la réponse du
Serveur. La réponse sera traitée par une fonction
de retour (Callback) quand elle arrivera.
L'état de la requête est donné par l'attribut
readyState de l'objet XMLHttpRequest.
Source : J.J. Garrett 2005 - http://www.adaptivepath.com/ideas/essays/archives/000385.php
JUG Montréal 14 avril 2011
67. Communication avec le serveur & Ajax
RPC (« Remote Procedure Call ») ,appel de procédure à distance
RPC rend facile l'échange d'objets Java ou POJOS (sérialisés)
entre le code-client et le code-serveur
Fournit une procédure automatique de sérialisation des objets
Autres outils Ajax :
HTTPRequest
RequestBuilder
FormPanel
Support de :
XML
JSON (JavaScript Object Notation)
JUG Montréal 14 avril 2011
68. Compilation & déploiement serveur RPC
WEB-INF/
Eclipse classes/../client/
Données à
Échanger Model/
MesDonnee MesDonneesDO
DO Services/
MonService
MonServiceAsync
Interfaces client
Java
Compilateur classes/../server/
MonService
MonService Java
Async
MonServiceImpl
MonServiceImpl
(servlet)
(servlet)
Code Java
Serveur
(servlet)
MonService lib/
Impl
gwt-servlet.jar
gwt-servlet.jar
Configuration
web.xml Autres .jar
gwt-user.jar gwt-servlet.jar serveurs sans
restrictions
Configuration
web.xml
JUG Montréal 14 avril 2011
69. Client léger HTML vs client riche Ajax
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
70. Client léger HTML vs client riche Ajax
Client HTML
(fureteur)
Serveur
sans état avec état
(stateless) (statefull)
Pas d'état persistant
entre les transactions qui sont
considérées comme indépendantes
Client JavaScript
(fureteur) Serveur
avec état sans état
(statefull) (stateless)
Pas d'état persistant
entre les transactions qui sont
considérées comme indépendantes
JUG Montréal * Source : http://www.google.com 14 avril 2011
71. Appel de procédure à distance
GWT offre le très utile mécanisme d'appel de procédure à distance ou RPC
(Remote Procedure Call), comme moyen de communiquer avec les services
J
hébergés sur un serveur JEE. Client et serveur parlent alors le même langage,
i.e. le Java
JUG Montréal * Source : http://www.google.com 14 avril 2011
72. RPC (Remote Procedure Call)
Un objet Java MesDonneesDO à échanger
import com.google.gwt.user.client.rpc.IsSerializable;
public class MesDonneesDO implements IsSerializable {
//...
}
Une première interface définit le service
import com.google.gwt.user.client.rpc.RemoteService;
public interface MonService extends RemoteService {
MesDonneesDO getReponseMonService(String requete);
}
Une deuxième interface dite asynchrone spécifie getReponseMonservice( ) mais avec un paramètre
supplémentaire sous la forme d'une procédure de rappel (« Callback ») que le code-client utilisera pour
appeler le service.
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface MonServiceAsync {
public void getReponseMonService(String requete,
AsyncCallback maProcedureDeRappel);
}
JUG Montréal 14 avril 2011
73. RPC - Code-serveur
Classe à implémenter du côté serveur hérite de com.google.gwt.user.server.rpc.RemoteServiceServlet
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import qc.ets.web2.gwt.client.MesDonneesDO;
import qc.ets.web2.gwt.client.MonService;
public class MonServiceImpl extends RemoteServiceServlet implements MonService {
public MesDonneesDO getReponseMonService(String requete) {
if (requete.length() < 1) {
throw new IllegalArgumentException("Requete invalide.");
}
MesDonneesDO resultat = new MesDonneesDO();
resultat.setDonnees("...");
if ( isInvalide( resultat )) {
return null;
}
return resultat;
}
public boolean isInvalide(MesDonneesDO resultat) {
Return true; // à modifier
}
}
JUG Montréal 14 avril 2011
74. RPC - Code-client
Le client n'est pas encore connecté au service. Nous pouvons faire cela en ajoutant un récepteur
(Listener) à un élément de l'interface, ce qui peut être fait avec une classe interne.
public class MonClientRPC implements EntryPoint {
public void onModuleLoad() {
final Button bouton = new Button("Appel RPC");
final MonServiceAsync serviceProxy =
(MonServiceAsync)GWT.create(qc.ets.web2.gwt.client.MonService.class);
ServiceDefTarget pointService = (ServiceDefTarget) serviceProxy;
pointService.setServiceEntryPoint(GWT.getModuleBaseURL() + "/reponseService");
bouton.addClickListener(new ClickListener( ) {
public void onClick(Widget emetteur) {
AsyncCallback maProcedureDeRappel = new AsyncCallback() {
public void onSuccess(Object resultat) {
MesDonneesDO resultatDO = (MesDonneesDO) resultat;
System.out.println("*** SUCCES RPC ***n" + resultatDO.getDonnees());
}
public void onFailure(Throwable erreur) {
System.out.println("*** ERREUR RPC ***" + erreur.getMessage());
}
};
serviceProxy.getReponseMonService("Requete bidon", maProcedureDeRappel);
}});
RootPanel.get("emprise1").add(bouton);
}
}
JUG Montréal 14 avril 2011
75. Intégration facile aux APIs Google
JUG Montréal * Source : http://www.google.com 14 avril 2011
76. Intégration facile aux APIs Google
Google a un riche écosystème d'APIs en source libre
AppEngine : déploiement facile d'applications GWT
dans le nuage
Androïd : réalisation d'applications mobiles avec GWT
OpenSocial : réalisation facile de gadgets avec GWT
Google Maps APIs : services de cartes et géolocation
Google Ajax Search APIs : le moteur Google Search
Google Gears API : BD locale et navigation hors ligne
Google Language API : services de traduction
...
JUG Montréal 14 avril 2011
77. GWT – Atelier de Gadgets!
Compiler avec GWT pour générer le code JS du gadget
Déploiement facile sur un serveur Web externe
Intégrer facilement le gadget dans un conteneur OpenSocial
c
JUG Montréal 14 avril 2011
78. GWT – Applications mobiles multiplateformes
JUG Montréal * Source : http://www.google.com 14 avril 2011
79. GWT – Applications mobiles multiplateformes
Développer pour chaque plateforme une application native ou
développer une application multiplateforme?
Si l'application n'a pas besoin d'accéder à des périphériques
spécifiques, de performances « temps réel » ou le dessin 3D, il est
préférable de créer une application multiplateforme.
Dans ce contexte, le fureteur est la plateforme et les technologies
Ajax du fureteur, comme JavaScript, HTML/HTML5 et CSS sont
privilégiées
La boîte à outils Ajax GWT facilite la création d'un client
multiplateforme sur la base d’une application web pour mobile et
d'ajouts spécifiques via les bibliothèques PhoneGap et GwtMobile
À long terme, extension de la norme HTML5 et l’accroissement
des performances des engins JavaScript
JUG Montréal 14 avril 2011
80. IUG – Patrons de conception
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
81. IUG – Patron de conception - Composite
Patron Composite (ou Object Composite)
* Source : http://www.google.com
* Source : http://fr.wikipedia.org/wiki/Objet_composite
Facilite la création de Widgets
S'utilise chaque fois qu'on crée un nouveau widget à partir de widgets existants
Offre un meilleur contrôle sur l'API exposé
Généralement préférable à l'utilisation de l'héritage
JUG Montréal 14 avril 2011
82. IUG – Patron de conception - Composite
class MonPremierComposite extends Composite {
private VerticalPanel conteneur = new VerticalPanel();
private Label monTitre = new Label();
private TextBox maZoneTexte = new TextBox();
// Constructeur
public MonPremierComposite() {
conteneur.add(monTitre);
conteneur.add(maZoneTexte);
initWidget(conteneur);
}
}
JUG Montréal 14 avril 2011
83. IUG – Patron de conception - Commande
Le patron de conception Commande (Command Pattern) encapsule dans un objet la notion d'invocation d'une
action ou commande souvent à être invoquée à un moment ultérieur.
Le patron comporte trois parties : l'invocateur, la commande et le récepteur.
Le patron « Commande » permet de découpler le code qui déclenche l'action (le code d'invocation) et le code
de l'action elle-même.
Par exemple, les différents items d'un menu sont associés chacun à une Commande et à ses arguments.
Ainsi, l'item de menu ignore les détails de l'action effectuée par la Commande. Aussi utilisé pour implémenter
le « undo ».
Invocateur << Interface >>
Commande
+ événement1(...)
+ événement2(...) + executer()
Récepteur CommandeImpl
+ action1(...) + executer()
+ action2(...)
JUG Montréal 14 avril 2011
84. GUI – Patron de conception - Observateur
Le Modèle utilise le patron de conception Observateur (Observer Pattern) pour informer la
Vue/Contrôleur du changement des données et bien découpler la Vue du Modèle*
Ainsi, différents éléments du Modèle servent de sujets ou données observables (Subjects) à
un ensemble d'observateurs (Observers) contenus dans les Vues/Contrôleurs qui sont en
quelque sorte abonnés aux modifications des données du modèle.
Programmation événementielle qui favorise un découplage des composants
Compromis entre un petit nombre d'événements généraux du genre « quelque chose » a
changé dans le modèle (granularité grossière) et un grand nombre de petits événements
reliés à des éléments très précis du modèle (granularité fine).
* Patron observateur relie MV et VC dans le patron MVC
JUG Montréal Source figure : R. Dewsbury 2008 – Chap.2, p.96 14 avril 2011
85. GUI – Patron de conception - MVC
Patron MVC
Client MVC
Vue: Présentation découplée
Affiche les Échages de
événements données
informations et
achemine les
actions de l'usager
V C
mise à jour
no
not
es
né
tiifii
acc
Contrôleur:
ccè do
on
de ur
cat
ès onn
atio
sd
nt jo
en nnée
me e à
on
Établit les liens
nl é s
n
ge is
ect s
et
an m
entre le Modèle et
ure
ue
M la Vue
au
aux
ch
x
Reçoit les
événements de la
Modèle:
Vue et gère les
Données de l'application actions de l'usager
(POJOs) Notifie les
changements du modèle
par des événements
transmis aux vues
abonnées
JUG Montréal 14 avril 2011
86. Bus d'événements
Bus d'événements (Event Bus) : peut être vu comme
un système téléphonique qui relie les composants de
l'application
Les composants émettent et reçoivent des
événements (events).
Les composants peuvent réagir différemment selon le
type d'événement reçus
JUG Montréal 14 avril 2011
87. Contrôleur de l'application
Le contrôleur de l'application (Application Controller)
est en quelque sorte le chef d'orchestre de
l'application.
Le contrôleur de l'application contient la logique de
l'application
JUG Montréal 14 avril 2011
88. GUI - Patron de conception - MVP
Patron MVP : Modèle-Vue-Présentateur (Model-View-
Presenter) Présentateur:
Communique (reçoit /
émet) avec le reste de
Modèle:
Données du
Modèle l'application via le bus
d'événements.
Bus composant
Reçoit des événements
É
(POJOs).
de la Vue S
V Communique avec le E
É serveur via des services R
N V
E Présentateur
M I
E C
N E
T Vue:
S Affiche les
S
informations et
achemine les Vue
actions
(événements)
de l'usager
JUG Montréal 14 avril 2011
89. GUI - Patron de conception - MVP
Modèle-Vue-Présentation (Model-View-Presenter)
Inventé par Martin Fowler et promu par Google
Meilleur « découplage » / séparation
Plus facile de répartir le code entre développeurs
Plus facile à tester en remplaçant la vue par une vue
factice (MockView)
Le modèle contient les données à afficher
La vue correspond à une interface d'affichage. Les
données envoyées à la vue sont des primitives.
Certains composants sont reliés au bus d'événements
alors que d'autres sont reliés à la couche de services
JUG Montréal 14 avril 2011
90. GUI - Patron de conception - MVP
Le présentateur travaille avec des interfaces pas des
implémentations (HasClickHandlers, HasValue, etc.)
Le présentateur contient la logique du composant d'IU.
Il envoie les données mise-à-jour à la vue et reçoit les
valeurs modifiées par la vue.
Le présentateur reçoit également les événements
envoyés par les autres composants de l'application et
il émet ses propres événements via le bus
d'événements.
Le présentateur reçoit des données du Modèle
Le présenteur et la vue associée sont couplés via une
Interface d'Affichage
JUG Montréal 14 avril 2011
91. Architecture Application MVP
BUS D'ÉVÉNEMENTS
Contrôleur de l'Application
Modèle Modèle Modèle
Présentateur Présentateur Présentateur
Vue Vue Vue
Service Service
Serveur
JUG Montréal 14 avril 2011
92. Démo – Bâtir des applications GWT
GWT
en Action
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
93. Google Wave – Un exemple qui a fait des vagues!
Source : http://googleblog.blogspot.com/2009/05/went-walkabout-brought-back-google-wave.html
JUG Montréal 14 avril 2011
94. OpenSyllabus – Un exemple Québécois!
OpenSyllabus : un éditeur structuré de plan de cours
http://confluence.sakaiproject.org/confluence/display/OSYL/OpenSyllabus+Home
JUG Montréal 14 avril 2011
95. Planificateur d'horaire – GWT à l'ETS!
http://planhoraire.aeets.com/planhoraire.html
JUG Montréal 14 avril 2011
96. Créer un squelette d'application GWT
GWT crée automatiquement un code-client
rudimentaire
Vous pouvez ensuite mettre de la chair sur ce
squelette dans le but de créer une application Web
plus sophistiquée
GWT
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
97. Créer un squelette d'application GWT
public class Bonjour implements EntryPoint {
public void onModuleLoad() {
Button bouton = new Button("Cliquez-moi!",
new ClickHandler() {
public void onClick(ClickEvent event) {
Window.alert("Bouton cliqué!");
}
});
RootPanel.get().add(bouton);
}
}
JUG Montréal 14 avril 2011
98. Enrichir une page web
GWT permet d'ajouter des composants graphiques
interactifs dans une page Web
Un composant GWT peut être intégré dans n'importe
quelle page HTML, ainsi l'application continue à
ressembler à une page Web
Tout fichier HTML incluant un certain jeu de balises
peut servir de support à une application GWT
GWT ne cherche pas exclusivement à ressembler à
une application bureautique en exécution locale
Le résultat est juste une meilleure application Web
Exemple : application d'ouverture de session (login)
JUG Montréal 14 avril 2011
99. Créer des applications Web similaires à des
applications bureautiques en exécution locale
Ouverture de plusieurs fenêtres à la fois dans le
navigateur
Déplacement des fenêtres dans le navigateur,
redimensionnement et défilement des fenêtres
Glisser et déposer des contenus
Applications Web se comportant « comme des
applications bureautiques locales »
JUG Montréal 14 avril 2011
100. GWT – Avantages pour les utilisateurs
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
101. GWT – Avantages pour les utilisateurs
Réponses rapides aux actions de l'utilisateur
La vitesse est vitale, spécialement au démarrage
Ne requiert pas de plugiciel, Flash, .Net, ni de JVM
Pas de long téléchargement, ni d'installation
Compatible avec tous les fureteurs
Donne la préférence aux composants natifs de l'IU
L'utilisateur conserve le contrôle du navigateur Web en
tout temps
Gestion de l'historique de navigation
Produit des applications Web riches, rapides et légères
JUG Montréal 14 avril 2011
102. GWT – Avantages pour les développeurs
aniaque
GWT
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
103. GWT – Avantages pour les développeurs
Un unique langage, le “Java”
Bien que le code-serveur peut être en n'importe quel langage
Gère les différences entre les fureteurs Web
Bibliothèque OO de composants IUG
Semblable à SWING ou AWT
Encourage les bonnes pratiques du génie logiciel en s'appuyant
sur des outils Java matures et performants
Eclipse, NetBeans, IntelliJ
Communications Ajax faciles via RPC
S'intègre aux technologies Web standards
Réduit la charge sur le serveur et le réseau
Le code-client est beaucoup plus léger qu'un Applet Java
JUG Montréal 14 avril 2011
104. Qui peut le mieux profiter de GWT ?
J'
GWT
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
105. Qui peut le mieux profiter de GWT ?
Designers Web
– GWT utilise les feuilles de style CSS
– Doivent apprendre Java
Développeurs d'applications Web
– Une application GWT s'exécute sur le client plutôt que d'être
contrôlée entièrement par le serveur
– Doivent maîtriser les technologies du client riche et de présentation
Développeurs Ajax (gourous JavaScript)
– GWT intègre facilement le code JavaScript grâce à JSNI
– Doivent laisser tomber certaines habitudes du codage JS
Développeurs d'applications Java (Swing)
– Réaliser des Web-app. avec des outils et un environnement familier
– Doivent apprendre CSS & les restrictions particulières des Web-app.
JUG Montréal 14 avril 2011
107. GWT vs autres solutions Web riche
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
108. GWT vs autres solutions Web riche
Outils purs JavaScript (jQuery, Scriptaculous, Prototype, YUI, Dojo, etc.)
Facilitent beaucoup la programmation JavaScript mais ça reste du JavaScript!
JavaServer Faces - Norme JEE, orienté serveur, plutôt complexe
JavaFX - Trop peu, trop tard!, exige JVM
Java Applet – Passé de mode et lourd passé, exige JVM
ZK - Rapide et facile à programmer, orienté serveur, licence GPL
Adobe Flash, Flex, AIR (Adobe Integrated Runtime) et OpenLazslo
orienté serveur, +/- propriétaire, exige plugiciel Flash, langage à scripts
Micro$oft Silverlight - propriétaire & basé Windows
Windows Volta, une copie GWT pour .NET, annoncé 2007 puis disparu...
Ruby – Innovateur (RAILS), toujours à base de pages et orienté serveur..
JUG Montréal 14 avril 2011
109. GWT - Avantages & inconvénients
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
110. GWT - Avantages
Bon pour enrichir des applications Web avec Ajax ou créer
des applications Web riches avec des IUs complexes
Un seul langage: JAVA + riche écosystème Java
Développement et mise au point rapide dans des EDIs
favorisant une bonne productivité et qualité du code
(Eclipse, UiBinder, GWT Designer...)
Bonne bibliothèque de composants (~ Swing)
Très bon support Ajax
Performant & économe en ressources réseau & serveur
Code source libre, licence Apache 2, bien documenté
Supporté par GOOGLE... et l'écosystème Google
GWT ne va pas résoudre « magiquement » tous les
problèmes avec Ajax ou le Web 2.0
JUG Montréal 14 avril 2011
111. GWT - Inconvénients
JS
Ajax
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011
112. GWT - Inconvénients
Nécessite que le fureteur exécute JavaScript
Connaissance de la programmation Java
Séparation nette entre client et serveur
Les composants (widgets) sont de sources et de
qualités inégales
Dépend des performances du transcompilateur
Lenteur de JavaScript
Quelques problèmes de compatibilité entre fureteurs,
surtout au niveau des CSS
Certains problèmes demandent une expertise JS
L'aspect sécurité est à surveiller
JUG Montréal 14 avril 2011
113. Ressources - Livres
GWT in Action: Easy Ajax with the Google Web
Toolkit
par Robert Hanson, Adam Tacy
600 pages
Manning Publications
(5 juin, 2007)
www.manning.com/hanson/
Google Web Toolkit Applications
par Ryan Dewsbury
608 pages
Prentice Hall
(15 décembre, 2007)
www.gwtapps.com
JUG Montréal 14 avril 2011
114. Ressources - Livres
Google Web Toolkit Solutions : More Cool &
Useful Stuff
par David Geary, Rob Gordon
408 pages
Prentice Hall
(17 novembre, 2007)
www.coolandusefulgwt.com
GWT in Practice
par Robert T. Cooper, Charlie E. Collins
358 pages
Manning Publications
(12 mai, 2008)
www.manning.com/cooper/
JUG Montréal 14 avril 2011
115. Ressources - Livres
Programmation GWT 2 : Développer des
applications RIA et Ajax avec Google Web Toolkit
par Sami Jaber
484 pages
Eyrolles
(5 janvier, 2010)
www.programmationgwt2.com
GWT - Créer des applications web interactives
avec Google Web Toolkit (versions 1.7 et 2.0)
par Olivier Gérardin
205 pages
Dunod
(4 novembre, 2009)
http://code.google.com/p/livre-gwt
JUG Montréal 14 avril 2011
116. Ressources - Outils
Sites généralistes
http://code.google.com/webtoolkit
http://code.google.com/webtoolkit/overview.html
Groupe de discussions (25 000 membres)
http://groups.google.com/group/google-web-toolkit
Sites de nouvelles
http://www.ongwt.com/
Socle d'application MVP - GWTP
http://code.google.com/p/gwt-platform/
JUG Montréal 14 avril 2011
117. Questions
?
JUG Montréal * Source Clipart : http://www.clipart.com 14 avril 2011