Redécouvrez le web avec Wicket

Java constitue une formidable plateforme de développement que cela soit pour les clients riches ou les applications web.
S'il n'est pas nécessaire d'utiliser Java EE pour réaliser un site web, il est nécessaire de faire appel aux services d'un framework.

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Share on Google+ 

Introduction

Malgré son succès pour le déploiement d'applications web côté serveur, Java souffre d'une réputation de technologie compliquée et difficile à mettre en oeuvre. Cette constatation est parfaitement vraie dans le cas de Java Enterprise Edition, conçue pour soutenir de très grosses applications réparties sur plusieurs machines. La plateforme Java SE suffit cependant pour construire des applications web grâce aux servlets, aux Java Server Pages (JSP) et à un simple serveur comme Tomcat, également appelé conteneur de servlet. Les JSP et servlets ne constituent que la couche de plus bas niveau des applications web écrites en Java. Pour simplifier et accélérer les développements, de nombreux frameworks sont disponibles, proposant tous des fonctionnalités et des concepts très différents.

Image non disponible
Le site de Wicket propose des liens vers les blogs des développeurs

Certains de ces frameworks, comme Spring, Turbine, Tapestry, Cocoon ou encore le fameux Struts, sont largement répandus et utilisés par de nombreuses entreprises. Bien que Wicket ne soit à première vue qu'un framework de plus dans cet univers déjà surchargé, les motivations de ses auteurs sont très claires. Contrairement aux offres existantes, Wicket est simple à apprendre, ne nécessite pas de code HTML spécifique ni de fichier de configuration XML compliqué et repose sur une API semblable à Swing. A l'instar des Java Server Faces (JSF) ou d'ASP.NET, Wicket maintient en outre automatiquement l'état des composants sur le serveur. Un champ texte d'une page HTML est par exemple lié à un composant et à un modèle Java du côté serveur. Cette solution permet de vous affranchir d'une grande partie de la gestion des sessions utilisateurs. Enfin, comme nous allons le voir, Wicket rend très facile la séparation entre la logique et la présentation.

Image non disponible
Certains composants Wicket sont complexes, comme cet exemple d'arbre.

Mise en route

Le framework Wicket existe aujourd'hui en versions 1.0 et 1.1-beta2. Nous allons utiliser cette dernière pour nos premiers pas. Vous trouverez cet exemple dans l'application login-wicket (HTTP - FTP). La distribution binaire contient une bibliothèque appelée wicket-1.1-b2.jar que vous devrez copier dans le dossier WEB-INF/lib de votre application web. Vous devrez également copier les dépendances qui se trouvent dans le répertoire lib/ de Wicket. Il ne vous reste plus qu'à créer le descripteur web.xml de l'application comme celui présenté dans le listing 1.

