I. Introduction▲
I-A. Remerciements▲
Merci à Ricky81 pour sa relecture attentive.
I-B. Présentation▲
Au cours de cet article, nous verrons comment utiliser et intégrer le framework GWT avec Eclipse.
La présentation se fera par la réalisation d'une application permettant la consultation et le filtre d'une liste de contacts.
Les exemples de cet article se feront sous Windows, mais devraient s'adapter à un autre environnement sans trop de difficultés.
II. Mise en place de l'environnement▲
II-A. Environnement de développement▲
Pour commencer, il faut créer le répertoire de base du projet.
mkdir demoGWT
On se place dans ce répertoire pour travailler.
cd demoGWT
Création des fichiers projet Eclipse
projectCreator -eclipse demoGWT
Created directory D:\gwt-windows-1.1.10\demoGWT\test
Created file D:\gwt-windows-1.1.10\demoGWT\.project
Created file D:\gwt-windows-1.1.10\demoGWT\.classpath
Création de l'arborescence applicative
applicationCreator -eclipse demoGWT com.developpez.exemple.gwt.client.MonApplication
Created directory D:\gwt-windows-1.1.10\demoGWT\src
Created directory D:\gwt-windows-1.1.10\src\demoGWT\com\developpez\exemple\gwt
Created directory D:\gwt-windows-1.1.10\src\demoGWT\src\com\developpez\exemple\gwt\client
Created directory D:\gwt-windows-1.1.10\src\demoGWT\src\com\developpez\exemple\gwt\public
Created file D:\gwt-windows-1.1.10\src\demoGWT\com\developpez\exemple\gwt\MonApplication.gwt.xml
Created file D:\gwt-windows-1.1.10\src\demoGWT\com\developpez\exemple\gwt\public\MonApplication.html
Created file D:\gwt-windows-1.1.10\src\demoGWT\com\developpez\exemple\gwt\client\MonApplication.java
Created file D:\gwt-windows-1.1.10\demoGWT\MonApplication.launch
Created file D:\gwt-windows-1.1.10\demoGWT\MonApplication-shell.cmd
Created file D:\gwt-windows-1.1.10\demoGWT\MonApplication-compile.cmd
Maintenant que la structure applicative est créée, on pourrait simplement utiliser un éditeur de texte.
Mais utilisons Eclipse, pourquoi se priver de fonctionnalités avancées?
Pour cela, il suffit d'ouvrir Eclipse.
Dans le menu file, choisir import
Choisir Existing Projects into workspace
Cibler le répertoire demoGWT et importer.
On obtient
II-B. Environnement de production▲
En production, on aura évidemment besoin d'un serveur applicatif ou d conteneur web tel Tomcat.
Pour l'installation et le fonctionnement de Tomcat, je vous laisse consulter ce tutoriel.
Ensuite, il vous suffit de déployer votre application comme n'importe quelle autre application Java.
III. Bonjour le monde▲
Comme tout bon tutoriel, nous allons commencer par un « Hello World ! ».
Pour cela, lancer le script MonApplication-shell.cmd. Un navigateur va se lancer.
Il vous permettra de voir le rendu de votre application en cours de développement.
La page que vous voyez apparaître devrait ressembler à celle-ci.
Félicitation, vous venez de réussir votre premier « HelloWorld » avec le framework GWT.
IV. On complique un peu▲
IV-A. Un peu de nettoyage▲
Le ménage commence par la page HTML qui sert de support à notre application.
On supprime le surplus du HelloWorld pour ne conserver que le titre de la page et les balises propres à GWT.
On obtient alors la page suivante :
<head>
<!-- -->
<!-- Ici on définit le titre de notre fenêtre -->
<!-- -->
<title>
MonApplication GWT</title>
<!-- -->
<!-- La balise suivante permet de faire le -->
<!-- lien entre la page html et le code GWT -->
<!-- -->
<meta
name
=
'gwt:module'
content
=
'com.developpez.exemple.gwt.MonApplication'
>
</head>
<body>
<!-- -->
<!-- L'inclusion de gwt.js est obligatoire. -->
<!-- Elle placer ici pour des raisons de -->
<!-- Performances. -->
<!-- -->
<script
langage
=
"javascript"
src
=
"gwt.js"
></script>
<!-- La balise suivante est optionnelle, elle gère l'historique des pages -->
<iframe
id
=
"__gwt_historyFrame"
style
=
"width:0;height:0;border:0"
></iframe>
</body>
</html>
IV-B. Entrypoint▲
Lorsque l'on développe une application AWT/SWING, on utilise une classe avec une méthode main pour lancer notre application.
Étant donné que les classes Java que nous allons écrire seront converties en code Javascript, l'utilisation d'une méthode main est impossible.
Dans notre cas, notre classe de lancement sera la page html de notre application et notre méthode main la balise meta.
<meta name
=
'gwt:module'
content
=
'com.developpez.exemple.gwt.MonApplication'
>
L'attribut content de la balise permet de faire le lien vers le fichier de configuration de notre module GWT.
<module>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits
name
=
'com.google.gwt.user.User'
/>
<!-- Specify the app entry point class. -->
<entry-point
class
=
'com.developpez.exemple.gwt.client.MonApplication'
/>
</module>
La balise entry-point permet de spécifier quelle sera la classe principale de notre application.
Cette classe doit implémenter l'interface Entrypoint.
Il est intéressant aussi d'implémenter l'interface WindowResizeListener.
Cette interface permet de recevoir les informations liées à la taille de la fenêtre du navigateur et donc de redimensionner notre application proportionnellement à celle-ci.
Le code de la classe devrait ressembler à ça:
package
com.developpez.exemple.gwt.client;
import
com.google.gwt.core.client.EntryPoint;
import
com.google.gwt.user.client.Window;
import
com.google.gwt.user.client.WindowResizeListener;
/**
* Entry point classes define
<
code
>
onModuleLoad()
<
/code
>
.
*/
public
class
MonApplication implements
EntryPoint , WindowResizeListener {
/**
* This is the entry point method.
*/
public
void
onModuleLoad
(
) {
// Hook the window resize event, so that we can adjust the UI.
Window.addWindowResizeListener
(
this
);
// Get rid of scrollbars, and clear out the window's built-in margin,
// because we want to take advantage of the entire client area.
Window.enableScrolling
(
false
);
Window.setMargin
(
"10px"
);
}
public
void
onWindowResized
(
int
width, int
height) {
// TODO Auto-generated method stub
}
}
On obtient donc une application GWT pleinement fonctionnelle, mais qui ne fait rien.
IV-C. Création des éléments graphiques▲
Les classes des éléments graphiques de GWT reprennent les noms et comportements que l'on a l'habitude de manipuler quand on réalise une application AWT/SWING. Avec GWT, nous manipulerons donc des Panels et autres Label et TextBox.
IV-C-1. Les Panels▲
Les panels se déclinent en plusieurs classes qui ont chacune un comportement spécifique.
Dans cette mise en application, nous utiliserons les panels suivants :
- DockPanel
- HorizontalPanel
- VerticalPanel
Le DockPanel servira de base d'accueil pour notre application. Il contiendra dans sa partie nord un VerticalPanel et dans sa partie Centre un HorizontalPanel.
Le verticalPanel contiendra les champs de recherche et le VerticalPanel présentera les résultats.
On commence par ajouter le DockPanel à l'application. Ce qui nous donne pour la classe MonApplication.java le code suivant :
package
com.developpez.exemple.gwt.client;
import
com.google.gwt.core.client.EntryPoint;
import
com.google.gwt.user.client.Window;
import
com.google.gwt.user.client.WindowResizeListener;
import
com.google.gwt.user.client.ui.DockPanel;
import
com.google.gwt.user.client.ui.RootPanel;
/**
* Entry point classes define
<
code
>
onModuleLoad()
<
/code
>
.
*/
public
class
MonApplication implements
EntryPoint , WindowResizeListener {
private
DockPanel outer =
new
DockPanel
(
);
/**
* This is the entry point method.
*/
public
void
onModuleLoad
(
) {
outer.setWidth
(
"100%"
);
outer.setHeight
(
"100%"
);
// Hook the window resize event, so that we can adjust the UI.
Window.addWindowResizeListener
(
this
);
// Get rid of scrollbars, and clear out the window's built-in margin,
// because we want to take advantage of the entire client area.
Window.enableScrolling
(
false
);
Window.setMargin
(
"10px"
);
RootPanel.get
(
).add
(
outer);
}
public
void
onWindowResized
(
int
width, int
height) {
// TODO Auto-generated method stub
}
}
Nous allons créer deux panels, RechechePanel et ContactsPanel qui étendent respectivement HorizontalPanel et VerticalPanel.
Le fait de ne pas utiliser directement les panels génériques nous permet d'alléger la classe MonApplication et surtout nous permettra d'avoir un code lisible.
Pour la classe ContactsPanel
et pour la classe RecherchePanel
Il ne nous reste plus qu'à les insérer dans le DockPanel.
package
com.developpez.exemple.gwt.client;
import
com.developpez.exemple.gwt.client.panel.ContactsPanel;
import
com.developpez.exemple.gwt.client.panel.RecherchePanel;
import
com.google.gwt.core.client.EntryPoint;
import
com.google.gwt.user.client.Window;
import
com.google.gwt.user.client.WindowResizeListener;
import
com.google.gwt.user.client.ui.DockPanel;
import
com.google.gwt.user.client.ui.HorizontalPanel;
import
com.google.gwt.user.client.ui.VerticalPanel;
import
com.google.gwt.user.client.ui.RootPanel;
/**
* Entry point classes define
<
code
>
onModuleLoad()
<
/code
>
.
*/
public
class
MonApplication implements
EntryPoint , WindowResizeListener {
private
DockPanel outer =
new
DockPanel
(
);
/**
* This is the entry point method.
*/
public
void
onModuleLoad
(
) {
HorizontalPanel recherchePanel =
new
RecherchePanel
(
);
VerticalPanel contactsPanel =
new
ContactsPanel
(
);
outer.setWidth
(
"100%"
);
outer.setHeight
(
"100%"
);
// Hook the window resize event, so that we can adjust the UI.
Window.addWindowResizeListener
(
this
);
// Get rid of scrollbars, and clear out the window's built-in margin,
// because we want to take advantage of the entire client area.
Window.enableScrolling
(
false
);
Window.setMargin
(
"10px"
);
outer.add
(
recherchePanel, DockPanel.NORTH);
outer.add
(
contactsPanel, DockPanel.CENTER);
RootPanel.get
(
).add
(
outer);
}
public
void
onWindowResized
(
int
width, int
height) {
// TODO Auto-generated method stub
}
}
IV-C-2. Les éléments graphiques▲
Maintenant que la structure d'accueil de notre application est prête, nous allons pouvoir mettre un peu de contenu.
En plus des composants graphiques de base, nous utiliserons aussi la classe Composite.
La classe Composite permet d'envelopper un ou plusieurs autres éléments graphiques. Ce groupe de composant agit alors comme un seul et même élément.
Nous allons commencer par créer une classe Texte qui héritera de Composite. Cette classe nous permettra de gérer les zones de saisie utilisateur.
Elle gèrera le libellé et la zone de saisie. On utilisera la classe Label pour le libellé et la classe TextBox pour la zone de saisie.
package
com.developpez.exemple.gwt.client.panel;
import
com.google.gwt.user.client.ui.Composite;
import
com.google.gwt.user.client.ui.HorizontalPanel;
import
com.google.gwt.user.client.ui.Label;
import
com.google.gwt.user.client.ui.TextBox;
public
class
Texte extends
Composite {
private
Label label =
new
Label
(
);
private
TextBox textBox =
new
TextBox
(
);
public
Texte
(
) {
HorizontalPanel panel =
new
HorizontalPanel
(
);
panel.add
(
label);
panel.add
(
textBox);
initWidget
(
panel);
}
public
void
setLabel
(
String texte){
label.setText
(
texte+
" : "
);
}
public
void
setTexte
(
String texte){
textBox.setText
(
texte);
}
public
String getTexte
(
){
return
textBox.getText
(
);
}
}
Ensuite, il suffit d'ajouter ce composant à notre RecherchePanel, pour avoir nos zones de filtre.
package
com.developpez.exemple.gwt.client.panel;
import
com.google.gwt.user.client.ui.Button;
import
com.google.gwt.user.client.ui.HorizontalPanel;
public
class
RecherchePanel extends
HorizontalPanel {
public
RecherchePanel
(
){
this
.setTitle
(
"Recherche"
);
this
.setWidth
(
"100%"
);
Texte tb =
new
Texte
(
);
tb.setLabel
(
"Nom"
);
add
(
tb);
Texte tb2 =
new
Texte
(
);
tb2.setLabel
(
"Prénom"
);
add
(
tb2);
}
}
Avant de compléter notre application, nous allons créer une classe utilitaire Contact.
Ce sera la représentation objet des différentes personnes de notre application.
Afin d'avoir quelques éléments graphiques pour la démonstration, on rajoute une méthode getAllContacts() sur la classe.
Cette méthode va nous renvoyer un tableau de contacts à afficher, le temps que l'on implémente le service d'accès à une base de données.
À terme cette méthode disparaîtra.
Les différents contacts connus seront affichés sous forme de tableau.
Nous utiliserons pour cela la classe FlexTable. Le contenu d'un tableau se positionne par ses coordonnées.
Nous utiliserons la première ligne pour afficher les entêtes de tableau.
package
com.developpez.exemple.gwt.client.panel;
import
com.developpez.exemple.gwt.client.util.Contact;
import
com.google.gwt.user.client.ui.FlexTable;
import
com.google.gwt.user.client.ui.VerticalPanel;
public
class
ContactsPanel extends
VerticalPanel {
private
FlexTable t =
new
FlexTable
(
);
public
ContactsPanel
(
) {
t.setTitle
(
"Contacts"
);
t.setText
(
0
, 0
,"Nom"
);
t.setText
(
0
, 1
,"Prénom"
);
t.setText
(
0
, 2
,"Email"
);
t.setText
(
0
, 3
,"Tel"
);
t.setWidth
(
"100%"
);
t.setCellSpacing
(
2
);
for
(
int
i =
0
; i <
Contact.getAllContacts
(
).length; ++
i)
addContact
(
Contact.getAllContacts
(
)[i],i+
1
);
this
.add
(
t);
this
.setWidth
(
"100%"
);
}
private
void
addContact
(
Contact contact,int
i) {
t.setText
(
i, 0
,contact.getNom
(
));
t.setText
(
i, 1
,contact.getPrenom
(
));
t.setText
(
i, 2
,contact.getEmail
(
));
t.setText
(
i, 3
,contact.getTel
(
));
}
}
Une fois compilée, notre application donne ça.
IV-D. Utilisation des styles css▲
Maintenant que l'on a tous nos éléments, on va leur donner un aspect un peu plus convivial.
Pour cela, on va utiliser un fichier css.
On ajoute donc un fichier MonApplication.css au répertoire public de notre arborescence.
Afin que ces styles soient disponibles dans les classes GWT, il faut éditer le fichier MonApplication.gwt.xml, et déclarer le fichier css dans notre module.
Pour cela il suffit d'ajouter la ligne suivante dans la déclaration du module.
<stylesheet
src
=
'MonApplication.css'
/>
Les différentes classes graphiques du framework GWT héritent toutes de la classe UIObject.
Cette classe nous donne la méthode setStyleName sur tous nos composants et nous permet donc d'assigner un style précis à chacun de nos objets.
Par exemple, pour changer le style du RecherchePanel, il nous suffit d'ajouter le code suivant à son constructeur pour en modifier l'apparence.
this
.setStyleName
(
"gwt-RecherchePanel"
);
Bien évidemment le style gwt-RecherchePanel a été défini dans le fichier css.
Par convention, les noms de style sont composés du nom du module tiret l'élément graphique auquel il s'applique.
En appliquant nos styles à nos différents éléments, on obtient ça.
Mais bien sûr, nous n'avons encore aucun composant actif dans notre page.
V. Activation du filtre▲
Nous allons commencer à mettre un peu d'intelligence dans notre application. Pour cela, nous allons écouter les événements sur les zones de saisie et modifier le contenu du tableau en conséquence.
On va commencer par se donner des accesseurs à nos Panels en leur appliquant le pattern Singleton. Puis on va rajouter les méthodes getNom et getPrenom sur le RecherchePanel et la méthode filtre sur le contactsPanel.
Les méthodes getNom et getPrenom retourneront les valeurs saisies tandis que filtre modifiera le contenu du tableau de résultats. Ensuite, on va écouter les événements clavier qui surviennent dans nos zones de saisie en ajoutant le code suivant à notre classe Texte.
textBox.addKeyboardListener
(
new
KeyboardListener
(
) {
public
void
onKeyDown
(
Widget sender, char
keyCode, int
modifiers) {}
public
void
onKeyPress
(
Widget sender, char
keyCode, int
modifiers) {}
public
void
onKeyUp
(
Widget sender, char
keyCode, int
modifiers) {
ContactsPanel.instance.filtre
(
);
}
}
);
On remplit la méthode filtre.
public
void
filtre
(
){
String nom =
RecherchePanel.instance.getNom
(
);
String prenom =
RecherchePanel.instance.getPrenom
(
);
for
(
int
i =
t.getRowCount
(
)-
1
; i >
0
; i--
) {
t.removeRow
(
1
);
}
int
next =
1
;
for
(
int
i =
0
; i <
Contact.getAllContacts
(
).length; ++
i){
Contact contact =
Contact.getAllContacts
(
)[i];
if
(
contact.getNom
(
).toUpperCase
(
).startsWith
(
nom.toUpperCase
(
))
&&
contact.getPrenom
(
).toUpperCase
(
).startsWith
(
prenom.toUpperCase
(
))) {
addContact
(
contact,next);
next++
;
}
}
}
Une fois nos classes modifiées, on obtient ça.
VI. Dialogue avec le serveur▲
L'application semble fonctionnelle, mais la liste des contacts reste encore contenue dans la classe Contact, ce qui est peu satisfaisant.
Nous allons donc dans un premier temps créer un package server qui recevra les classes distantes et supprimer la méthode static getAllContact de la classe Contact.
VI-A. Mise en place d'un service▲
Le framework GWT dispose de sa propre solution de communication entre le client et le serveur, basée sur le principe d'appel de procédure distante (RCP).
Le serveur et le client dialogue dialoguent en Asynchrone (vous savez le premier A de AJAX ).
Il faut donc deux flux de communication, le premier direct vers le serveur pour émettre les requêtes, le second asynchrone pour recevoir les réponses du serveur.
Le flux ascendant est modélisé par une interface qui doit étendre l'interface RemoteService.
On définit dessus les différentes méthodes que l'on souhaite obtenir du serveur.
On va donc créer une interface ContactService.
Afin que le client puisse recevoir la réponse du serveur, on va créer une seconde interface ContactServiceAsync.
Cette interface doit répondre à plusieurs critères :
- le nom de l'interface doit être le même que celui pour le flux ascendant avec à la fin « Async » ;
- toutes ses méthodes sont de type void ;
- le nombre et le nom de ses méthodes sont identiques à ceux pour le flux ascendant ;
- chacune de ses méthodes doit prendre les mêmes paramètres que pour le flux montant plus un paramètre supplémentaire de la classe AsyncCallback.
C'est au travers de l'objet AsyncCallback que le serveur retournera sa réponse au client.
Maintenant que nous avons nos flux de communication avec le serveur, il nous faut ensuite créer une servlet sur le serveur capable de recevoir notre demande et d'y répondre.
Pour cela dans le package server, on va créer une classe ContactServiceImpl qui étendra RemoteServiceServlet et implémentera notre interface ContactService.
Hériter de la classe RemoteServiceServlet permet de faire abstraction de l'élaboration de l'objet AsyncCallback.
Le mécanisme RCP fonctionne comme un miroir, les méthodes appelées côté client seront exécutées côté serveur sur notre servlet.
C'est donc dans le corps des méthodes issues de l'implémentation de notre interface que l'on placera le code que l'on souhaite exécuter sur le serveur.
Notre classe servlet elle aussi doit répondre à plusieurs critères :
- le nom de la servlet doit être le même que celui pour le flux ascendant avec à la fin « Impl » ;
- la servlet doit implémenter RemoteServiceServlet ;
- la servlet doit implémenter l'interface du service ascendant.
package
com.developpez.exemple.gwt.server;
import
com.developpez.exemple.gwt.client.ContactService;
import
com.developpez.exemple.gwt.client.util.Contact;
import
com.google.gwt.user.server.rpc.RemoteServiceServlet;
public
class
ContactServiceImpl extends
RemoteServiceServlet implements
ContactService {
public
Contact[] getAllContact
(
) {
return
ContactData.getAllContacts
(
);
}
}
La classe ContactData est une classe utilitaire chargée de fournir la liste des contacts.
La méthode d'obtention des contacts importe peu, jdbc, Hibernate, fichier XML, LDAP, libre à vous d'utiliser celle qu'il vous plait.
Dernière action pour finaliser la création de notre service, la déclaration dans le fichier MonApplication.gwt.xml.
Pour cela, il suffit d'ajouter la ligne suivante à la déclaration du module.
<
servlet path=
"/contactService"
class=
"com.developpez.exemple.gwt.server.ContactServiceImpl"
/>
VI-B. Exploitation du service▲
Maintenant que le service est créé, nous allons pouvoir l'utiliser. On va l'appeler directement dans notre classe ContactsPanel.
On rajoute une méthode getAllContacts sur notre classe, qui après quelques modifications ressemble à ça :
package
com.developpez.exemple.gwt.client.panel;
import
com.developpez.exemple.gwt.client.ContactService;
import
com.developpez.exemple.gwt.client.ContactServiceAsync;
import
com.developpez.exemple.gwt.client.util.Contact;
import
com.google.gwt.core.client.GWT;
import
com.google.gwt.user.client.rpc.AsyncCallback;
import
com.google.gwt.user.client.rpc.ServiceDefTarget;
import
com.google.gwt.user.client.ui.FlexTable;
import
com.google.gwt.user.client.ui.VerticalPanel;
public
class
ContactsPanel extends
VerticalPanel {
private
FlexTable t =
new
FlexTable
(
);
private
Contact[] contacts;
public
static
ContactsPanel instance;
public
ContactsPanel
(
) {
getAllContacts
(
);
t.setTitle
(
"Contacts"
);
t.setText
(
0
, 0
,"Nom"
);
t.setText
(
0
, 1
,"Prénom"
);
t.setText
(
0
, 2
,"Email"
);
t.setText
(
0
, 3
,"Tel"
);
t.setWidth
(
"100%"
);
t.setCellSpacing
(
2
);
for
(
int
i =
0
; i <
4
; i++
) {
t.getCellFormatter
(
).addStyleName
(
0
, i, "contact-ContactPanel"
);
}
this
.add
(
t);
this
.setWidth
(
"100%"
);
instance=
this
;
}
private
void
addContact
(
Contact contact,int
i) {
t.setText
(
i, 0
,contact.getNom
(
));
t.setText
(
i, 1
,contact.getPrenom
(
));
t.setText
(
i, 2
,contact.getEmail
(
));
t.setText
(
i, 3
,contact.getTel
(
));
for
(
int
j =
0
; j <
4
; j++
) {
if
(
i%
2
==
0
)
t.getCellFormatter
(
).addStyleName
(
i, j, "contact-ContactPanel-line1"
);
else
t.getCellFormatter
(
).addStyleName
(
i, j, "contact-ContactPanel-line2"
);
}
}
public
void
filtre
(
){
String nom =
RecherchePanel.instance.getNom
(
);
String prenom =
RecherchePanel.instance.getPrenom
(
);
for
(
int
i =
t.getRowCount
(
)-
1
; i >
0
; i--
) {
t.removeRow
(
1
);
}
int
next =
1
;
for
(
int
i =
0
; i <
contacts.length; ++
i){
Contact contact =
contacts[i];
if
(
contact.getNom
(
).toUpperCase
(
).startsWith
(
nom.toUpperCase
(
))
&&
contact.getPrenom
(
).toUpperCase
(
).startsWith
(
prenom.toUpperCase
(
))) {
addContact
(
contact,next);
next++
;
}
}
}
private
void
getAllContacts
(
){
contacts =
new
Contact[0
];
// define the service you want to call
ContactServiceAsync svc =
(
ContactServiceAsync) GWT.create
(
ContactService.class
);
ServiceDefTarget endpoint =
(
ServiceDefTarget) svc;
String moduleRelativeURL =
GWT.getModuleBaseURL
(
) +
"contactService"
;
endpoint.setServiceEntryPoint
(
moduleRelativeURL);
AsyncCallback callback =
new
AsyncCallback
(
) {
public
void
onSuccess (
Object result)
{
contacts =
(
Contact[]) result;
filtre
(
);
}
public
void
onFailure (
Throwable ex)
{
contacts =
new
Contact[0
];
filtre
(
);
}
}
;
// execute the service
svc.getAllContact
(
callback);
}
}
Si on détaille un peu la méthode getAllContacts() :
ContactServiceAsync svc =
(
ContactServiceAsync) GWT.create
(
ContactService.class
);
ServiceDefTarget endpoint =
(
ServiceDefTarget) svc;
String moduleRelativeURL =
GWT.getModuleBaseURL
(
) +
"contactService"
;
endpoint.setServiceEntryPoint
(
moduleRelativeURL);
AsyncCallback callback =
new
AsyncCallback
(
) {
public
void
onSuccess (
Object result)
{
contacts =
(
Contact[]) result;
filtre
(
);
}
public
void
onFailure (
Throwable ex)
{
contacts =
new
Contact[0
];
filtre
(
);
}
}
;
J'ai utilisé une classe interne, car le comportement voulu était très simple, mais dans un cadre plus complexe, il serait souhaitable d'utiliser une classe externe.
svc.getAllContact
(
callback);
Dans notre exemple la mise place et l'appel du service sont fait dans la même méthode, car l'appel du service n'est fait qu'une seule fois au chargement de la page.
Néanmoins, on peut très bien placer notre service sur un slot et y faire ensuite appel en différente occasion.
Chaque appel à un service génère un aller-retour serveur. Il faut donc prévoir les temps de latence possibles.
De plus il est intéressant comme dans notre application, de stocker en cache côté client un certain nombre d'informations, afin d'alléger le nombre de requêtes au serveur.
Typiquement dans notre exemple, il était inutile de faire un aller/retour serveur pour le filtre (à la volumétrie près).
Notre application est maintenant terminée et nous obtenons la liste des contacts d'un serveur distant.
VII. Déploiement sur Tomcat▲
La structure standard d'une application sous Tomcat est la suivante :
La structure de notre projet sous Eclipse est la suivante :
Pour déployer dans une arborescence tomcat il faut :
- créer une webapp avec le nom de notre service ;
- copier le contenu du répertoire bin dans le répertoire classes de notre webapps ;
- placer le jar gwt-servlet.jar dans le répertoire lib de notre application ou dans le répertoire common/lib à la racine de tomcat ;
- copier le contenu du répertoire www à la racine de notre webapp.
Dans notre exemple le répertoire www contient un sous répertoire com.developpez.exemple.gwt.MonApplication.
Lors d'un déploiement, il est possible de ne pas conserver ce sous-répertoire en ne copiant que son contenu à la racine de la webapps.
Cela permet de simplifier l'adresse de notre application.
Enfin, il faut déclarer notre servlet. Il faut donc placer un fichier web.xml dans le répertoire WEB-INF.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Copyright 2004 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<web-app
xmlns
=
"http://java.sun.com/xml/ns/j2ee"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi
:
schemaLocation
=
"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version
=
"2.4"
>
<display-name>
GWT</display-name>
<description>
GWT example
</description>
<servlet>
<servlet-name>
ContactService</servlet-name>
<servlet-class>
com.developpez.exemple.gwt.server.ContactServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
ContactService</servlet-name>
<url-pattern>
/contactService</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>
MonApplication.html</welcome-file>
</welcome-file-list>
</web-app>
VIII. Conclusion▲
Au cours de cet article, nous avons vu tout l'intérêt du framework GWT.
Nous avons réalisé une application web interactive, dialoguant avec un serveur, en faisant abstraction de tout autre langage à part Java.
De plus le code généré est compatible avec la majorité des navigateurs.
Le framework GWT apporte au développement WEB tous les avantages du développement d'un client lourd, en permettant notamment la modélisation des classes gérant l'interface graphique.