RichFaces : Filtrer et trier une DataTable

Après avoir installé RichFaces, je me suis lancé dans la rédaction d'une page d'exemple, histoire d'apprendre le fonctionnement de cette librairie qui semble bien intéressante.

Le but de cette page d'exemple est de mettre en place une DataTable, avec fonctionnalités de tri et de filtres. Toutes ces fonctionnalités utiliseront de l'Ajax, et il ne sera donc pas nécéssaire de recharger la page afin de voir les changements.

Les contacts contenus dans notre DataTable devront être triés par nom de famille par défaut. Il sera également possible pour l'utilisateur de changer l'ordre de tri (croissant, décroissant), ainsi que la propriété servant à effectuer ce tri (prénom, nom, ou adresse mail).

Enfin, pour le filtre, nous aurons un champ de texte qui limitera la liste aux contacts :
  • Dont le nom commence par la requête
  • Dont le prénom commence par la requête
  • Dont l'adresse mail contient la requête

Mise en place d'une Rich DataTable

Afin de commencer notre page d'exemple, nous allons créer une classe Contact, qui aura pour vocation de contenir les données. Cette classe est un JavaBean, et possède donc les caractérisques suivantes :
  • Les propriétés doivent être privées
  • Chaque propriété doit avoir des accésseurs (getters et setters) publics
  • La classe doit avoir un constructeur par défaut
  • La classe doit implémenter Serializable


Nous allons donc créer notre classe Contact avec les propriétés firstName, lastName et mailAddress :

La seconde étape sera de créer un managed bean JSF, qui nous renvera une liste de contacts d'exemple :

Et enfin, dernière étape, nous allons créer notre Rich DataTable, basique pour l'instant, capable d'afficher ces données :

Nous avons dans l'exemple de code précédent créé une Rich DataTable. Le code ressemble à celui d'une DataTable classique, la seule différence étant l'utilisation de la taglib RichFaces au lieu de la taglib standard.

Rajout des fonctionnalités de tri

L'ajout du tri dans une Rich DataTable est très facile. La balise <rich:column /> possède un attribut sortBy, qui permet de spécifier la propriété qui sera utilisée pour trier la colonne concernée.

Notre code précédent ressemble donc désormais à ceci :
L'exécution de ce code nous montre que sur chaque colonne, RichFaces a rajouté des boutons permettant à l'utilisateur de choisir quelle colonne sera utilisée pour trier les données, et de choisir l'ordre de tri.

Il est également possible de donner un ordre de tri par défaut à notre DataTable. Pour celà, nous allons utiliser l'attribut sortOrder de notre balise <rich:column /> :
Ainsi, au lancement de la page, les contacts seront triés par ordre alphabétique en fonction de leur nom de famille. Il sera également possible pour l'utilisateur de changer la propriété servant à faire le tri (et de choisir le prénom, ou l'adresse mail). L'utilisateur aura également la possibilité de changer l'ordre de tri (croissant, décroissant).

Filtrer les données

Le filtrage des données à l'intérieur d'une DataTable passe par plusieurs étapes :
  • Il faut commencer par créer un champ de texte, permettant à l'utilisateur de rentrer la requête sur laquelle nous allons nous baser pour filtrer les entrées
  • Il faudra ensuite créer une méthode permettant de filter chacune de nos entrées. Cette méthode prends en paramètre l'objet à filter, et renvoie un booléen indiquant si l'objet doit être affiché
  • Enfin, il faudra que notre DataTable soit mise à jour à chaque modification de la requête

