Le contexte:
Le projet a pour but d'améliorer l'ergonomie et l'usabilité du back office d’un produit en cours de développement réalisé en collaboration avec SFEIR
Dans le cadre de ce projet, la version de GWT utilisée passe de la 1.7.1 à la 2.0.3 afin de bénéficier des nouvelles fonctionnalités offertes par cette version. De nouveaux pattern de développement ont également été mis en place au cours de ce projet.
Voici une série d'article sur les nouveautés de GWT 2, les choix d'architectures, et bibliothèques utilisés qui font part de notre retour d'expérience sur le sujet. Ces articles ont été écris par David Aboulkheir, Patrice de Saint Steban et Cyril Lakech
- Nouveautés de GWT 2.0
- UiBinder, enfin une forte collaboration entre le designer et le développeur
- Intégration facile de maquette Html en GWT 2
- Architecture Modèle-Vue-Presenteur
- Implémentation Modèle-Vue-Présenteur
- Ecrire des tests unitaires avec Mockito
- Mise en place de Gin sur le projet
- Internationalisation
UiBinder, enfin une forte collaboration entre le designer et le développeur
Dans la version 2 de GWT, Google propose aux développeurs de choisir comment coder les écrans, soit en Java uniquement comme c'était le cas jusqu'à présent soit en utilisant une nouvelle fonctionnalité UiBinder, qui permet de coder les écrans en XML, très proche du HTML.
UiBinder permet d'écrire les interfaces graphiques avec un formalisme XML un peu comme on peut le faire avec JSF, Flex, Silverlight ou encore en HTML. Jusque-là, la création d'interface en GWT se faisait en manipulant du code java à la façon native de Swing ou SWT/JFace. On va maintenant pouvoir les écrire en XML et les lier (les binder) avec une classe java qui contiendra le code de notre vue. Le code en sera d'autant plus lisible, maintenable et plus rapide à développer. Cette évolution va permettre également la multiplication d'outils puissants, comme les éditeurs d'interfaces GWT, plus simples à créer, comme GWTDesigner d'Instantiations, qui a été acheté par Google et qui est maintenant disponible gratuitement: http://code.google.com/intl/fr/webtoolkit/tools/download-gwtdesigner.html
Cette nouvelle organisation, sépare la partie présentation (l'écran) de la partie contrôle (le code java). On écrit un fichier XML contenant nos widgets graphiques, puis on les associe avec les objets dans notre classe java où l'on ajoute aussi les évènements de l'IHM. Il est également possible d'écrire notre interface en HTML en y incorporant nos widgets HTML. Le CSS peut se trouver directement dans le fichier d'interface ou dans un ClientBunddle (système GWT2 de gestion des ressources type CSS en java qui sera détaillé ci-dessous).
Prenons une classe Miniature.java, qui permet d'afficher une image et son titre, pour utiliser UIBinder. Commençons par créer le fichier xml :
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:gwt='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
.mini {
float : left;
margin: 20px;
height: 150px;
width: 150px;
}
</ui:style>
<gwt:VerticalPanel styleName="{style.mini}">
<gwt:Image ui:field="miniature" />
<gwt:Label ui:field="label"/>
</gwt:VerticalPanel>
</ui:UiBinder>
Nous voyons ici, que la racine du XML, ui:UiBinder permet de configurer les namespaces pour utiliser les composants, le namespace "ui" contient les configurations du UiBinder, tandis que le namespace "gwt" permet d'utiliser les composants de base de GWT. La balise <ui:Style> permet d'insérer le CSS utilisé par notre composant. Dans la suite du fichier, on peut accéder à la classe CSS en utilisant la syntaxe {style.nomClasse}. Nous voyons ensuite que le composant GWT racine est le VerticalPanel qui contient une Image et un Label. Pour les composants Image et Label, on a ajouté un attribut ui:field associé à un nom de paramètre, ce qui nous permettra d'accéder au composant depuis notre classe Java.
Voyons maintenant la classe Java associée :
public class Miniature extends Composite {
interface Binder extends UiBinder<Widget, Miniature> { }
private static final Binder binder = GWT.create(Binder.class);
@UiField Image miniature;
@UiField Label label;
private String destination;
public Miniature(String url, String titre, String destination) {
this.destination = destination;
initWidget(binder.createAndBindUi(this));
miniature.setUrl(url);
label.setText(titre);
}
@UiHandler("miniature")
public void onClick(ClickEvent event) {
Window.open(destination, "Image", "width=200, height=100");
}
}
L'interface Binder étend UiBinder qui prend deux paramètres de type, le composant de base de notre interface (VerticalPanel dans notre cas, mais nous utilisons une super classe), et la classe qui va contenir les composants reliés (La classe actuel). Nous créons ensuite, en variable static, une instance de cette interface en utilisant GWT.create(); C'est le compilateur de GWT qui s'occupera d'implémenter cette classe en utilisant les informations du fichier XML.
Puis nous ajoutons les champs de notre interface en utilisant l'annotation @UiField pour indiquer à GWT qu'il faut relier ces champs avec les composants GWT définis dans le fichier XML. Le nom du champ doit être celui donné dans l'attribut ui:field. Dans notre constructeur, nous appelons la methode createAndBindUi sur notre interface Binder, qui va alors créer et relier les composants GWT à notre classe. Enfin, la methode onClick, appelée lors du clic sur l'image, est reliée à notre composant miniature grâce à l'annotation @UiHandler("miniature").
UiBinder permet aussi de créer une interface en HTML et d'y intégrer nos composants GWT sans passer par les traditionnels composants Panel de GWT (VerticalPanel, Grid, ...), tout simplement en utilisant le composant HTMLPanel. Utilisons ce procédé pour refaire le formulaire de recherche :
<?xml version="1.0" encoding="UTF-8"?>
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:gwt='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
.label {
float: left;
width: 50px;
clear: both;
}
.element {
float: left;
width: 250px;
}
</ui:style>
<gwt:HTMLPanel>
<dl>
<dt class='{style.label}'>
<ui:msg>Topic :</ui:msg>
</dt>
<dd class='{style.element}'>
<gwt:TextBox ui:field="saisieSujet" />
</dd>
<dt class='{style.label}'>
</dt>
<dd class='{style.element}'>
<gwt:Button ui:field="boutonAjouter">
<ui:msg>Search</ui:msg>
</gwt:Button>
</dd>
</dl>
</gwt:HTMLPanel>
</ui:UiBinder>
Ici, la classe Java est sensiblement équivalente à la classe Miniature.java :
public class FormulaireRecherche extends DialogBox {
interface Binder extends UiBinder<Widget, FormulaireRecherche> {}
private static final Binder binder = GWT.create(Binder.class);
@UiField Button boutonAjouter;
@UiField TextBox saisieSujet;
public FormulaireRecherche() {
super(true);
add(binder.createAndBindUi(this));
center();
}
@UiHandler("boutonAjouter")
public void onClick(ClickEvent event) {
hide();
}
}
Références :
