De jolies URL dans vos applications Web JSF avec Pretty Faces

Thierry Leriche-Dessirier

Cet article est une introduction à la bibliothèque Pretty Faces qui, associée avec JSF, permet de créer des sites Web dynamiques employant des URL jolies. Commentez ♪

- Titre : De jolies URL dans vos applications Web JSF avec Pretty Faces

- Auteur : Thierry Leriche-Dessirier

- Parution : 14 avril 2012

- Public visé :

- 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 ® 2011 Thierry Leriche-Dessirier. 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

- I. Introduction

- I-A. À propos

- I-B. Avant de commencer

- II. Découverte du projet d'exemple

- II-A. Télécharger, installer et importer le projet d'exemple

- II-B. Ce que fait déjà le projet d'exemple

- III. Action

- III-A. Maven

- III-B. Configuration

- III-C. Adresses simplifiées

- III-D. Adapter les menus

- III-E. Passer des paramètres

- III-F. Des URL jolies malgré les paramètres

- III-G. Réécriture d'URL

- III-H. Liens avec des paramètres

- IV. Conclusions

- V. Remerciements

- VI. Annexes

- VI-A. Précisions sur la page de calcul

- VI-B. Liens

- VI-C. Les fichiers importants en entier

- VI-D. PrettyFaces et Spring Security

I - Introduction

Avoir de belles URL lorsqu'on programme un site Web en Java JEE, surtout avec JSF, n'est pas une chose aisée. Il faut prendre en compte de nombreux aspects et peu de développeurs aiment s'y confronter. Heureusement, la bibliothèque Pretty Faces simplifie la tâche. C'est ce que nous allons découvrir dans la suite.

I-A - À propos

Découvrir une technologie n'est pas chose facile. En aborder plusieurs d'un coup l'est encore moins. Partant de ce constat, cet article a été écrit pour aller à l'essentiel. Les points importants sont présentés dans le corps de l'article et les éléments secondaires sont expliqués en annexes.

I-B - Avant de commencer

Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :

- Java JDK 1.6.0_24-b07 ;

- Eclipse Indigo 3.7 JEE 64b ;

- Maven 3.0.3 ;

- Tomcat 6.0.29 64b ;

- Pretty Faces 3.3.2.

II - Découverte du projet d'exemple

II-A - Télécharger, installer et importer le projet d'exemple

Pour commencer, je vous propose de télécharger le fichier Zip « fibowebapp1.zip », contenant un projet Java-Maven d'exemple (une mini webapp) qui va nous servir de support visuel pour les fonctionnalités présentées dans la suite de cet article.

Compilez le projet d'exemple et importez-le dans Eclipse (comme expliqué dans le tutoriel « Importer un projet Maven dans Eclipse en 5 minutes ») ou dans l'IDE de votre choix.

Installez ensuite la webapp dans le serveur d'application de votre choix, par exemple Tomcat 6, ce que vous pouvez faire directement depuis Eclipse.

Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexes) et de faire confiance aux captures d'écran.

II-B - Ce que fait déjà le projet d'exemple

Le projet d'exemple est une petite webapp permettant de calculer plusieurs fonctions mathématiques célèbres. Cette application Web n'a rien de très complexe. Elle utilise le framework Web JSF, incluse dans Java. Les fonctionnalités (calcul de la suite de Fibonacci et du factoriel) servent uniquement d'illustration.

Accueil

À partir du menu, on peut aller sur la page qui nous intéresse, permettant de calculer la suite de Fibonacci. Cette page est située dans le sous-dossier « math » de l'application. Le code source du menu doit donc bien spécifier ce chemin.

menu.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">

<div id="menus">
<h:link value="Fibonacci" outcome="/math/fibonacci.jsf" /> <br/>
<h:link value="Factoriel" outcome="/math/factoriel.jsf" /> <br/>
</div>

</ui:composition>

L'URL (adresse « http://…/fibowebapp/math/fibonacci.jsf ») de la page fait donc apparaitre le nom du sous-dossier (« math »). Ce n'est ni très joli, ni très pratique, ni très sécurisé, ni très performant du point de vue de l'indexation dans les moteurs de recherche, etc. Et c'est sans parler de l'extension « .jsf » qui est inutile du point de vue de l'utilisateur et donne des informations confidentielles.

Formulaire de calcul de la suite de Fibonacci

À la place de l'URL « http://…/fibowebapp/math/fibonacci.jsf »), on préfèrerait avoir une adresse comme « http://…/fibowebapp/fibonacci », par exemple, non polluée par des détails techniques qui n'intéressent pas l'utilisateur.

