Redécouvrez le web avec Wicket

Romain Guy

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.

- Titre : Redécouvrez le web avec Wicket

- Auteur : Romain Guy

- Parution : 1 janvier 2006

- Mise à jour : 5 mars 2020

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2006 Romain Guy. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Introduction

- Mise en route

- Utilisation des formulaires

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 œuvre. 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 servlets. 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.

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. À 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 utilisateur. Enfin, comme nous allons le voir, Wicket rend très facile la séparation entre la logique et la présentation.

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

<?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

package com.loginmag;

import wicket.protocol.http.WebApplication;

public class HelloWorldApplication extends WebApplication {
public HelloWorldApplication() {
getPages().setHomePage(HelloWorldPage.class);
}
}

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

<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.

Tomcat est un conteneur de servlets 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 celles 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

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.

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

<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 racines, un formulaire chatForm et une liste de messages 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. À 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.

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

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

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.

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

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

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 multithread). 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.

De plus en plus d'ouvrages sont consacrés au développement simplifié d'applications web Java

Romain Guy