listing 1
Sélectionnez

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
  <display-name>Login: Wicket</display-name>
  <servlet>
    <servlet-name>HelloWorldApplication</servlet-name>
    <servlet-class>wicket.protocol.http.WicketServlet</servlet-class>
    <init-param>
      <param-name>applicationClassName</param-name>
      <param-value>com.loginmag.HelloWorldApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>HelloWorldApplication</servlet-name>
    <url-pattern>/helloworld/*</url-pattern>
  </servlet-mapping>
  
  <servlet>
    <servlet-name>ChatApplication</servlet-name>
    <servlet-class>wicket.protocol.http.WicketServlet</servlet-class>
    <init-param>
      <param-name>applicationClassName</param-name>
      <param-value>com.loginmag.ChatApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>ChatApplication</servlet-name>
    <url-pattern>/chat/*</url-pattern>
  </servlet-mapping>
</web-app>

Ce descripteur peut prêter à confusion car il est possible de créer plusieurs applications Wicket dans une même application web. Pour créer une nouvelle application Wicket, il vous suffit d'utiliser le servlet WicketServlet et d'utiliser le paramètre applicationClassName pour indiquer la classe représentant l'application à proprement parler. Une application est une classe Java héritant wicket.protocol.http.WebApplication et servant de point d'entrée et de configuration. La méthode getPages() renvoie la propriété la plus importante de votre application, une instance d'ApplicationPages qui vous permet de définir la page d'accueil et les pages d'erreur. Le listing 2 présente l'implémentation minimale d'une application Wicket.

listing 2
Sélectionnez

package com.loginmag;

import wicket.protocol.http.WebApplication;

public class HelloWorldApplication extends WebApplication {
  public HelloWorldApplication() {
    getPages().setHomePage(HelloWorldPage.class);
  }
}
Image non disponible
Suivant l'API Swing au plus près, Wicket propose une méthode paint() pour générer des images.

La page d'accueil est passée en paramètre de la méthode setHomePage() sous la forme d'une classe Java (une instance de Class), dans notre cas HelloWorldPage.class. Une fois la page d'accueil spécifiée, toute requête sur l'URL http://localhost:8080/login-wicket/helloworld renverra le code HTML généré par la page HelloWorldPage.

Une page Wicket est constituée de deux éléments : une classe Java héritant wicket.markup.html.WebPage et un fichier HTML portant le même nom que la classe, HelloWorldPage.html dans notre cas. Le listing 3 présente le contenu de la page HTML.

listing 3
Sélectionnez

<html>
  <head>
    <title>Login: Wicket</title>
  </head>
  <body>
    <span wicket:id="message">Emplacement du message</span>
  </body>
</html>

Le code n'utilise que des balises HTML ou XHTML classiques. La seule différence réside dans l'utilisation du namespace wicket pour identifier les composants pour le code Java. Dans cet exemple nous avons créé un élément <span /> appelé message et contenant un texte par défaut.

Image non disponible
Tomcat est un conteneur de servlet gratuit et open source très simple à utiliser avec Wicket.

Cette approche, très simple, permet aux designers de concevoir l'apparence visuelle du site sans se soucier d'intégrer des instructions de programmation. Ils pourront ainsi éditer les pages dans un outil comme DreamWeaver ou Nvu, à condition de conserver les wicket:id des composants. Lors de la conception visuelle des pages, les designers utiliseront les valeurs par défaut, comme celle de notre exemple. De la même manière, les développeurs n'auront pas à s'inquiéter d'interférer avec l'apparence du site et pourront se concentrer sur l'implémentation de la logique. Pour vous en convaincre, étudiez le code Java de HelloWorldPage présenté dans le listing 4.

listing 4
Sélectionnez

package com.loginmag;

import wicket.markup.html.WebPage;
import wicket.markup.html.basic.Label;

public class HelloWorldPage extends WebPage {
  public HelloWorldPage() {
    add(new Label("message", "Hello World !"));
  }
}

L'unique ligne de cette page ajoute un composant de type Label pour lequel le premier paramètre définit le nom et le second paramètre la valeur. Lorsqu'un visiteur arrivera sur votre page, Wicket exécutera votre code pour remplacer le contenu de la balise <span /> par la valeur du Label.

Image non disponible
Les spécifications de Java EE 5 font plus de 300 pages... Wicket est bien plus simple !

Utilisation des formulaires

Notre second exemple est un petit chat que vous trouverez dans l'application Wicket ChatApplication. Il ne contient qu'une seule page, ChatPage, qui permet aux visiteurs d'envoyer des messages. Le listing 5 contient une version simplifiée de la page HTML représentant le chat.

listing 5
Sélectionnez

<form wicket:id="chatForm">
  Surnom : <input type="text" wicket:id="nick"></input><br />
  Message : <input type="text" wicket:id="message"></input><br />
  <input type="submit" value="Envoyer" />
</form>
<span wicket:id="messages">
  <span wicket:id="nick">Invité</span> : <span wicket:id="message">Message.</span><br /><br />
</span>

Dans cette page se trouvent deux composants racine, un formulaire chatForm et une liste de message appelée messages. Ils contiennent chacun un champ nick et un champ message pour permettre au visiteur de saisir ou de voir les messages. En aparté, cet exemple montre que Wicket gère parfaitement des arbres de composants. Nous avons appris au début de cet article que les composants HTML sont liés à un composant Java et à un modèle. Dans cet exemple, le formulaire permet de remplir les informations d'un modèle qui seront lues pour l'affichage des messages. A l'opposé de Java EE et de ses EJB, Wicket se contente de POJO (Plain Old Java Object) pour gérer les modèles. Le modèle du chat correspond à la classe Message qui se trouve sur le CD-Rom.

Image non disponible
La réalisation d'un chat en Wicket ne nécessite que quelques lignes de code.

Elle implémente simplement l'interface Serializable pour permettre à Wicket de la sauvegarder en session, et expose ses attributs avec des accesseurs et mutateurs. Conformément à la page HTML, un message contient le surnom de l'utilisateur, attribut nick, et son message, attribut message. La réalisation de la page Java responsable de la liaison entre la page HTML et le modèle demande d'utiliser de nouveaux composants Wicket comme le montre le listing 6 qui contient la définition de la page ChatPage.

listing 6
Sélectionnez

public class ChatPage extends WebPage {
  private static List messagesList = new ArrayList();
  private ListView messagesListView;
  
  public ChatPage() {
    add(new ChatForm("chatForm"));
    add(messagesListView = new ChatListView("messages", messagesList));
  }
  // ...
}

Le premier composant personnalisé est ChatForm, dérivant de Form, capable de gérer les champs du formulaire. Le second composant est un dérivé de ListView, ChatListView, que nous utilisons pour afficher la liste des messages saisis par les utilisateurs. Le modèle de cette liste est une ArrayList statique afin qu'elle soit visible de tous les visiteurs du site. Lors du rendu de la page, la méthode populateListItem() du composant ChatListView sera invoquée pour chaque élément de la liste messagesList. Le listing 7 présente le code utilisé pour modifier les valeurs des composants HTML correspondant à chaque élément.

listing 7
Sélectionnez

private class ChatListView extends ListView {
  // ...
  public void populateItem(ListItem listItem) {
    Message message = (Message) listItem.getModelObject();
    listItem.add(new Label("nick", message.getNick()));
    listItem.add(new Label("message", message.getMessage()));
  }
}

Le composant ListItem passé en paramètre est le conteneur dans lequel se trouvent les composants nick et message. Il suffit donc de récupérer le modèle à l'aide de getModelObject() et d'invoquer ses accesseurs pour obtenir les valeurs désirées.

Image non disponible
Les designers pourront utiliser des outils WYSIWYG sans corrompre le code

Le modèle que nous venons d'extraire est ajouté à la liste lors de la soumission du formulaire. Ce dernier est un peu plus complexe à mettre en place car il doit être lié à l'objet du modèle comme le montre le listing 8.

listing 8
Sélectionnez

public ChatForm(final String componentName) {
  super(componentName, new CompoundPropertyModel(new Message()), null);
  add(new TextField("nick"));
  add(new TextField("message"));
}

Lors de l'appel du constructeur parent de la classe Form nous passons en paramètre le nom du composant ainsi qu'un IModel. La documentation de wicket.model.IModel présente les différents types de modèles disponibles mais nous devons ici utiliser un CompoundModel pour le partager en deux composants, le formulaire et la liste. Le CompoundModel prend lui-même en paramètre notre objet modèle. Tous les composants ajoutés au formulaire seront automatiquement liés à l'attribut du modèle possédant le même nom (ainsi le champ nick sera lié à getNick et setNick). Enfin, lorsque le visiteur clique sur le bouton Envoyer du formulaire, la méthode onSubmit() est exécutée.

listing 9
Sélectionnez

public final void onSubmit() {
  Message message = (Message) getModelObject();
  Message newMessage = new Message(message);
  
  messagesListView.modelChanging();
  messagesList.add(0, newMessage);
  messagesListView.modelChanged();

  message.setMessage("")
}

Souvenez-vous que Wicket conserve l'état des composants, et donc leurs modèles, en mémoire. Vous devez donc dupliquer l'objet modèle pour ne pas modifier les valeurs de la liste lors du prochain affichage du formulaire. Cela fait, il ne vous reste qu'à ajouter le message dans la liste messagesList. Les deux appels modelChanging() et modelChanged() permettent de protéger les accès concurrents (souvenez-vous qu'un serveur web est multi threads). La dernière ligne efface le contenu du champ Message lorsque la page est rechargée. Vous constaterez que le contenu du champ Surnom contient toujours ce que l'utilisateur a saisi car Wicket a conservé le même modèle en mémoire. Ces exemples devraient vous convaincre de la simplicité et de l'élégance de l'architecture de Wicket. Vous pouvez vous rendre sur le site http://wicket.sf.net pour consulter les exemples et la documentation.

Image non disponible
De plus en plus d'ouvrages sont consacré au développement simplifié d'applications web Java

Romain Guy

Articles et tutoriels Java
L'essentiel de Java en une heure
L'API java.nio du JDK 1.4
Inversion de contrôle en Java
L'introspection
Le Java Community Process
Conception de tests unitaires avec JUnit
Les Strings se déchaînent
Présentation de SWT
La programmation réseau en Java avec les sockets
Du bon usage de l'héritage et de la composition
Les références et la gestion de la mémoire en Java
Constructeurs et méthodes exportées en Java
Les membres statiques, finaux et non immuables en Java
Les classes et objets immuables en Java
Comprendre et optimiser le Garbage Collector
Les principes de la programmation d'une interface graphique
Les opérateurs binaires en Java
Prenez le contrôle du bureau avec JDIC
Les Java Data Objects (JDO version 1.0.1)
La persistance des données avec Hibernate 2.1.8
Journalisation avec l'API Log4j
Java 5.0 et les types paramétrés
Les annotations de Java 5
Java 1.5 et les types paramétrés
Créer un moteur de recherche avec Lucene
Articles et tutoriels Swing
Threads et performance avec Swing
Rechercher avec style en utilisant Swing
Splash Screen avec Swing et Java3D
Drag & Drop avec style en utilisant Swing
Attendre avec style en utilisant Swing
Mixer Java3D et Swing
Articles et tutoriels Java Web
Redécouvrez le web avec Wicket
Ces textes sont disponibles sous licence Creative Commons Attribution-ShareAlike. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.