5. Historique
– Créé en 2006 par Bruce Johnson et Joel Webber
– Rachat par Google de la startup créée par Bruce Johnson
– Version 1.0 en 2006
– Version 1.5 en 2008
– Version 2.0 en 2009
– Version 2.1 en 2010 (Activities and Places, Request Factory – une alternative à GWT RPC)
– Version 2.2 en 2011 (update du widget CellTable)
– Version 2.4 en septembre 2011
– Version 2.5 prévue en 2012 (un SuperDevMode ?)
– Release notes : https://developers.google.com/web-toolkit/release-notes
Celinio Fernandes No. 5
7. A quelle catégorie de
frameworks appartient GWT ?
• Catégorisation possible :
– basés sur des requêtes :
• Struts, Spring MVC, Wicket
– basés sur des composants :
• JSF, Tapestry, Vaadin
– RIA :
• Flex, JavaFX
GWT un mix des deux dernières catégories ?
• génère du code qui tourne côté client donc basé sur des
composants ?
• utilise des widgets donc RIA ?
Celinio Fernandes No. 7
8. Principe
• Un framework qui propose d’écrire une application en Java et de compiler ce code Java vers
du HTML et du JavaScript nativement interprétable par les navigateurs web.
Client Java JavaScript
Compilateur GWT
Services RPC
Serveur
Services Java
Partie cliente : le code Java qui est au final compilé en JavaScript et qui est exécuté dans un
browser.
• N’utilisé, côté client, que des librairies de l’API Java qui peuvent être
compilées en JavaScript
• Emulation partielle de JRE (java.lang.*, java.util.*, etc…)
Celinio Fernandes No. 8
9. Plugin GWT pour Eclipse (1/3)
• Renommé Google
Plugin
• Installation facile
via l’URL
• http://dl.google.com/eclipse/plugin/3.7
• (Eclipse 3.7 Indigo)
• Permet de créer un projet GWT sous Eclipse
• Permet de lancer une application en mode
« developpement »
Celinio Fernandes No. 9
12. Structure d’un projet / module GWT
•Fichier de configuration du module :
LabGWT.gwt.xml
•Package client : code Java compilé en
JavaScript (si spécifié par le tag <source> du
fichier de configuration)
•Package server : code Java non compilé en
JavaScript
•Package shared : code Java commun au client
et au serveur. Compilé en JavaScript (si spécifié
par le tag <source> du fichier de configuration)
•Point d’entrée : LabGWT.java
public void onModuleLoad() équivalent du
main() en C/C++/Java.
•Page HTML d’accueil : LabGWT.html. Elle inclut
le fichier JavaScript généré,
<module>.nocache.js, dans un tag <script> :
<script type="text/javascript" language="javascript"
src="labgwt/labgwt.nocache.js"></script>
Celinio Fernandes No. 12
13. Fichiers JavaScript générés
• Les fichiers JavaScript générés sont présent dans le classpath.
• Ils sont par défaut obfuscated. C’est un format compressé (pas de retour à la ligne, pas
d’espace, noms des fonctions changés, etc) qui accélère les temps de chargement.
Celinio Fernandes
14. Création d’un projet GWT avec Maven
(1/2)
Le plugin gwt-maven-plugin permet de générer un squelette de projet GWT
Celinio Fernandes
15. Création d’un projet GWT avec Maven
(2/2)
• Problème : • Archétype :
• Classes non trouvées. Faire un mvn install d’abord. • mvn archetype:generate
Puis copier-coller des classes générées suivantes : • -DarchetypeRepository=repo1.maven.org
• /target/generated- • -DarchetypeGroupId=org.codehaus.mojo
sources/gwt/foo/client/GreetingServiceAsync.java • -DarchetypeArtifactId=gwt-maven-plugin
• /target/generated- • -DarchetypeVersion=2.4.0
sources/gwt/foo/client/Messages.java
• vers /src/main/java/foo/client • http://mojo.codehaus.org/gwt-maven-
plugin/user-guide/archetype.html
•
Dépendances Maven :
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>2.4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
Celinio Fernandes
16. Création d’un projet GWT avec Spring
Roo (1/3)
• Version standalone de Roo. Pas besoin de SpringSource
Tool Suite (STS).
• Un exemple standard, Expenses, intègre GWT :
• Roo> script expenses.roo
• Roo > exit
Celinio Fernandes No. 16
18. Création d’un projet GWT avec Spring
Roo (3/3)
• Projet importable dans Eclipse.
• L’exemple Expenses utilise « Activities and Places ».
• Autre commande Roo :
• Roo > web gwt setup
• Documentation officielle :
• http://static.springsource.org/spring-roo/reference/html/base-gwt.html
Celinio Fernandes
19. Mode développement (1/3)
• Le mode developpement permet de
tester l’application dans le browser sans
avoir besoin de compiler en JavaScript.
• Apporte une plus grande productivité.
Les modifications au niveau de l’UI sont
visibles immédiatement, après refresh.
• Requiert l’installation du plugin GWT
Developer pour le browser (Firefox,
Internet Explorer, Chrome …).
• URL se termine avec
gwt.codesvr=127.0.0.1:9997. Par
exemple :
http://127.0.0.1:8888/LabGWT.html?gwt.cod
esvr=127.0.0.1:9997
Celinio Fernandes No. 19
20. Mode développement (2/3)
• Mode développement ou hosted • Mode web ou production
• Le code Java est traduit en
• Utilisé dans la phase de JavaScript
développement • Déploiement sur le serveur
• Le code client n’est pas traduit en • Application plus rapide
JavaScript
• Possibilité de debugger
• Les messages de log sont affichés
dans une fenêtre de log
• Utilise par défaut un serveur
embarqué : Jetty
• Evite la compilation de l’application
et le déploiement sur le serveur
Celinio Fernandes
21. Mode developpement (3/3)
• Pour lancer le mode
developpement avec le
plugin Maven :
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
• goal gwt:run <version>2.4.0</version>
<executions>
• goal gwt:debug <execution>
<goals>
<goal>compile</goal>
<goal>test</goal>
<goal>i18n</goal>
<goal>generateAsync</goal>
</goals>
</execution>
</executions>
<!-- Plugin configuration. There are many available options, see
gwt-maven-plugin documentation at codehaus.org -->
<configuration>
<runTarget>labGWT2.html</runTarget>
<hostedWebapp>${webappDirectory}</hostedWebapp>
<i18nMessagesBundle>foo.client.Messages</i18nMessagesBundle>
</configuration>
</plugin>
Celinio Fernandes No. 21
23. Les widgets (1/7)
• Widget = composant graphique
• Les composants graphiques générés sont du code HTML.
• On peut utiliser l’arbre DOM directement, même s’il vaut mieux utiliser les widgets et leurs
propriétés :
Button button= new Button();
DOM.setStyleAttribute(button.element, " backgroundColor", "blue");
DOM.setStyleAttribute(button.element, " border", " 1px solid ");
• Dans la hiérarchie des classes des Widgets, la classe mère est
com.google.gwt.user.client.ui.UIObject.
• http://google-web-toolkit.googlecode.com/svn/javadoc/2.4/com/google/gwt/user/client/ui/UIObject.html
• Sous-classes directes de UIObject :
• MenuItem
• MenuItemSeparator
• TreeItem
• Widget
Celinio Fernandes No. 23
24. Les widgets (2/7)
• Sous-classes directes de com.google.gwt.user.client.ui.Widget :
• AbstractNativeScrollbar : classe parente abstraite pour les scrollbars
• CellWidget
• Composite : pour créer des widgets personnalisés
• FileUpload : widget qui wrap le tag HTML <input type="type">
• FocusWidget
• Frame
• Hidden
• Hyperlink
• Image
• LabelBase
• MenuBar
• Panel : classe abstraite de base pour les panels (widgets qui contiennent d’autres widgets)
• Tree : contient une hiérarchie de TreeItems
Celinio Fernandes No. 24
25. Les widgets (3/7)
• Quelques widgets de position (layout) :
HorizontalPanel
FlowPanel
DisclosurePanel
VerticalPanel
TabLayoutPanel
Celinio Fernandes No. 25
26. Les widgets (4/7)
• Quelques widgets de saisie :
CheckBox
RadioButton
DatePicker
FileUpload
Celinio Fernandes No. 26
27. Les widgets (5/7)
• Autres widgets :
CellTable
CellTree Tree
Celinio Fernandes No. 27
28. Les widgets (6/7)
• Le showcase officiel : une
gallerie de widgets avec code
source disponible à l’URL
http://gwt.google.com/samples/Sh
owcase/Showcase.html
• Disponible également dans le
répertoire samples du SDK.
Celinio Fernandes
29. Les widgets (7/7)
• Possibilité de créer un widget personnalisé soit en :
• sous-classant un widget existant
public class DynamicSelectionCell extends SelectionCell { … }
• héritant com.google.gwt.user.client.ui.Composite (recommandé)
public class MultiSelect extends Composite {
public Label lab = new Label();
public TextBox textBox = new TextBox();
public ListBox listBox = new ListBox();
...
public MultiSelect(String caption) {
HorizontalPanel panel = new HorizontalPanel();
panel.add(lab);
panel.add(listBox);
…
// All composites must call initWidget() in their constructors.
initWidget(panel);
}
...
}
Celinio Fernandes No. 29
30. L’interface UiBinder (1/5)
– Façon déclarative de créer des layouts (vues, widgets …)
• Un template avec l’extension ui.xml : RapportViewImpl.ui.xml
• Code XML
– Ne contient pas de logique
– Décrit le layout
• Une Owner classe de même nom : RapportViewImpl.java
• Annotations : @UiField, @UiHandler, @UiTemplate (pour un nom de template différent
et/ou avec plusieurs templates), etc…
• Utilise UiBinder pour charger le layout
• Relie les évènements au code
Celinio Fernandes No. 30
36. Events et handlers (1/4)
– Un évènement (event) peut être :
• un clic de bouton (ClickEvent)
• un changement dans une listbox (ChangeEvent)
• une touche de clavier pressée (KeyDownEvent)
• un passage de souris dans une zone (MouseOverEvent)
• un défilement (ScrollEvent)
• etc…
– La classe de base est com.google.gwt.event.shared.GwtEvent
Celinio Fernandes No. 36
37. Events et handlers (2/4)
• Pour gérer ces évènements, on ajoute des handlers aux widgets. Avec plusieurs possibilités de
faire:
• en passant par une classe anonyme
• en implémentant l’interface du Handler
• etc …
• Exemples d’interfaces d’handlers : ClickHandler, ChangeHandler, KeyDownHandler, MouseOverHandler,
FocusHandler, ValueChangeHandler, SelectionHandler, OpenHandler …
• L’interface de base est com.google.gwt.event.shared.EventHandler
Celinio Fernandes No. 37
38. Events et handlers (3/4)
• Classe Handler anonyme :
public void anonClickHandlerExample() {
Button b = new Button("Click Me");
b.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// handle the click event
}
});
}
Celinio Fernandess No. 38
39. Events et handlers (4/4)
• Implémentation de l’interface du Handler :
public class HandlerExample extends Composite implements ClickHandler {
private FlowPanel fp = new FlowPanel();
private Button b1 = new Button("Button 1");
public HandlerExample() {
initWidget(fp);
fp.add(b1);
b1.addClickHandler(this);
}
public void onClick(ClickEvent event) {
Widget sender = (Widget) event.getSource();
…
}
}
– Adéquat pour des handlers complexes (plusieurs boutons, design complexe ..)
Celinio Fernandes No. 39
41. Les services RPC (1/6)
• Les services RPC (Remote Procedure Call) permettent de faire des appels d’objets entre la
partie cliente et la partie serveur.
• GWT utilise des services RPC asynchrones pour rendre les applications Web plus interactives.
Que veut dire asynchrone ?
• Le programme n’attend pas la fin de l’exécution de la méthode pour passer la suite (principe
même d’Ajax). Si un service est long, il ne faut pas attendre la réponse et il faut laisser la main
au browser.
• GWT prend en charge la sérialisation et la désérialisation des objets Java.
• GWT utilise des interfaces pour créer un service RPC :
• Une interface synchrone qui hérite de com.google.gwt.user.client.rpc.RemoteService,
côté client
• Une interface asynchrone, côté client
• Une classe, côté serveur (= package serveur), qui implémente l’interface synchrone et les
méthodes RPC qu’on veut mettre à disposition côté client
• Pourquoi des services RPC dans GWT ?
• Permettre l’exécution de méthodes côté serveur et qui ne sont pas exécutables côté client
(compilation impossible en JavaScript, problème de sécurité …)
Celinio Fernandes No. 41
42. Les services RPC (2/6)
• Etapes
1. Créer les classes et interfaces RPC côté client
2. Créer l’implémentation côté serveur du service RPC. C’est une servlet qui implémente
l’interface synchrone et qui étend RemoteServiceServlet.
3. Faire l’appel du service RPC dans le code
4. Ne pas oublier de modifier le fichier web.xml pour y déclarer la servlet et faire le mapping !
Celinio Fernandes No. 42
43. Les services RPC (3/6)
• Diagramme de la plomberie RPC
• Source : https://developers.google.com/web-toolkit/doc/latest/DevGuideServerCommunication#DevGuidePlumbingDiagram
•
Celinio Fernandes No. 43
44. Les services RPC (4/6)
• L’interface synchrone (côté client) :
@RemoteServiceRelativePath("manageVille")
public interface ManageVilleService extends RemoteService {
public long getCodePostalVille (String nom) throws VilleNonTrouveeExceptionDto;
}
• L’interface asynchrone (côté client) :
public interface ManageVilleServiceAsync {
void getCodePostalVille (String nom, AsyncCallback<long> callback);
}
• L’implémentation du service (côté serveur) :
@RemoteServiceRelativePath("manageVille")
public class ManageVilleDelegate extends SpringBeanInjectionRemoteServiceServlet implements ManageVilleService {
@Autowired
private ManageVille manageVilleApplication;
public long getCodePostalVille (String nom) throws VilleNonTrouveeExceptionDto {
// appels de services des autres couches / de modules non GWT …
…
}
• Note : @RemoteServiceRelativePath associe le service à un chemin relatif
Celinio Fernandes No. 44
45. Les services RPC (5/6)
• Appel du service RPC depuis une activity (côte client), par exemple :
public class VilleActivity extends AbstractActivity implements VilleView.Presenter {
// RPC service proxy
private final ManageVille ServiceAsync manageVilleServiceProxy;
…
manageVilleServiceProxy.getCodePostalVille(String nom, new AsyncCallback<long> () {
public void onFailure(Throwable caught) {
Window.alert("Problème !!");
}
public void onSuccess(long codePostal){
view.setCodePostal(codePostal);
}
});
….
}
• Création d’une classe AsyncCallback anonyme, en paramètre de la méthode asynchrone
appelée.
Lab GWT No. 45
46. Les services RPC (6/6)
• Important : les objets transportés doivent être sérialisables. Les règles de sérialisation
diffèrent un peu de celles de l’API Java standard.
• https://developers.google.com/web-toolkit/doc/latest/DevGuideServerCommunication?hl=fr-
FR#DevGuideSerializableTypes
• Problème des entités :
• Les entités JPA sont transformées au runtime par Hibernate, pour les rendre persistantes. Hibernate les
instrumente en modifiant le bytecode, ce qui pose problème pour l’échange des données entre le client et
le serveur à l’aide de la sérialisation.
• Solution :
• Utiliser le pattern DTO. Les objets de transfert (avec la même structure ou non que les objets persistés) ne
sont pas instrumentés et peuvent être rendus sérialisables.
• Et utiliser Dozer pour la transformation.
Entité Dozer DTO
Celinio Fernandes No. 46
48. Le design pattern MVP (1/5)
• Qui connait MVP ?
• Permet d’éviter du code spaghetti
MVP
•
• Modèle : les DTOs, les données qui sont affichées
• Vue : l’interface graphique
• Presenter : équivalent du contrôleur de MVC. Implémente l’accès à la logique métier et au modèle
de données. Réagit aux évènements de l’utilisateur et qui sont transmis par la Vue.
Celinio Fernandes No. 48
49. Le design pattern MVP (2/5)
• Avantages :
• Séparation claire entre la partie présentation et la logique métier
• Plus grande maintenabilité puisqu’il n’y a presque pas de dépendance avec la logique métier
(couplage faible).
• Plus facile à tester. On peut mocker la Vue, le Presenter … (Mockito).
Celinio Fernandes No. 49
50. Le design pattern MVP (3/5)
• Un pattern conceptualisé par Martin Fowler :
• http://martinfowler.com/eaaDev/ModelViewPresenter.html
• Permet de séparer la logique métier de l’UI.
• Deux variantes : Passive View et Supervising Controller
• Source : http://msdn.microsoft.com/en-us/library/ff647543.aspx
Celinio Fernandes No. 50
51. Le design pattern MVP (4/5)
• Dans GWT, c’est plutôt la variante Passive View qui est appliquée.
• Sens unidirectionnel (dans l’idéal, la Vue est totalement passive)
Vue Presenter Modèle
•
• Le Presenter met à jour la Vue.
• Sens bidirectionnel
Vue Presenter Modèle
• Le Presenter communique avec la Vue et la Vue communique avec le Presenter. Il existe un
lien étroit.
• Dans les deux sens, il n’y a pas de communication directe entre le Modèle et la Vue.
Celinio Fernandes No. 51
52. Le design pattern MVP (5/5)
• Différences avec MVC ?
Vue Modèle
Contrôleur
• Le Contrôleur gère les actions de l’utilisateur.
• La Vue peut accéder au Modèle directement.
Vue Presenter Modèle
• La Vue gère les actions de l’utilisateur (via le Presenter).
• La Vue n’interagit pas avec le Modèle.
Celinio Fernandes No. 52
54. L’EventBus (1/5)
• Le but du bus d’évènements est de permettre à des objets de « souscrire » à certains évènements du
bus.
• C’est un singleton. On peut créer plusieurs bus, par fonctionnalité.
• Par exemple un bus pour traiter les évènements liés à la navigation seulement, un autre bus pour
transmettre des messages …
• Pour créer un bus, on peut étendre la classe com.google.gwt.event.shared.EventBus.SimpleEventBus
• Permet un couplage lâche puisqu’il permet aux objets d’interagir sans avoir de dépendances directes les
uns envers les autres.
• Est utilisé par l’API Activities and Places.
• Exemples d’utilisation :
• Affichage d’une barre de notification lorsqu’un traitement démarre ou se termine.
• Redirection vers un écran de login lors d’un timeout de session, après un appel à un service RPC
Celinio Fernandes No. 54
55. L’EventBus (2/5)
• Une instance unique d’un EventBus est transmise aux composants qui interagissent avec.
Composant 1 Composant 2 Composant 3
Event Event Event
+ + + etc…
Handler Handler Handler
EventBus
Composant 4 Composant 5 Composant 6
Celinio Fernandes No. 55
56. L’EventBus (3/5)
• Création d’un évènement
import com.google.gwt.event.shared.GwtEvent;
public class MessageEvent extends GwtEvent<MessageEventHandler> {
public static final Type<MessageEventHandler> TYPE = new Type<MessageEventHandler>();
private final String message;
public MessageEvent(final String pMessage) {
super();
message = pMessage;
}
@Override
protected void dispatch(MessageEventHandler handler) {
handler.onMessageRecu(this);
}
@Override
public Type<MessageEventHandler> getAssociatedType() {
return TYPE;
}
public String getMessage() {
return message;
}
}
Celinio Fernandes No. 56
57. L’EventBus (4/5)
• Création d’un handler d’évènement
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.gwt.user.client.Window;
public class MessageEventHandler implements EventHandler {
public static final Type<MessageEventHandler> TYPE = new Type<MessageEventHandler>();
public MessageEventHandler() {
}
/**
* Affichage d'une alerte lors de la réception d'un message
*
* @param messageEvent
*/
public void onMessageRecu(final MessageEvent messageEvent) {
Window.alert(messageEvent.getMessage());
}
}
Celinio Fernandes No. 57
58. L’EventBus (5/5)
• Classe com.google.gwt.event.shared.EventBus
• 2 méthodes principales :
• <H> HandlerRegistration addHandler(Event.Type<H> type, H handler)
Ajoute un handler (à l’EventBus) pour recevoir des évènements de ce type de toutes les sources.
private void ecouterEvents() {
GWT.log("attachement des events");
this.eventBus.addHandler(MessageEvent.TYPE, new MessageEventHandler());
}
• abstract void fireEvent(GwtEvent<?> event)
Déclenche l'évènement passé en paramètre, pour les handlers qui écoutent ce type d'évènement
private final MessageEvent messageEvent = new MessageEvent(« ATTENTION !!!");
…
eventBus.fireEvent(messageEvent);
Cet EventBus est par exemple passé en paramètre à la méthode start() d’une activity.
Celinio Fernandes No. 58
59. Activities and Places (1/8)
• Une API pour la navigation et pour la gestion de l’historique. Apparu dans la version 2.1.
• Adéquat pour mettre en place une architecture basée sur le design pattern MVP.
• Ne pas confondre « Activities and Places » avec MVP :
on peut implémenter MVP sans « Activities and Places » et on peut utiliser « Activities and
Places » sans MVP.
• Explications officielles :
http://code.google.com/webtoolkit/doc/latest/DevGuideMvpActivitiesAndPlaces.html
• API complexe
• Bonne façon de commencer :
http://code.google.com/p/google-web-toolkit/downloads/detail?name=Tutorial-hellomvp-2.1.zip
Celinio Fernandes No. 59
60. Activities and Places (2/8)
–Les objets concernés
• La vue : La partie graphique associée à une activité.
• L’activité : c’est le presenter. L’interface du presenter est définie dans l’interface de la vue qui
lui est associée.
• La place : un objet Java qui représente un état bookmarkable de l’application. Utilisée pour
l’historique. C’est l’endroit (la page) où l’on se trouve dans l’application.
• Un PlaceHistoryMapper pour déclarer les places qu’on souhaite historiser (boutons Précédent
et Suivant) dans l’application. Est lié à PlaceHistoryHandler qui permet le mapping bi-
directionnel entre les places et l’URL (qui contient le token de la Place appelée).
• Un PlaceController : gère le changement de places.
• Un ActivityManager : détermine l’activité à lancer pour une place donnée. Il utilise un
ActivityMapper. Un ActivityManager par zone est une bonne idée.
• L’EventBus : est passé dans les activities et les vues. Il dispatche des évènements vers les
parties intéressées.
• Une ClientFactory : non requis mais bonne pratique. Utilisée pour l’injection
d’objets tels que l’EventBus, le PlaceController, les vues …
Celinio Fernandes No. 60
61. Activities and Places (3/8)
– La vue
public interface HelloView extends IsWidget
{
void setName(String helloName);
void setPresenter(Presenter listener);
public interface Presenter
{
void goTo(Place place);
}
}
• Hérite de IsWidget
• Généralement une vue est mappée à un presenter. Les vues
complexes peuvent avoir plusieurs presenters.
• setPresenter(…) permet une communication bi-
directionnelle
Celinio Fernandes No. 61
62. Activities and Places (4/8)
– L’activity (presenter)
public class HelloActivity extends AbstractActivity implements
HelloView.Presenter {
…
public void goTo(Place place) {
clientFactory.getPlaceController().goTo(place);
}
}
• Elle étend AbstractActivity
• Elle implémente l’interface déclarée dans la vue
• Le PlaceController est injecté dans l’activité
Celinio Fernandes No. 62
63. Activities and Places (5/8)
– Méthodes du cycle de vie d’une activity
• public void start(AcceptsOneWidget containerWidget, EventBus
eventBus)
– est appelée lors du retour de l’activity par l’ActivityMapper
– seule méthode obligatoire si on étend AbstractActivity
• public String mayStop()
– est appelée avant que l’utilisateur quitte l’activity
– retourne un message pour prévenir l’utilisateur, sinon rien
• public void onCancel()
• est appelée si l’utilisateur change d’activity avant le retour de la méthode
start(…)
• public void onStop()
• est appelée lorsque l’activity se termine (quand on quitte la page ou qu’une
autre activity la remplace)
Celinio Fernandes No. 63
64. Activities and Places (6/8)
– La place
• public class GoodbyePlace extends Place {
private String goodbyeName;
public GoodbyePlacetoken) {
this.goodbyeName = token;
}
public String getGoodbyeName() {
return goodbyeName;
}
public static class Tokenizer implements PlaceTokenizer< GoodbyePlace > {
@Override
public String getToken(GoodbyePlace place) {
return place.getGoodbyeName();
}
@Override
public GoodbyePlace getPlace(String token) {
return new GoodbyePlace token);
}
}
}
• Une place hérite de com.google.gwt.place.shared.Place
Celinio Fernandes No. 64
65. Activities and Places (7/8)
– Par défaut l’URL est de la forme
http://127.0.0.1:8888/HelloMVP.html#{NomPlace}:T
oken
où
• {NomPlace} : par défaut le nom de la classe de la place.
Peut être changé à l’aide de l’annotation @Prefix
• Token : le token retourné par PlaceTokenizer
http://127.0.0.1:8888/HelloMVP.html#GoodbyePlace:World!
Celinio Fernandes No. 65
66. Activities and Places (8/8)
– PlaceHistoryMapper
@WithTokenizers( {
HelloPlace.Tokenizer.class,
GoodbyePlace.Tokenizer.class,
RapportPlace.Tokenizer.class
})
public interface AppPlaceHistoryMapper extends PlaceHistoryMapper {
}
• Non obligatoire. Si une place n’est pas déclarée, il n’y a
pas d’historique pour cette place et le bouton
« Précédent » du navigateur est désactivé.
Celinio Fernandes No. 66
67. Optimisation avec le code splitting
(1/2)
– Chargement à la demande
• Par défaut, tout le code JavaScript est compilé en un seul fichier qui est téléchargé au
chargement de la page. Ce chargement initial peut être long.
• Le code splitting consiste à splitter ce fichier JS en plusieurs fichiers JS qui seront téléchargés
quand ceux-ci seront appelés.
• On insère des « split points » dans le code.
GWT.runAsync(new RunAsyncCallback() {
@Override
public void onFailure(Throwable caught) {
//En cas d'échec du téléchargement du nouveau code
Window.alert("Echec du téléchargement du JavaScript");
}
@Override
public void onSuccess() {
//Ce code est téléchargé au moment où il est appelé
Window.alert("Chargement à la demande ");
}
});
Celinio Fernandes No. 67
68. Optimisation avec le code splitting
(2/2)
– Les fichiers JavaScript générés sont placés dans le répertoire defferedjs
– Il convient de placer les split points à des endroits judicieux.
– Avec Activities and Places, on peut par exemple faire du code splitting au niveau de
l’ActivityManager en créant un wrapper autour de la classe AbstractActivity, avec l’interface
AsyncProvider<T,F>.
Ce wrapper renvoie une activité quand elle est appelée. Son code n’est donc pas chargé au
démarrage de l’application.
Celinio Fernandes No. 68
69. Autres bonnes pratiques (1/2)
• Ne pas mélanger GWT avec d’autres frameworks, pour la partie présentation.
• GWT ne doit pas être utilisé que pour créer des widgets mais aussi pour gérer la
navigation, l’historique, l’internationalisation, la validation etc.
• Créer des composants personnalisés réutilisables
• Packager les ressources avec un client bundle
Celinio Fernandes No. 69
70. Autres bonnes pratiques (2/2)
• Créer des classes chargées de gérer les callbacks (allège le code, permet de réutiliser les
callbacks …) des services RPC.
• public class FindAllVillesCallBack implements AsyncCallback<List<VilleRechercheDto>> {
• ...
• public void onFailure(Throwable caught) {
• eventBus.fireEvent(finishSearchVillesEvent);
• if (caught instanceof AccesInterditExceptionDto) {
• view.accesDenied();
• }
• else if (caught instanceof InvocationException) {
• GWT.log("FindAllVillesCallBack : InvocationException *****" + caught.getMessage());
• return;
• }
• else if (caught instanceof NotFoundExceptionDto) {
• view.noData();
• } else {
• GWT.log("FindAllVillesCallBack: une erreur technique s'est produite : " + caught);
• }
• }
• public void onSuccess(List<VilleRechercheDto> result) {
• GWT.log("FindAllVillesCallBack : onSuccess****************");
• view.setData(result);
• eventBus.fireEvent(finishSearchVillesEvent);
• }
• }
• private final ManageVilleServiceAsync manageVilleServiceProxy;
• manageVilleServiceProxy.findAllVilles(new FindAllDVillesCallBack(view, eventBus, finishSearchVillesEvent));
Celinio Fernandes No. 70
71. Non couvert
• Request Factory : alternative à GWT RPC
• Internationalisation
• Ressources bundles / client bundle : mettre en cache des ressources
(fichiers, images, CSS …)
• JSNI (JavaScript Native Inteface) : support pour JavaScript natif (inclure du
code JavaScript dans du code Java).
• Tests : GWTTestCase
• Deferred binding (liaison différée) :
• pour l’insertion d’une classe à la compilation, pas au runtime.
• pour créer plusieurs implémentations (une par browser) de la même fonctionnalité
• GWT.create(Class) instancie une classe via le deferred binding
• Speed Tracer : mesurer les performances
• Gin : GWT Injection, framework IoC pour GWT, côté client
• Guice : framework d’injection de dépendances
• etc …
Celinio Fernandes No. 71
73. Librairies tierces
• SmartGWT : Remplace GWT-Ext. Type de licence : open source LGPL.
C’est un wrapper de SmartClient (les composants encapsulent le code JavaScript SmartClient, en utilisant JSNI).
http://gwt-ext.com/
http://www.smartclient.com/smartgwt/showcase/
• Sencha GXT (Ext GWT) : Sencha est le créateur du framework JavaScript Ext JS. Ce n’est pas un
wrapper de Ext JS, les composants sont natifs c.a.d. écrits en Java. Types de licences : GPL et
commercial.
http://www.sencha.com/products/gxt/
https://developers.google.com/web-toolkit/tools/gwtdesigner/features/gwt/gxt
• GWT-Ext : wrapper autour de Ext JS. N’est plus maintenu par Sencha.
• etc …
• Questions à se poser :
1. Peut-on mélanger ces widgets avec les widgets de base de GWT ?
2. Open source ou commerciale ?
3. Performances ? Composants plus riches mais performances plus faibles par rapport à GWT de base ?
• Etude comparative de quelques widgets entre Sencha GXT et GWT :
http://gxtvsgwt.appspot.com/
Les widgets Sencha seraient 2 à 10 fois moins rapides que celles de GWT de base.
Celinio Fernandes No. 73
74. Dart : la menace ?
• Dart : créé en 2011 par Google. Certains développeurs GWT travaillent maintenant sur
Dart.
• Nouveau langage, avec une syntaxe proche d’un mélange entre C et Java. Produit du
JavaScript.
• Google IO 2012 (3 jours, fin juin) :
• 2 sessions GWT seulement, pour l’instant (fin mai) : "Migrating Code from GWT to Dart" et
"The History and Future of Google Web Toolkit"
• Déjà au moins 4 sessions Dart de prévues
https://developers.google.com/events/io/sessions
Source : http://www.dartlang.org/support/faq.html#future-for-GWT
– Version 2.5 de GWT contiendrait une grosse surprise !
Celinio Fernandes No. 74
75. Pour aller plus loin
– Livres
• En anglais :
GWT in Action, 2nd édition (prévue en août 2012)
• En français :
Programmation GWT 2 - Développer des
applications RIA et Ajax avec le Google Web Toolkit
de Sami Jaber (1ère édition, janvier 2010).
Deuxième édition prévue en juin 2012.
– Liens
https://developers.google.com/web-toolkit/doc/latest/DevGuide
https://developers.google.com/web-toolkit/doc/latest/DevGuideMvpActivitiesAndPlaces
http://groups.google.com/group/Google-Web-Toolkit
Celinio Fernandes No. 75