La première étape est donc de créer notre champ de texte. Il s'agit d'un simple champ de texte JSF (<h:inputText />) que nous allons lier à une propriété d'un managed bean : Puis le code JSP correspondant :
Seconde étape, toujours dans notre managed bean, nous allons créer une méthode filtrant les objets de type Contact en fonction de la requête qui nous est envoyée par le champ de saisie. Dans l'exemple ci dessous, la méthode doFilter prends en paramètre l'objet que nous allons devoir filtrer (dans notre cas, on objet de type Contact), et dois renvoyer true si le contact doit être affiché, false sinon : Nous allons également dire à notre DataTable d'utiliser cette méthode afin de filtrer les entrées à afficher :
Enfin, dernière étape, nous allons préciser à RichFaces que notre champ de texte doit automatiquement rafraîchir, en Ajax, notre DataTable afin que les données soient de nouveau filtrées, avec la nouvelle requête : La balise <a4j:support /> permet, entre autres, de mettre rafraîchir un composant. Elle prends 3 paramètres :
  • event : l'évènement JavaScript qui devra déclencher le rafraîchissement
  • reRender : le composant à rafraîchir
  • requestDelay : permet de spécifier un délai entre la requête et le refraîchissement du composant

A chaque fois que la valeur du champ de texte est modifiée, la nouvelle valeur est envoyé dans notre managed bean, et notre DataTable est raffraîchie. Ainsi, le tableau va de nouveau être filtré, et notre méthode va permettre d'éliminer certains résultats de notre tableau.


Nous avons donc vu un premier exemple de fonctionnalité Ajax qu'il est possible de réaliser grâce à RichFaces. Une DataTable avec fonctionnalités de tri et de filtre, qui se rafraîchit sans recharger la page.

Les sources du projet NetBeans de cet article sont disponnibles ici.

Permalink  |  Commentaires (2)

RichFaces

Je continue dans ma recherche de librairie de composants pour JSF. J'avais déjà testé ICEFaces, mais elle ne me satisfaisait pas. Trop de changement au niveau du cycle de vie de JSF à mon goût.

J'ai testé aujourd'hui une nouvelle librairie, qui à l'air de s'intégrer parfaitement à JSF. Très peu de changements dans le cycle de vie JSF, beaucoup de composants, dont la plupart en Ajax. Il s'agit de RichFaces.

L'installation, comparée à celle de ICEFaces, est très simple. Quelques librairies, quelques dépendances (BeanUtils, Collections, Digester, Commons Log). La seule configuration nécessaire est la déclaration d'un filtre dans le fichier web.xml :
Il ne reste plus qu'à tester la liste assez imposante de composants proposés :)

Permalink  |  Commentaires (0)

Système d'inclusion en JSF

Pour éviter les erreurs, voici un rapide rappel pour faire de l'inclusion de pages en JSF. Cet article contient un exemple de code classique, puis quelques points à ne pas oublier pour que tout se passe bien.

Le but de cet exemple sera d'avoir une page index.jsp qui inclue une page content.jsp.

index.jsp

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>

<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>JSP Page</title>
    </head>
    <body>
        <f:view>
            <f:subview id="content">
                <jsp:include page="content.jsp" flush="false" />
            </f:subview>
        </f:view>
    </body>
</html>

content.jsp

<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<h:outputText value="Ceci est le contenu !" />

Points importants

Il existe quelques règles assez importantes pour que ce système d'inclusion de page marche correctement :
  • Dans la page de base, entourer l'inclusion avec une balise <f:subview />
  • Lors de l'inclusion, penser à mettre l'attribut flush à false. Cet attribut existe sur la plupart des balises permettant l'inclusion de pages.
  • Dans la page de destination, réutiliser les composants JSF directement, sans remettre de balise <f:view />
  • Les taglibs doivent quand à elles être réimportées.

Et voilà le résultat (en HTML) :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>JSP Page</title>
    </head>

    <body>
        Ceci est le contenu !
    </body>
</html>

Martin en parle également.

Permalink  |  Commentaires (0)

JSF + Tiles, complément

J'avais déjà parlé de coupler les avantages de JSF et Tiles, je reviens aujourd'hui rajouter un petit complément.

J'avais en effet parlé d'un inconvénient majeur, l'impossibilité de lier directement le rendu d'une page à une définition de Tiles.

J'ai découvert aujourd'hui, en lisant le tutoriel sur le site Tiles, que l'API de Tiles fournissait une Servlet qui liait les URL de type *.tiles vers les définitions correspondantes. Par exemple, grâce à cette Servlet, il est par exemple possible d'accéder à une définition nommée index via l'URL /index.tiles.

