IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Tutoriel sur la création d'une application CRUD avec JSF2 (partie 2) : mise en œuvre de PrettyFaces et PrimeFaces


Image non disponible

Dans la première partie du tutoriel, j'avais déjà mis en place le cœur de l'application. Dans cette partie, nous allons aborder son aspect graphique avec la mise en place de JSF2 et PrimeFaces. Nous étudierons par la même occasion la réécriture des URL avec PrettyFaces.

Pour réagir au contenu de cet article, un espace de dialogue vous est proposé sur le forum 3 commentaires Donner une note à l´article (5).

Article lu   fois.

Les deux auteurs

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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

web.xml
Sélectionnez
1.
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 :

faces-config.xml
Sélectionnez
1.
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.

PersonBean
Sélectionnez
1.
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.

pom.xml
Sélectionnez
1.
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.

home.xhtml
Sélectionnez
1.
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>
new_person.xhtml
Sélectionnez
1.
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>
Image non disponible
Image non disponible
Image non disponible

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.

pretty-config.xml
Sélectionnez
1.
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.

PersonBean
Sélectionnez
1.
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 :

Image non disponible
Image non disponible
Image non disponible

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.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Copyright © 2013 PaloIT. Aucune reproduction, même partielle, ne peut être faite de ce site ni 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.