Création d’une application CRUD avec JSF2, Spring, Hibernate, Primefaces et Pretty Faces (partie 2)

 

Dans la première partie du tutoriel, j’avais déjà mis en place la partie coeur de l’application (voir ici). Dans cette partie, nous allons  aborder son aspect graphique avec la mise en place de JSF2, Primefaces. Nous étudierons par la même occasion la réécriture des URL avec PrettyFaces.

POURQUOI  SPRING COMME INJECTEUR DE DEPENDANCES DANS LES BACKING BEANS?

 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.

CONFIGURATION DE WEB.XML

Voici notre fichier 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">
	<!-- 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 tous les URL terminant par .jsf. Des lignes 20 à 29, nous avons déclaré le filtre de prettyfaces qui intercepte tous les URL afin de les réécrire (nous y reviendrons plus tard). Des lignes 34 à 39, nous avons défini deux listener 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é, 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.

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 :


		<?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.

/*
 *   Palo-it  source code:
 */
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";
    }

    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;
    }

}

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 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. A 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.

<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

<!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

<!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>



REECRITURE DES URL 

On peut remarquer qu’on a le 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.

MISE EN PLACE DE PRETTYFACES

Pour mettre en place Pretty Faces, nous allons déclarer le filtre de Pretty Faces dans le fichier web.xml afin d’intercepter toutes les requêtes HTTP et de les traiter. Une fois notre filtre déclaré, nous allons maintenant créer un fichier pretty-config.xml. C’est dans ce fichier que nous allons mettre en place les règles de réécriture des URL.

<?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 Pretty faces.

/*
 *   Palo-it  source code:
 */
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 pretty-faces précédé de “pretty:”. Et maintenant, voici le résultat final :


Références :

Code Sources

Share
Oumar CISSE
Oumar CISSE

12297