Après quelques tests, il est possible de coupler cette Servlet avec JSF.

Première étape : Déclarer la Servlet de Tiles

Dans web.xml :
<servlet>
    <servlet-name>Tiles Dispatch Servlet</servlet-name>
    <servlet-class>org.apache.tiles.web.util.TilesDispatchServlet</servlet-class>
</servlet>
...
<servlet-mapping>
    <servlet-name>Tiles Dispatch Servlet</servlet-name>
    <url-pattern>*.tiles</url-pattern>
</servlet-mapping>

Ainsi, toutes les URL *.tiles seront liées aux définitions correspondantes.

Deuxième étape : Configurer JSF pour utiliser les URL *.tiles

La seconde étape va consister à modifier légèrement le comportement de JSF. Par défaut, pour générer la réponse d'une requête index.jsf, le framework va chercher la page index.jsp. Nous allons maintenant lui dire d'aller chercher index.tiles à la place. Requête à laquelle Tiles répondra en introduisant une définition (la définition nommée index dans notre cas).

Il faut pour cela modifier une propriété propre à JSF :
<context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.tiles</param-value>
</context-param>


Et voilà. Il ne reste plus qu'à essayer d'accéder à index.jsf. Le FacesContext est chargé, puis la main est passée à Tiles pour le rendu. Il suffit de déclarer nos JSP et nos définitions comme je l'ai précisé dans la première version.

Permalink  |  Commentaires (0)

JSF + Tiles

Combiner JSF et Tiles, c'est possible !

Voici comment j'ai réussi à mixer les deux :

1. Télécharger Tiles

La page de téléchargement est ici. J'ai utilisé la 2.0.5.

Une fois l'archive téléchargée et extraite, il faut récupérer les fichiers JAR de l'archive (situés à la racine et dans /lib, et les copier dans votre projet.

Ayant créé mon projet sous Glassfish, les librairies de JSF sont directement inclues dans le serveur d'application.

2. Configurer Tiles

La configuration de Tiles se passe en deux étapes. Une première étape consiste à déclarer une Servlet qui sera chargée au démarrage. La seconde étape consistera à déclarer un écouteur. Tout ça dans notre application Web.

Première chose, déclarer la Servlet de Tiles. Dans notre fichier web.xml :
<servlet>
    <servlet-name>TilesServet</servlet-name>
    <servlet-class>org.apache.tiles.web.startup.TilesServlet</servlet-class>
    <init-param>
        <param-name>org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</param-name>
        <param-value>/WEB-INF/tiles-defs.xml</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
</servlet>

Ensuite, l'écouteur (toujours dans web.xml) :
<listener>
    <listener-class>org.apache.tiles.web.startup.TilesListener</listener-class>
</listener>

3. Utiliser Tiles !

Dernière étape : tester l'installation !

On déclare une définition dans notre fichier /WEB-INF/tiles-defs.xml :
<definition name="test" template="/WEB-INF/pages/test.jsp">
</definition>

On crée ensuite le template correspondant à notre définition. S'agissant d'une simple page de test, j'ai fait plutôt simple :
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>

<h2><h:outputText value="Tiles works !" /></h2>

Il ne reste plus qu'à inclure nos définitions dans nos pages JSF :
<%@page contentType="text/html" pageEncoding="UTF-8" %>

<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>

<f:view>
    <f:subview id="test">
        <tiles:insertDefinition name="test" flush="false" />
    </f:subview>
</f:view>

4. Inconvénients et astuces

Tiles est un framework très bien intégré à Struts. Il est possible, en utilisant Struts, de lier directement le rendu d'une action vers une définition Tiles.

Cela n'est malheureusement pas possible en JSF.

Une petite astuce permet cependant de passer à coté de cet inconvénient. Il s'agit de créer une JSP visible (en dehors de /WEB-INF) qui inclue directement la définition à utiliser. Au lieu de créer un lien vers une définition, il faudra alors créer un lien vers la JSP qui inclue cette définition.

Permalink  |  Commentaires (0)