Quand on clique sur le bouton « Calculer », après avoir choisi un rang, on reste sur la même page. L'URL ne change pas, mais le contenu de la page est rafraichi.

Suite de Fibonacci au rang 15

L'application utilise un bean standard JSF pour stocker les valeurs et lancer les actions.

FiboBean.java

@ManagedBean(name = "fiboBean")
public class FiboBean {

private Integer rang;
private Long valeur;

// Service singleton qui realise le calcul.
private final FiboService fiboService = FiboService.getInstance();

public void calculer() {
valeur = fiboService.calculerFibonacci(rang);
...
}

// + getters/setters
...

Quant à la page, elle est également très simple.

fibonacci.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jsp/jstl/core"
template="/template.xhtml">
<ui:define name="mainContent">
<div id="content">
<h1>Fibonacci</h1>
<h:form>
Rang :

<h:selectOneMenu id="fiboselect" value="#{fiboBean.rang}">
<c:forEach var="entry" begin="1" end="90">
<f:selectItem itemLabel="#{entry}" itemValue="#{entry}"/>
</c:forEach>
</h:selectOneMenu>

<h:commandButton id="fibobutton" value="Calculer" action="#{fiboBean.calculer}" />

<c:if test="#{fiboBean.valeur ne null}">
La valeur de la suite de Fibonacci pour le rang <b>#{fiboBean.rang}</b> est <b>#{fiboBean.valeur}</b>.
</c:if>
...
</h:form>
</div>
</ui:define>
</ui:composition>

III - Action

III-A - Maven

Durée estimée : 1 minute.

Pour utiliser Pretty Faces, il faut ajouter une dépendance dans le fichier « pom.xml ».

Dépendance dans le pom.xml

<dependency>
<groupId>com.ocpsoft</groupId>
<artifactId>prettyfaces-jsf2</artifactId>
<version>3.3.2</version>
</dependency>

Puis relancer une installation Maven.

Commande Maven

mvn clean install eclipse:eclipse

En fonction des éléments déjà présents sur le disque dur, le résultat de l'installation Maven devrait ressembler à la trace suivante.

Commande Maven

C:\...\fibowebapp>mvn clean install eclipse:eclipse

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building fibowebapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.025s
[INFO] Finished at: Thu Apr 05 20:59:22 CEST 2012
[INFO] Final Memory: 10M/53M
[INFO] ------------------------------------------------------------------------

On doit ensuite faire un refresh (touche F5) dans Eclipse pour faire apparaitre Pretty Faces dans la liste des bibliothèques référencées.

Pretty Faces dans Eclipse

III-B - Configuration

Durée estimée : 2 minutes.

La bibliothèque Pretty Faces est livrée avec un filtre qu'on doit référencer dans la webapp. Pour cela, il faut modifier le fichier « web.xml ».

Filtre de Pretty Faces dans web.xml

<filter>
<filter-name>Pretty Filter</filter-name>
<filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Pretty Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

La balise « filter-mapping » indique, ici, que toutes les requêtes doivent passer par le filtre de Pretty Faces.

Il faut ensuite créer un fichier nommé « pretty-config.xml » dans le dossier « WEB-INF », juste à côté du fichier « web.wml ». Dans un premier temps, on va se contenter de créer un fichier « vide ».

pretty-config.xml vide

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.2
http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.2.xsd">

</pretty-config>

À ce stade, quand on relance la webapp, on ne doit constater aucun changement de comportement.

III-C - Adresses simplifiées

Durée estimée : 1 minute.

Les URL utilisées sont relativement laides, mais nous allons y remédier immédiatement. Pour cela, nous allons configurer le fichier « pretty-config.xml », en ajoutant des entrées pour chaque page.

pretty-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.2
http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.2.xsd">

<url-mapping id="home">
<pattern value="/home" />
<view-id value="/home.jsf" />
</url-mapping>

<url-mapping id="fibonacci">
<pattern value="/fibo" />
<view-id value="/math/fibonacci.jsf" />
</url-mapping>

<url-mapping id="factoriel">
<pattern value="/fact" />
<view-id value="/math/factoriel.jsf" />
</url-mapping>

</pretty-config>

Il faut relancer le serveur pour que cette modification soit prise en compte.

On peut maintenant accéder à la page de calcul des éléments de la suite de Fibonacci à l'aide de l'URL simplifiée « http://…/fibowebapp/fibo », alors qu'il fallait utiliser l'adresse (moche) « http://…/fibowebapp/math/fibonacci.jsf » avant. On remarque en particulier la disparition de l'extension « .jsf » et de la mention du sous-dossier « math ».

Des URL plus jolies

Pretty Faces accepte des « regex » complexes dans ses mappings.

III-D - Adapter les menus

Durée estimée : 1 minute.

On constate que les menus continuent de fonctionner alors qu'on ne les a pas encore modifiés et qu'ils conduisent vers les jolies URL et non vers les anciennes versions. Cela vient du fait qu'on utilisait les balises JSF. Ça n'aurait pas été le cas si on avait utilisé les balises HTML classiques.

On va maintenant utiliser la « taglib » (ensemble de balises) de Pretty Faces pour adapter les menus. Ça nous permettra, plus tard, de passer des paramètres. Pour cela, il faut déclarer un nouveau « xmlns » et employer le tag « pretty:link ».

menu.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:pretty="http://ocpsoft.com/prettyfaces">

<div id="menus">

<!--
<h:link value="Fibonacci" outcome="/math/fibonacci.jsf" />
<h:link value="Factoriel" outcome="/math/factoriel.jsf" />
-->

<pretty:link mappingId="fibonacci">
Fibonacci
</pretty:link>

<pretty:link mappingId="factoriel">
Factoriel
</pretty:link>

</div>

</ui:composition>

L'attribut « mappingId » de la balise « pretty:link » (dans le menu) fait référence à la valeur de l'attribut « id »de la balise « url-mapping » (dans la config).

III-E - Passer des paramètres

Durée estimée : 2 minutes.

Pour l'instant, on est obligé de passer par le menu et de choisir un rang dans la liste déroulante, puis de cliquer sur le bouton « Calculer » pour avoir la valeur d'un membre de la suite de Fibonacci. On voudrait avoir ce résultat directement, en passant un paramètre dans l'URL. Cela se fait classiquement à l'aide d'une adresse comme « http://…/fibowebapp/fibo?r=12 ». Il faut bien entendu programmer la gestion des paramètres et les injecter dans les beans. Avec Pretty Faces, cela ne prend que quelques secondes.

pretty-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2" ...>

...

<url-mapping id="fibonacci">
<pattern value="/fibo" />
<view-id value="/math/fibonacci.jsf" />
<query-param name="r">#{fiboBean.rang}</query-param>
</url-mapping>

...

</pretty-config>

Lorsqu'on demande l'adresse « http://…/fibowebapp/fibo?r=12 », on constate que le rang est déjà sélectionné à « 12 ».

Rang présélectionné

Toutefois, on voudrait aussi que le calcul soit déjà réalisé lors de l'affichage de la page. Pretty Faces permet de lancer directement une méthode lors d'un appel.

pretty-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2" ...>

...

<url-mapping id="fibonacci">
<pattern value="/fibo" />
<view-id value="/math/fibonacci.jsf" />
<query-param name="r">#{fiboBean.rang}</query-param>
<action>#{fiboBean.calculer}</action>
</url-mapping>

...

</pretty-config>

Maintenant, quand on demande « http://…/fibowebapp/fibo?r=9 », on a bien la valeur déjà calculée.

Rang présélectionné et calcul effectué

Bien entendu, si le paramètre « r » n'est pas spécifié dans l'URL, ça va tout de même vers la bonne page, mais sans spécifier de valeur pour le rang. Dans notre cas, il faudra bien penser à donner une valeur par défaut au rang dans le bean ou vérifier que le rang n'est pas « null » pour éviter une « NullPointerException ».

pretty-config.xml

public class FiboBean {
...

public void calculer() {
if(rang == null) {
return;
}

...

III-F - Des URL jolies malgré les paramètres

Durée estimée : 1 minute.

On a déjà un résultat très sympa, mais pas encore assez à mon goût ; ce n'est pas très agréable d'avoir des signes « ? » ou « = » dans les URL. À la place d'une adresse comme « http://…/fibowebapp/fibo?r=14 », on voudrait une URL ressemblant à « http://…/fibowebapp/fibo/14 », comme si la valeur « 14 » était une sous-rubrique de la section « fibo » du site.

Pour avoir de telles adresses, on va ajouter un nouveau mapping dans la configuration de Pretty Faces.

pretty-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2" ...>

...

<!-- Avec des ? -->
<url-mapping id="fibonacci">
<pattern value="/fibo" />
<view-id value="/math/fibonacci.jsf" />
<query-param name="r">#{fiboBean.rang}</query-param>
<action>#{fiboBean.calculer}</action>
</url-mapping>

<!-- Sans les ? -->
<url-mapping id="fibonacci2">
<pattern value="/fibo/#{fiboBean.rang}" />
<view-id value="/math/fibonacci.jsf" />
<action>#{fiboBean.calculer}</action>
</url-mapping>
...

</pretty-config>

On peut donc demander l'adresse « http://…/fibowebapp/fibo/14 », qui est beaucoup plus jolie et beaucoup plus efficace dans le cadre du référencement sur les moteurs de recherche.

URL comme une sous-section

La bibliothèque Pretty Faces ne limite pas le nombre de paramètres (avec « ?= ») et/ou sous-section à un seul. On peut en utiliser autant qu'on le souhaite (qu'on en a besoin) et on peut mélanger l'utilisation des paramètres et des sous-sections. On peut tout à fait avoir des URL comme « http://…/fibowebapp/fibo/14/fr/blue/15?method=recursif&limit=10 ».

III-G - Réécriture d'URL

Un peu dans le même ordre d'idée, on peut utiliser Pretty Faces avec des jolies URL sur une application qui nécessite des URL avec des paramètres. Par exemple, si l'application est conçue pour fonctionner avec l'adresse laide « http://…/fibowebapp/math/factoriel?number=5 », on peut utiliser Pretty Faces pour employer une l'adresse « http://…/fibowebapp/fact/5 » à la place. C'est tout de même plus sympa, n'est-ce pas ? Cela se fait simplement comme les autres mappings.

pretty-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2" ...>

...

<url-mapping>
<pattern value="/fact/#{number}" />
<view-id>/math/factoriel.jsf</view-id>
</url-mapping>

...

</pretty-config>

La bibliothèque va, ici, comprendre qu'il faut mapper la sous-section identifiée par « #{number} » sur le paramètre « number ». Cela fonctionne comme une simple redirection, sans affecter des variables de bean, contrairement aux exemples des chapitres précédents.

III-H - Liens avec des paramètres

Durée estimée : 1 minute.

L'étape d'après consiste à construire des liens, utilisant la configuration de Pretty Faces, tout en passant des paramètres, mais sans se soucier de les organiser.

À titre d'illustration, nous allons ajouter un nouveau menu.

menu.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:pretty="http://ocpsoft.com/prettyfaces">

<div id="menus">

<pretty:link mappingId="fibonacci">
Fibonacci
</pretty:link>

<pretty:link mappingId="fibonacci2">
<f:param value="10" />
Fibonacci de 10
</pretty:link>

<pretty:link mappingId="factoriel">
Factoriel
</pretty:link>

</div>

</ui:composition>

Après avoir relancé le serveur, on constate que ce nouveau menu conduit bien vers l'adresse « http://…/fibowebapp/fibo/10 » et que le calcul est déjà réalisé lorsqu'on arrive sur la page.

Au dixième rang

Bien entendu, ce paramètre peut être dynamique. À titre d'illustration, disons qu'on souhaite utiliser une valeur par défaut (par exemple à 7), définie dans le bean.

FiboBean.java

public class FiboBean {

private static final Integer DEFAULT_RANG = 7;

public Integer getDefaultRang() {
return DEFAULT_RANG;
}

...

Il ne reste plus qu'à utiliser cette valeur (qui n'est pas forcément une constante) dans le menu.

menu.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:pretty="http://ocpsoft.com/prettyfaces">

<div id="menus">

<pretty:link mappingId="fibonacci2">
<f:param value="#{fiboBean.defaultRang}" />
Fibonacci au rang DEFAULT_RANG
</pretty:link>

...

</div>

</ui:composition>

Sans surprise, le lien fonctionne…

Liens avec un paramètre dynamique

Et voilà…

IV - Conclusions

C'est magique : Pretty Faces permet une navigation plus intelligente et bien plus sexy. Ce petit article n'aborde que les points fondamentaux de la bibliothèque, mais j'ai le sentiment qu'ils couvrent les besoins les plus courants.

Pour en savoir plus, je recommande la lecture de la documentation de Pretty Faces car cette bibliothèque regorge de fonctionnalités. Elle mérite d'être connue et utilisée. Je vous invite également à regarder les autres produits de la société OCPSoft, et en particulier Pretty Time à propos duquel j'écrirai prochainement un article.

Le code final de ce tutoriel est disponible dans le fichier ZIP fibowebapp2.zip.

Retrouvez mes autres tutoriels rapides sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articles

Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : Commentez

V - Remerciements

Je tiens à remercier, en tant qu'auteur de tutoriel, toutes les personnes qui m'ont aidé et soutenu. Je pense tout d'abord à mes collègues qui subissent mes questions au quotidien, mais aussi à mes contacts et amis du Web, dans le domaine de l'informatique ou non, qui m'ont fait part de leurs remarques et critiques. Bien entendu, je n'oublie pas l'équipe de developpez.com qui m'a guidé dans la rédaction de cet article et m'a aidé à le corriger et le faire évoluer, principalement sur le forum.

Plus particulièrement j'adresse mes remerciements à keulkeul et Claude Leloup.

VI - Annexes

VI-A - Précisions sur la page de calcul

En plus de calculer la valeur du membre de la suite de Fibonacci pour le rang choisi, la page calcule tous les éléments de rang inférieur. Le programme utilise deux méthodes de calcul. La première méthode fonctionne à l'aide d'un algorithme récursif. Elle est un peu lente, mais donne des valeurs exactes. La seconde méthode emploie une formule mathématique ayant l'avantage d'être rapide, mais dont la justesse dépend de la précision des constantes utilisées.

Suite de Fibonacci au rang 15

La seconde méthode de calcul utilise le nombre d'or et la racine de 5.

FiboService.java

public class FiboService {

private final static double NOMBRE_OR = 1.61803398874989;
private final static double RACINE_5 = 2.236067977499;

La valeur renvoyée par la méthode de calcul direct dépend de la précision des constantes utilisées. Ici, on constate un écart dès le rang 62, ce qu'on met en avant dans la dernière colonne.

Le calcul direct diverge à partir du rang 62

Ces deux méthodes de calcul ont été présentées dans le tutoriel « 3T en pratique, application au calcul de la suite de Fibonnaci, en 5 minutes », disponible sur Developpez.com.

VI-B - Liens

Le site Web de Pretty Faces est disponible à l'adresse http://ocpsoft.org/prettyfaces

QR Code vers Pretty Faces

Retrouvez mes autres tutoriels sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articles

QR Code vers mes articles

Ajoutez-moi à vos contacts à l'aide du QR Code suivant :

QR Code contenant ma vCard

VI-C - Les fichiers importants en entier

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dvp</groupId>
<artifactId>fibowebapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>

<name>fibowebapp</name>
<description>fibowebapp</description>

<licenses>
<license>
<name>Copyright ©1995-2012 thierryler.com et Copyright ©2012 Developpez.com</name>
<comments>Les sources présentées sur cette page sont libres de droits, et vous pouvez [..] </comments>
</license>
</licenses>

<developers>
<!-- Thierry -->
<developer>
<name>Thierry Leriche-Dessirier</name>
<roles>
<role>Developper</role>
</roles>
<organization>ICAUDA</organization>
</developer>

</developers>

<properties>
<!-- Build -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.6</java.version>
<wtp.version>2.0</wtp.version>

<!-- Test -->
<junit.version>4.10</junit.version>

<!-- Servlet et pages -->
<mojarra.version>2.1.4</mojarra.version>
<jboss-el.version>2.0.1.GA</jboss-el.version>
<jstl.version>1.2</jstl.version>
<servlet-api.version>2.5</servlet-api.version>

<!-- Plugins -->
<maven-compiler-plugin.version>2.3.2</maven-compiler-plugin.version>
<maven-eclipse-plugin.version>2.8</maven-eclipse-plugin.version>
<tomcat-maven-plugin.version>1.1</tomcat-maven-plugin.version>

<!-- Pretty faces -->
<prettyfaces-jsf2.version>3.3.2</prettyfaces-jsf2.version>

</properties>

<dependencyManagement>
<dependencies>

<!-- JSF -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>${mojarra.version}</version>
</dependency>

<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>${mojarra.version}</version>
<scope>compile</scope>
</dependency>

<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>

<!-- Servlet 2.5 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>

<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<!-- pretty faces -->
<dependency>
<groupId>com.ocpsoft</groupId>
<artifactId>prettyfaces-jsf2</artifactId>
<version>${prettyfaces-jsf2.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>

<!-- servlet -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
</dependency>

<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<scope>compile</scope>
</dependency>

<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>

<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>

<!-- pretty faces -->
<dependency>
<groupId>com.ocpsoft</groupId>
<artifactId>prettyfaces-jsf2</artifactId>
</dependency>
</dependencies>

<build>
<finalName>fibowebapp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>${maven-eclipse-plugin.version}</version>
<configuration>
<wtpversion>${wtp.version}</wtpversion>
<source>${java.version}</source>
<target>${java.version}</target>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>

<!-- Tomcat plugin for embedded tomcat -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>${tomcat-maven-plugin.version}</version>
<configuration>
<path>/${project.build.finalName}</path>
</configuration>
</plugin>
</plugins>
</build>

</project>

pretty-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.2
http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.2.xsd">

<url-mapping id="home">
<pattern value="/home" />
<view-id value="/home.jsf" />
</url-mapping>

<url-mapping id="fibonacci">
<pattern value="/fibo" />
<view-id value="/math/fibonacci.jsf" />
<query-param name="r">#{fiboBean.rang}</query-param>
<action>#{fiboBean.calculer}</action>
</url-mapping>

<url-mapping id="fibonacci2">
<pattern value="/fibo/#{fiboBean.rang}" />
<view-id value="/math/fibonacci.jsf" />
<action>#{fiboBean.calculer}</action>
</url-mapping>

<url-mapping id="factoriel">
<pattern value="/fact" />
<view-id value="/math/factoriel.jsf" />
</url-mapping>

</pretty-config>

menu.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:pretty="http://ocpsoft.com/prettyfaces">

<div id="menus">

<!--
<h:link value="Fibonacci" outcome="/math/fibonacci.jsf" /> <br/>
<h:link value="Factoriel" outcome="/math/factoriel.jsf" /> <br/>
-->

<pretty:link mappingId="fibonacci">
Fibonacci
</pretty:link><br/>

<pretty:link mappingId="fibonacci2">
<f:param value="10" />
Fibonacci de 10
</pretty:link><br/>

<pretty:link mappingId="fibonacci2">
<f:param value="#{fiboBean.defaultRang}" />
Fibonacci au rang DEFAULT_RANG
</pretty:link><br/>

<pretty:link mappingId="factoriel">
Factoriel
</pretty:link><br/>

</div>
</ui:composition>

VI-D - PrettyFaces et Spring Security

Quand on travaille sur une application Web importante, on a (en général) une page connexion (login) au système. Si celle-ci utilise Spring et plus particulièrement le module Spring-Security, il faut faire attention à deux choses : l'ordre des filtres dans le fichier « web.xml » et la configuration des accès.

Contrairement à ce qu'on pourrait (à tort) croire, il faut que le filtre de Spring-Security soit positionné avant celui de Pretty Faces.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

...

<!-- Spring security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Pretty faces -->
<filter>
<filter-name>Pretty Filter</filter-name>
<filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Pretty Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

...

Pour la page de connexion, il faut bien entendu ajouter un bon mapping. En général, la configuration de Spring Security ressemble à la suivante :

security-app-context.xml (avec uniquement les parties pour le login)

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">

...

<http use-expressions="true">

<!-- login / logout -->
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/login/**" access="permitAll" />
<intercept-url pattern="/accessdenied" access="permitAll" />
<intercept-url pattern="/logout_success" access="permitAll" />
...
<!-- Les autres pages sont refusees -->
<intercept-url pattern="/**" access="denyAll" />

...

<!-- login -->
<form-login login-processing-url="/login_check" login-page="/login"
default-target-url="/home/" authentication-failure-url="/login?login_error=1"
authentication-success-handler-ref="myHandler"  />

<access-denied-handler error-page="/accessdenied" />

<!-- logout -->
<logout invalidate-session="true" logout-success-url="/logout_success"
logout-url="/logout" delete-cookies="JSESSIONID" />

...

Il faut donc avoir une configuration de Pretty faces qui réponde aux URL de connexion.

pretty-config.xml (avec uniquement le mapping pour le login)

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.2
http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.2.xsd">

...

<!-- Login -->
<url-mapping id="login">
<pattern value="/login" />
<view-id value="/login.jsf" />
</url-mapping>

<!-- Access denied -->
<url-mapping id="accessdenied">
<pattern value="/accessdenied" />
<view-id value="/accessdenied.jsf" />
</url-mapping>

<!-- Logout -->
<url-mapping id="logout">
<pattern value="/logout" />
<view-id value="/j_spring_security_logout" />
</url-mapping>

<!-- Logout successed -->
<url-mapping id="logout_success">
<pattern value="/logout_success" />
<view-id value="/logout_success.jsf" />
</url-mapping>

...