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.
À 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.
<?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.
À 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.
L'application utilise un bean standard JSF pour stocker les valeurs et lancer les actions.
@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.
<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 ».
<dependency>
<groupId>
com.ocpsoft</groupId>
<artifactId>
prettyfaces-jsf2</artifactId>
<version>
3.3.2</version>
</dependency>
Puis relancer une installation 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.
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.
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 ».
<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 ».
<?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.
<?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 ».
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 ».
<?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.
<?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 ».
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.
<?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.
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 ».
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.
<?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.
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.
<?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.
<?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.
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.
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.
<?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…
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.code final
Retrouvez mes autres tutoriels rapides sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articlesTutoriels
Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : 6 commentaires
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.
La seconde méthode de calcul utilise le nombre d'or et la racine de 5.
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.
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
Retrouvez mes autres tutoriels sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articlesTutoriels
Ajoutez-moi à vos contacts à l'aide du QR Code suivant :
VI-C. Les fichiers importants en entier▲
<?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>
<?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>
<?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.
<?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 :
<
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.
<?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>
...