Comments

  1. […] Barcamp « Achilles, la persistance objet facile avec Apache Cassandra » Création d’une application CRUD avec JSF2, Spring, Hibernate, Primefaces et Pretty Faces (partie … […]

  2. abdou rabih Says: February 28, 2013 at 1:27 am

    bonsoir,
    merci bien pour ce tutoriel qui va nous aider pour démarrer une application JEE professionelle riche en terme d’outils et d’etapes d’un projet
    moi je vais commencer un application jee avec les memes technologies et j’aimerai bien savoir vos references pour plus de details
    merci bien

  3. Oumar CISSE Oumar CISSE Says: February 28, 2013 at 11:45 am

    Bonjour,

    Merci pour cette remarque. J’ai rajouté des références vers les sites qui m’ont aidé à réaliser ce tutoriel. Et n’hésite pas si tu as des questions

  4. abdou rabih Says: February 28, 2013 at 4:30 pm

    sincerement, et apres plusieurs recherches, je n’est pas vu l’utilité d’utiliser Spring (meme si je veux l’utiliser ) puisque hibernate offre la couche persistance et jsf-primefaces offrent des riches composants et une architecture mvc avec les managed-beans
    qu’est ce que vous en pensez ?

  5. Oumar CISSE Oumar CISSE Says: February 28, 2013 at 5:51 pm

    Hibernate te permet de faire du mapping alors que jsf permet de faire la coordination entre ta couche UI et celle du métier. Maintenant comment tu vas faire la liaison entre ta couche Service, UI et mapping? Si on injecte les objets hibernate directement dans les backing beans. où vas tu mettre les besoins métiers. Ces pourquoi j’ai rajouté cette couche en plus permettant d’implémenter les besoins fonctionnels. Et les liaisons entre les couches, elle sera gérée par Spring via l’injection de dépendance. J’espère que j’ai été clair.

  6. abdou rabih Says: February 28, 2013 at 6:47 pm

    merci pour votre éclaircissement,
    il y a quelques mois j’ai réalise une application web avec jsf-primefaces et hibernate : j’ai crée une couche métier (des classes avec un suffixe helper) : je me suis basé sur cet exemple : http://netbeans.org/kb/docs/web/hibernate-webapp.html
    et je pense que tous était bien lié et organisé et facile à maintenir
    donc je ne suis pas encore convaincu pour l’utilité de Spring 😉

  7. Oumar CISSE Oumar CISSE Says: March 1, 2013 at 11:10 am

    J’ai vu ton exemple et je l’ai relu avec intérêt toute la nuit. Dans son exemple , il y pas de règles métiers mais c’était le cas, où vas tu les gérer ??

  8. abdou rabih Says: March 1, 2013 at 4:50 pm

    effectivement il n y a pas de regles metiers, mais si j’ajoute un autre package appelé metier ou je mettrai les classes metiers qui vont gerer le metier en appelant les classes DAO et qui seront instancié dans les manage-beans : le probleme sera résolu et le code va etre bien organisé et facile a maintenir

  9. Oumar CISSE Oumar CISSE Says: March 1, 2013 at 5:28 pm

    Il y a deux problèmes avec cet approche: la première c’est le jour où tu as envie de changer de composant c’est à dire passer de JSF a une autre tu sera obligé de toucher à tes classes métier car ta couche UI est mélangée avec celle métier. Le second si tu veux un jour faire une version mobile, tu seras aussi obligé d’écrire deux classes métier faisant la même chose (une pour JSF et l’autre pour le mobile). L’approche que j’ai donné ici me permet de garder la partie metier mais de changer seulement la parties UI.

  10. abdou rabih Says: March 1, 2013 at 6:54 pm

    Mes classes métiers sont dans un package à part et contiennent des méthodes qui retournent des objets JAVA bien détermines (des beans et des arrayLists) selon les paramétres de la méthode, et c’est ces méthodes qui seront invoqués dans les managed-beans en leur affectant les paramètres lors de l’initialisation de la vue et aprés des actions des utilisateurs,
    donc les classes métiers ne vont pas être touchées si on ne change que le framework de la vue mais le metier de la vue reste le meme
    seuls les managed-beans qui vont être inutiles et doivent être remplacé selon le nouveau framework utilisé
    et c’est la meme chose pour le mobile

  11. Oumar CISSE Oumar CISSE Says: March 5, 2013 at 10:44 am

    Donc tu n’utilise pas un framework d’injection de dépendance. Tu instancies directement tes classes DAO dans tes classes métier?? Si oui regarde les avantages de l’injection de dépendances Injection de dépendance

  12. abdou rabih Says: March 5, 2013 at 12:20 pm

    je viens de me documenter sur l’utilité de l’injection de dépendance et l’AOP dernièrement et j’ai compris leur utilité surtout pour un projet qui évolue
    c’est vrai il nécessite plus de codage et d’interfaces et de classes et on gagne au niveau organisation et clarté et facilité d’évolution et maintenance
    merci 🙂

  13. La forture Says: March 6, 2013 at 9:24 pm

    Bonjour
    Très bonne exemple
    Serait-il possible d’avoir le source de cet exemple.

  14. Oumar CISSE Oumar CISSE Says: March 8, 2013 at 12:18 pm

    Merci. J’ai mis les sources sur GIT

  15. marylemoigne Says: March 9, 2013 at 3:21 pm

    “Il existe de multiples raisons et parmi elles on peut citer:

    Bonjour en introduction de votre article vous dites
    “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 pour plusieurs applications.’

    Les points que vous exposez ainsi semblent vouloir dire qu’il n’est pas possible ou qu’il ne faut pas combiner JSF et Spring hors le but de vos deux articles et d’en faire la démonstration ce que vous faites avec efficacité. Cependant vous ne répondez pas à la question que vous posez: “POURQUOI COMBINER JSF AVEC SPRING ?” vous est il possible de faire un update à votre article ou un commentaire pour expliquer pourquoi faire une combinaison de ce type?

    une autre petit remarque, vous signalez avoir publié votre code sur github, sans pour autant donner l’adresse du dépot, merci de rémdier à cet oubli via un commentaire ou un update à votre blog

  16. Oumar CISSE Oumar CISSE Says: March 11, 2013 at 10:14 am

    Bonjour

    Merci pour cette remarque. Vous avez parfaitement raison car je pense que je me suis mal exprimé. La question c’est plutôt pourquoi utiliser les beans de Spring à la place des managed Bean de JSF. Je vais corriger ça. Pour les codes sources, il faut cliquer sur code source à la fin des références.

    pourquoi combiner JSF avec Spring :

    Spring est la référence en matiére d’injection de dépendance. Et Contrairement au EJB, Les beans de Spring sont beaucoup plus léger et plus simple à tester. Pas besoin de conteneur pour exécuter.

    Le framework JSF permet de mettre en oeuvre efficacement le développement de vos applications spécifiques :
    JSF dispose de nombreux composants simples ou sophistiqués (à travers les Librairie UI) qui favorisent la réalisation d’applications Web avec une interface ergonomique, efficace et agréable pour les utilisateurs
    En simplifiant l’écriture de l’interface utilisateur, JSF permet de concentrer les efforts sur la problématique métier de l’application, et donc de maximiser la valeur ajoutée produite par les développeurs.
    En constante évolution, JSF offre également des garanties importantes de fiabilité et de nombreuses possibilités d’évolution :
    Framework Java, JSF peut s’appuyer sur le dynamisme de la communauté Java et OpenSource. De nombreux développeurs au travers du monde améliorent constamment la fiabilité de la plateforme et ses fonctionnalités.
    De nombreuses bibliothèques de composants, certaines commerciales mais la plupart open source et de grande qualité, sont disponibles pour compléter les composants fournis en standard avec JSF.

  17. onebegin Says: March 15, 2013 at 1:11 am

    merci pour cette exemple et pour le code source
    seulement un probleme est survenu pour moi lors de l’execution du code source

    dans un premier temps tout est bien passé (file => import => maven => existing maven projects => “votre projet” ) et puisque j’ai le plugin maven installé sur eclipse juno j’ai fais run as => maven build => tomcat run
    => le projet est bien lancé
    mais lorsque j’ouvre le lien sur la page web alors une datatable primefaces vides et ces deux lignes s’ajoutent sur la console d’eclipse :
    mars 15, 2013 12:02:04 AM com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder findClasses
    WARNING: Cannot find classes folder: /WEB-INF/classes/

    et le boutton create new user ne marche pas

    avez vous une idée

    merci bien

  18. Oumar CISSE Oumar CISSE Says: March 18, 2013 at 10:43 am

    Bonjour,

    désolé pour cette réponse tardive. regarde dans ton target si tu as le dossier /WEB-INF/classes/. Si tu ne l’as pas recompile. Si tu l’as regarde dans quel dossier pointe ton tomcat et ton classePath aussi

  19. Thanks for sharing your thoughts on hibernate. Regards

  20. I do accept as true with all of the concepts you have presented
    on your post. They’re really convincing and will definitely work.

    Nonetheless, the posts are very brief for starters.
    May just you please lengthen them a bit from next time?

    Thanks for the post.

Leave a Reply

Your email address will not be published. Required fields are marked *