I. Justification de Spring comme injecteur de dépendances▲
Cette question mérite d'être posée dans la mesure où, comme Spring, JSF permet de faire l'injection de dépendances. Il existe de multiples raisons et parmi elles on peut citer :
- mieux vaut avoir un seul framework d'IOC que deux ;
- Spring est plus mature et plus complète que JSF en matière d'injection de dépendances ;
- possibilité d'utiliser les beans de services comme des backing beans (beans JSF) ;
- possibilité d'utiliser les mêmes composants (beans) pour plusieurs applications.
II. Configuration de web.xml▲
Voici notre fichier web.xml
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
<?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"
>
<!-- JSF -->
<context-param>
<param-name>
javax.faces.PROJECT_STAGE</param-name>
<param-value>
Development</param-value>
</context-param>
<servlet>
<servlet-name>
facesServlet</servlet-name>
<servlet-class>
javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
facesServlet</servlet-name>
<url-pattern>
*.jsf</url-pattern>
</servlet-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>
<!-- SPRING -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Lets the bean definition file specify scopes of request and session. -->
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<welcome-file-list>
<welcome-file>
index.html</welcome-file>
</welcome-file-list>
</web-app>
Nous allons nous attarder un peu sur ce fichier afin que vous puissiez comprendre la configuration. De la ligne 11 à la ligne 19, nous avons défini une Servlet, celle de JSF qui intercepte toutes les URL terminant par .jsf. Des lignes 20 à 29, nous avons déclaré le filtre de PrettyFaces qui intercepte toutes les URL afin de les réécrire (nous y reviendrons plus tard). Des lignes 34 à 39, nous avons défini deux listeners de Spring. Nous allons expliquer le rôle de chaque listener :
- ContextLoaderListener : il est lancé lors du démarrage de l'application. C'est lui qui instancie l'applicationContext en se basant sur le fichier WEB-INF/applicationContext.xml. Une fois instanciée, la référence de l'applicationContext est placée dans ServletContext. On peut ainsi y accéder grâce à la méthode getRequiredWebApplicationContext de WebApplicationContextUtils.
- RequestContextListener : en plus des scopes classiques de Spring, ce listener nous permet d'avoir les scopes Request et Sessions.
III. Configuration de faces-config.xml▲
D'habitude c'est JSF qui se charge de la gestion des beans. Nous allons maintenant déléguer cette gestion à Spring. Pour cela, nous allons configurer notre fichier faces-config.xml comme suit :
2.
3.
4.
5.
6.
7.
8.
9.
<?xml version='1.0' encoding='UTF-8'?>
<faces-config
xmlns
=
"http://java.sun.com/xml/ns/javaee"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi
:
schemaLocation
=
"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version
=
"2.0"
>
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
</faces-config>
Nous allons maintenant mettre en place notre classe PersonBean qui sera un composant Spring.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
package
com.paloit.bean;
import
java.util.List;
import
javax.faces.event.ActionEvent;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.context.annotation.Scope;
import
org.springframework.stereotype.Component;
import
com.paloit.entities.Person;
import
com.paloit.manager.PersonManager;
/**
* PersonBean
*
*
@author
Palo-IT
*
@since
22 févr. 2013
*/
@Component
@Scope
public
class
PersonBean {
// =========================================================================
// ATTRIBUTES
// =========================================================================
private
Person person;
private
PersonManager manager;
// =========================================================================
// CONSTRUCTORS
// =========================================================================
public
PersonBean
(
) {
}
// =========================================================================
// METHODS
// =========================================================================
public
String savePerson
(
) {
manager.savePerson
(
person);
return
"home"
;
}
public
void
deletePerson
(
ActionEvent event) {
manager.deletePerson
(
person);
}
public
String editPerson
(
){
return
"new_person"
;
}
public
String newPerson
(
){
reinit
(
);
return
"new_personr"
;
}
person =
new
Person
(
);
}
// =========================================================================
// OVERRIDES
// =========================================================================
// =========================================================================
// GETTERS & SETTERS
// =========================================================================
public
List<
Person>
getAllPersons
(
) {
return
manager.getAllPersons
(
);
}
public
Person getPerson
(
) {
return
person;
}
public
void
setPerson
(
Person person) {
this
.person =
person;
}
@Autowired
public
void
setManager
(
PersonManager manager) {
this
.manager =
manager;
}
}
IV. Mise en place de PrimeFaces▲
JSF est un framework puissant et simple permettant de mettre en place des applications Web en se basant sur le Model MVC2. Cependant, JSF ne dispose que de peu de composants de base, laissant ainsi le soin au développeur d'utiliser des librairies ou d'implémenter ses propres composants. Parmi les librairies, PrimeFaces a particulièrement retenu mon attention. En effet, son intérêt principal réside dans sa simplicité, la richesse et la qualité de ses composants. À cela s'ajoute la quantité de composants mis à la disposition du développeur (plus de 100 composants). Contrairement aux autres librairies de composants comme RicheFaces, ICEfaces, Trinidad, l'intégration de PrimeFaces se fait sans configuration. En effet, il suffit d'ajouter ses dépendances dans le projet. Pour ce faire, il faut télécharger primefaces-x-y-z.jar et le placer dans le dossier lib ou à travers Maven en ajoutant la dépendance dans le fichier pom.xml.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
<repository>
<id>
prime-repo</id>
<name>
PrimeFaces Maven Repository</name>
<url>
http://repository.primefaces.org</url>
</repository>
<dependency>
<groupId>
org.primefaces</groupId>
<artifactId>
primefaces</artifactId>
<version>
3.5</version>
</dependency>
Nous allons mettre en place notre page xhtml. Pour cela, nous aurons deux pages. La première (home.xhtml) permettra d'afficher la liste des personnes présentes en base alors que la deuxième (user.xhtml) servira à créer ou mettre à jour une personne.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<html
xmlns
=
"http://www.w3.org/1999/xhtml"
xmlns
:
h
=
"http://java.sun.com/jsf/html"
xmlns
:
f
=
"http://java.sun.com/jsf/core"
xmlns
:
p
=
"http://primefaces.org/ui"
>
<
h
:
head>
<title></title>
<link
href
=
"./css/styles.css"
rel
=
"stylesheet"
type
=
"text/css"
/>
</
h
:
head>
<
h
:
body>
<
h
:
form
id
=
"form"
>
<
p
:
outputPanel
id
=
"users"
>
<
p
:
dataTable
id
=
"usersTable"
value
=
"#{personBean.allPersons}"
var
=
"person"
>
<
p
:
column>
<
f
:
facet
name
=
"header"
>
<
h
:
outputText
value
=
"Name"
/>
</
f
:
facet>
<
p
:
commandLink
action
=
"#{personBean.editPerson}"
>
<
h
:
outputText
value
=
"#{person.name}"
/>
<
f
:
setPropertyActionListener
target
=
"#{personBean.person}"
value
=
"#{person}"
/>
</
p
:
commandLink>
</
p
:
column>
<
p
:
column>
<
f
:
facet
name
=
"header"
>
<
h
:
outputText
value
=
"Age"
/>
</
f
:
facet>
<
p
:
commandLink
action
=
"#{personBean.editPerson}"
>
<
h
:
outputText
value
=
"#{person.age}"
/>
<
f
:
setPropertyActionListener
target
=
"#{personBean.person}"
value
=
"#{person}"
/>
</
p
:
commandLink>
</
p
:
column>
</
p
:
dataTable>
</
p
:
outputPanel>
<
p
:
commandButton
value
=
"Create New User"
action
=
"#{personBean.newPerson}"
/>
</
h
:
form>
</
h
:
body>
</html>
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<html
xmlns
=
"http://www.w3.org/1999/xhtml"
xmlns
:
h
=
"http://java.sun.com/jsf/html"
xmlns
:
f
=
"http://java.sun.com/jsf/core"
xmlns
:
p
=
"http://primefaces.org/ui"
>
<
h
:
head>
<title></title>
<link
href
=
"./css/styles.css"
rel
=
"stylesheet"
type
=
"text/css"
/>
</
h
:
head>
<
h
:
body>
<
h
:
form
id
=
"form"
>
<
p
:
growl
id
=
"msgs"
/>
<
p
:
panel
header
=
"Create a new User"
>
<
h
:
panelGrid
columns
=
"2"
id
=
"grid"
>
<
h
:
outputLabel
value
=
"Name : *"
for
=
"txt_name"
/>
<
p
:
inputText
id
=
"txt_name"
value
=
"#{personBean.person.name}"
required
=
"true"
/>
<
h
:
outputLabel
value
=
"age : *"
for
=
"txt_age"
/>
<
p
:
inputText
id
=
"txt_age"
required
=
"true"
value
=
"#{personBean.person.age}"
/>
<
p
:
commandButton
value
=
"Reset"
type
=
"reset"
/>
<
p
:
commandButton
id
=
"btn_add"
value
=
"Add"
action
=
"#{personBean.savePerson}"
/>
</
h
:
panelGrid>
</
p
:
panel>
</
h
:
form>
</
h
:
body>
</html>
V. Réécriture des URL▲
On peut remarquer qu'on a la même URL pour créer et pour éditer une personne. Ceci est normal, car nous utilisons la même page pour les deux actions. Nous allons utiliser deux URL pour différencier les deux actions. Pour ce faire, nous utiliserons PrettyFaces.
VI. Mise en place de PrettyFaces▲
Pour mettre en place PrettyFaces, nous allons déclarer le filtre de PrettyFaces dans le fichier web.xml afin d'intercepter toutes les requêtes HTTP et de les traiter. Une fois notre filtre déclaré, nous créons un fichier pretty-config.xml. C'est dans ce fichier que nous allons mettre en place les règles de réécriture des URL.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
<?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
=
"/"
/>
<view-id
value
=
"home.jsf"
/>
</url-mapping>
<url-mapping
id
=
"new_user"
>
<pattern
value
=
"/new_user"
/>
<view-id
value
=
"/new_person.jsf"
/>
</url-mapping>
<url-mapping
id
=
"edit"
>
<pattern
value
=
"/edit/#{personBean.person.name}"
/>
<view-id
value
=
"/new_person.jsf"
/>
</url-mapping>
</pretty-config>
L'URL pour éditer une personne est maintenant : /edit/nom de la personne et pour créer une nouvelle personne /new_user
Nous allons maintenant modifier notre classe PersonBean afin de l'adapter avec notre configuration PrettyFaces.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
package
com.paloit.bean;
import
java.util.List;
import
javax.faces.event.ActionEvent;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.context.annotation.Scope;
import
org.springframework.stereotype.Component;
import
com.paloit.entities.Person;
import
com.paloit.manager.PersonManager;
/**
* PersonBean
*
*
@author
Palo-IT
*
@since
22 févr. 2013
*/
@Component
@Scope
public
class
PersonBean {
// =========================================================================
// ATTRIBUTES
// =========================================================================
private
Person person;
private
PersonManager manager;
// =========================================================================
// CONSTRUCTORS
// =========================================================================
public
PersonBean
(
) {
}
// =========================================================================
// METHODS
// =========================================================================
public
String savePerson
(
) {
manager.savePerson
(
person);
return
"pretty:home"
;
}
public
void
deletePerson
(
ActionEvent event) {
manager.deletePerson
(
person);
}
public
String editPerson
(
){
return
"pretty:edit"
;
}
public
String newPerson
(
){
reinit
(
);
return
"pretty:new_user"
;
}
public
void
reinit
(
) {
person =
new
Person
(
);
}
// =========================================================================
// OVERRIDES
// =========================================================================
// =========================================================================
// GETTERS & SETTERS
// =========================================================================
public
List<
Person>
getAllPersons
(
) {
return
manager.getAllPersons
(
);
}
public
Person getPerson
(
) {
return
person;
}
public
void
setPerson
(
Person person) {
this
.person =
person;
}
@Autowired
public
void
setManager
(
PersonManager manager) {
this
.manager =
manager;
}
}
Comme vous le voyez, les méthodes ne renvoient plus le nom de la page mais plutôt l'ID défini dans le fichier de mapping des URL de PrettyFaces précédé de « pretty: ». Et maintenant, voici le résultat final :
VII. Remerciements▲
Cet article a été publié avec l'aimable autorisation de la société PaloITPaloIT.
Nous tenons à remercier f-leb pour sa relecture orthographique attentive de cet article et Mickael Baron pour la mise au gabarit.