Exemple JSF EJB Bean géré_pour_étudiants

publicité
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
Exemple JSF EJB et Bean géré
I.
Enoncé :
Cet exemple est une petite application web proposant deux pages web :
L’une qui affiche un formulaire afin de pouvoir ajouter un livre
(AjoutLivre.xhtml),
L’autre qui énumère tous les livres présents dans la base
(AfficherLivres.xhtml).
Ces deux pages utilisent le bean géré ControleurLivre pour stocker les propriétés
nécessaires et pour la navigation.
En utilisant JPA(Java Persistance API) pour la persistance et EJB pour la logique
métier, tout s’emboîte : le bean géré passe tous les traitements métier à ejbLivre, qui
contient deux méthodes :
L’une pour stocker un livre dans une base de données (AjoutLivre()),
L’autre pour récupérer tous les livres (recupererLivres()).
ejbLivre est un bean de session sans état qui utilise EntityManager pour manipuler
une entité Livre.
Le principe de navigation entre les pages est très simple : lorsqu’un livre est ajouté, on
affiche la liste. Un lien sur la page de la liste permet de revenir ensuite à la page
AjoutLivre.xhtml et de créer un autre livre.
Remarque :
Les différents composants sont assemblés dans un fichier . war et déployés sur une
instance de GlassFish et une base de données Derby.
Si on utilise, par exemple le framework Maven, cette application web doit respecter la
structure de répertoires de ce framework, les classes, les fichiers et les pages web
doivent être placés dans les répertoires suivants :
contient
l’entité Livre, l’EJB
ejbLivre et
le
bean géré ControleurLivre.
src/main/resources contient le fichier persistence.xml utilisé
pour associer l’entité à la base de données.
src/webapp contient les deux pages web AjoutLivre.xhtml et
AfficherLivres.xhtml.
src/main/java
src/webapp/WEB-INF
contient le fichier
web.xml
qui déclare la servlet
FacesServlet.
est un fichier POM (Project Object Model) de Maven décrivant le projet, ses
dépendances et ses extensions.
pom.xml
1
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
II. L’entité Livre :
C’est la mê me ent ité vue en c ours a vec les annotations de mapping, j’ai
juste ajouté deux attributs description (résumé du livre) et id (un identifiant généré
automatiquement) et la requête nommée trouverTousLesLivres, qui permet de récupérer
tous les livres à partir de la base de données.
Entité Livre avec une requête nommée :
Package coursJEE.ejbentity;
@Entity
@NamedQuery(name = "trouverTousLesLivres", query = "SELECT lv FROM Livre lv")
public class Livre {
@Id
@GeneratedValue
private long id;
@Column(nullable = false)
private String titre;
private float prix;
@Column(length = 2000)
private String description;
private String Code;
private int nbrePages;
// Constructeurs, getters, setters
}
Cette entité doit également être associée à un fichier persistence.xml dont le code est
détaillé au dessous.
Le fichier de configuration persistance.xml :
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name= "ExempleUP" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider </provider>
<class>coursJEE.ejbentity.Livre</class>
<properties>
<property name="eclipselink.target-database" value="DERBY"/>
<property name="eclipselink.jdbc.driver" value= "org.apache.derby.jdbc.ClientDriver"/>
<property name="eclipselink.jdbc.url" value="jdbc:derby://localhost:1527/ExempleDB"/>
<property name="eclipselink.jdbc.user" value="Chaouki"/>
<property name="eclipselink.jdbc.password" value="Bayoudhi"/>
</properties>
</persistence-unit>
</persistence>
Ce code permet de configurer la BD « exempleDB » gérée avec le SGBD Relationnel
Derby.
L’unité de persistance ExempleUP définit une connexion JDBC pour la base de
2
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
données Derby nommée ExempleDB. Elle se connecte à cette base sous le compte
utilisateur Chaouki avec le mot de passe Bayoudhi.
Le marqueur <class> demande au fournisseur de persistance de gérer la classe Livre.
Pour que ce code fonctionne, le SGBDR Derby doit s’exécuter sur le port 1527 et les
classes Livre et Main doivent avoir été compilées et déployées avec ce fichier METAINF/persistence.xml.
Grâce à l’API d’EntityManager, notre code manipule des objets de façon orientée
objet, sans instructions SQL ni appel JDBC.
III. L’EJB ejbLivre :
Le code ci-dessous représente un bean de session sans état. Ce dernier obtient par
injection une référence à un gestionnaire d’entités grâce auquel il peut rendre
persistante une entité Livre (avec la méthode CreerLivre()) et récupérer tous les
livres de la base (avec la requête nommée trouverTousLesLivres). Cet EJB n’a besoin
d’aucun descripteur de déploiement.
L’EJB sans état créant et récupérant des Iivres :
@Stateless
public class ejbLivre {
@PersistenceContext(unitName = "chapter10PU")
private EntityManager em;
public List<Livre> recupererLivres() {
//exécute la requête nommée déjà déclarée dans l’entité
Query req = em.CreerNamedQuery("trouverTousLesLivres");
return req.getResultList();
}
public Livre AjoutLivre(Livre unLivre) {
//enregistre le livre dans la base
em.persist(unLivre);
return unLivre;
}
}
IV. Le bean géré ControleurLivre :
L’un des rôles d’un bean géré consiste à interagir avec les autres couches de
l’application (la couche EJB, par exemple) ou à effectuer des validations. Dans le
code du ControleurLivre (le bean géré) il faut ajouter l’annotation
@ManagedBean. Ce bean géré contient deux attributs qui seront utilisés par les
pages :
est la liste des livres récupérés à partir de la base de données,
qui doit s’afficher dans la page AfficherLivres.xhtml.
lstLivres
est l’objet qui sera associé au formulaire (dans la page
AjoutLivre.xhtml) et rendu persistant.
unLivre
3
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
Tout le traitement métier (création et récupération des livres) s’effectue via ejbLivre
(via l’instance unEjbLiv). Le bean géré obtient une référence à l’EJB par
injection, via l’annotation @EJB, et dispose de deux méthodes qui seront invoquées par
les pages :
nouveauLiv() :
Cette méthode n’effectue aucun traitement mais permet
de naviguer vers AjoutLivre.xhtml.
Cette méthode permet de créer un livre en invoquant
l’EJB sans état et en lui passant l’attribut unLivre. Puis elle appelle à
nouveau l’EJB pour obtenir tous les livres de la base et stocke la liste
dans l’attribut lstLivres du bean géré. Ensuite, la méthode renvoie le nom
de la page vers laquelle elle doit naviguer.
Les getters et les setters, sont nécessaires pour chaque attribut (unLivre et lstLivres
dans notre cas).
doCreerLivre() :
Le bean géré ControleurLivre qui invoque I’EJB :
@ManagedBean
@RequestScoped
public class ControleurLivre {
@EJB
private ejbLivre unEjbLiv;
//Les attributs du bean géré
private Livre unLivre = new Livre();
private List<Livre> lstLivres;
public String nouveauLiv() {
return "AjoutLivre.xhtml";
}
public String recupererLivre() {
unLivre = unEjbLiv.CreerLivre(unLivre);
lstLivres = unEjbLiv.recupererLivres();
return "AfficherLivres.xhtml";
}
// Getters, setters
}
V. Les pages .xhtml :
La page AjoutLivre.xhtml
La page AjoutLivre.xhtml dont le code est ci-dessous est un formulaire permettant
à l’utilisateur de saisir les informations nécessaires à la création d’un livre (Code,
titre, prix, description, nombre de pages et illustrations).
4
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
<!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">
<h:head>
<titre>Creer un nouveau Livre</titre>
</h:head>
<h:body>
<h1>Ajouter un Livre</h1>
<hr/>
<h:form>
<table border="0">
<tr>
<td><h:outputLabel value="Code : "/></td>
<td>
<h:inputText value="#{controleurLvire.unLivre.Code}"/>
</td>
</tr>
<tr>
<td><h:outputLabel value="Titre :"/></td>
<td>
<h:inputText value="#{controleurLvire.unLivre.titre}"/>
</td>
</tr>
<tr>
<td><h:outputLabel value="Prix : "/></td>
<td>
<h:inputText value="#{controleurLvire.unLivre.prix}"/>
</td>
</tr>
<tr>
<td><h:outputLabel value="Description : "/></td>
<td><h:inputTextarea value="#{controleurLvire.unLivre.description}"
cols="25" rows="4"/></td>
</tr>
<tr>
<td><h:outputLabel value="Nombre de pages : "/></td>
<td>
<h:inputText value="#{controleurLvire.unLivre.nbrePages}"/>
</td>
</tr>
<tr>
<td><h:outputLabel value="Illustrations : "/></td>
<td><h:selectBooleanCheckbox
value="#{controleurLvire.unLivre.illustrations}"/> </td>
<tr>
</table>
<h:commandButton value="Ajout Livre"
action="#{controleurLvire.doCreerLivre}"/>
</h:form>
<hr/>
</h:body>
</html>
5
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
Comme le montre le code précédant, la plupart des informations sont entrées dans des
champs de saisie, sauf la description, qui utilise une zone de texte et les illustrations
qui sont indiquées par une case à cocher.
Un clic sur le bouton « Ajout Livre » provoque l’appel de la méthode
doCreerLivre() du bean géré et l’EJB stocke alors le livre dans la base de données.
Bien que ce code ait été simplifié, il contient l’essentiel. Il déclare d’abord l’espace de
noms h pour les composants HTML de JSF : pour les utiliser, il faudra donc les
préfixer par cet espace de noms (<h:body>, <h:outputText>, <h:commandButton>,...).
Le langage d’expressions EL permet ensuite de lier dynamiquement la valeur du
composant à la propriété correspondante du bean géré.
Le code suivant, par exemple :
<h:inputText value="#{controleu
controleurLvire
controleurLvire.
rLvire.unLivre.
unLivre.Code}"/> lie la valeur
de l’attribut Code de unLivre avec le contenu de ce composant inputText
lors de la soumission du f ormulaire. ( controleurLvire étant le nom par
défaut du bean géré). Ce code est donc équivalent à celui-ci :
controleurLvire.getLivre().setCode("ce qui a été saisi")
La page utilise différents composants graphiques dont voici un bref résumé :
permet de créer un formulaire dont les valeurs seront envoyées
au serveur lorsqu’il sera soumis.
<h:form>
affiche un label à partir d’une chaine fixe
(comme value="Code : ") ou en liant un bean à la propriété.
<h:inputTextarea> affiche une zone de texte et lie sa valeur à l’attribut
description du livre.
<h:outputLabel>
<h:selectBooleanCheckbox>
affiche une case à cocher et la lie à l’attribut
illustrations (un Boolean).
affiche un bouton de soumission de formulaire
qui lorsqu’on cliquera dessus, invoquera la méthode doCreerLivre() du
bean géré (action="#{controleurLvire.doCreerLivre}").
<h:commandButton>
La page AfficherLivres.xhtml
La méthode doCreerLivre() du bean géré est appelée lors du clic sur le bouton de
soumission de la page AjoutLivre.xhtml.Elle stocke le livre dans la base et, si aucune
exception n’a été lancée, renvoie le nom de la page à afficher ensuite,
AfficherLivres.xhtml, qui affiche tous les livres de la base.
Un lien sur cette page permet ensuite de revenir à AjoutLivre.xhtml pour créer un autre
livre.
Le code de la page AfficherLivres.xhtml lister ci-sessous utilise des composants
6
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
différents, mais le principe est le même que celui de la page précédente.
Le composant le plus important est celui qui affiche les données sous la forme d’un
tableau :
<h:dataTable value="#{controleurLvire.lstLivres}" var ="liv">
L’élément <h:dataTable> est lié à l’attribut lstLivres du bean géré (une ArrayList
de livres) et déclare la variable liv qui permettra de parcourir cette liste. Dans cet
élément, on peut ensuite utiliser des expressions comme #{liv.Code} pour obtenir
l’attribut Code d’un livre.
Chaque colonne du tableau est définie par un élément <h:column>.
Le marqueur <h:commandLink> en bas de la page crée un lien qui, lorsqu’on
clique dessus, appelle la méthode nouveauLiv() du bean géré (celle-ci permet de
revenir à la page AjoutLivre.xhtml).
Code de la page AfficherLivres.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">
<h:head>
<titre>Liste des livres de la bibliothèque</titre>
</h:head>
<h:body>
<h1>Liste Des Livres</h1>
<hr/>
<h:dataTable value="#{controleurLvire.lstLivres}" var="liv">
<h:column>
<f:facet name="entete">
<h:outputText value="Code"/>
</f:facet>
<h:outputText value="#{liv.Code}"/>
</h:column>
<h:column>
<f:facet name="entete">
<h:outputText value="Titre"/>
</f:facet>
<h:outputText value="#{liv.titre}"/>
</h:column>
<h:column>
<f:facet name="entete">
<h:outputText value="Prix"/>
</f:facet>
<h:outputText value="#{liv.prix}"/>
</h:column>
<h:column>
<f:facet name="entete">
7
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
<h:outputText value="Description"/>
</f:facet>
<h:outputText value="#{liv.description}"/>
</h:column>
<h:column>
<f:facet name="entete">
<h:outputText value="Nombre de Pages"/>
</f:facet>
<h:outputText value="#{liv.nbrePages}"/>
</h:column>
<h:column>
<f:facet name="entete">
<h:outputText value="Illustrations"/>
</f:facet>
<h:outputText value="#{liv.illustrations}"/>
</h:column>
</h:dataTable>
<h:form>
<h:commandLink action="#{controleurLvire.nouveauLiv}"> Ajout un
nouveau Livre
</h:commandLink>
</h:form>
<hr/>
</h:body>
</html>
VI. Configuration avec web.xml :
Les applications web sont généralement configurées à l’aide d’un descripteur de
déploiement web.xml. Nous avons écrit "généralement" car ce fichier est devenu
facultatif avec la nouvelle spécification Servlet 3.0.
Cependant, JSF 2.0 reposant sur Servlet 2.5 (et non sur Servlet 3.0), nous devons
quand même déployer notre application web avec un descripteur.
Les applications JSF ont besoin d’une servlet nommée F a c e s S e r v l e t qui
agit comme un contrôleur frontal pour toute l’application. Cette servlet et son
association doivent être définies dans le fichier w e b . x m l .
Le Fichier web.xml déclarant une FacesServlet :
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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-app_2_5.xsd">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
8
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
</web-app>
VII.
Compilation et assemblage avec Maven :
L’application web doit être compilée et assemblée dans un fichier war
(<packaging>war</packaging>). Le fichier pom.xml ci-dessous déclare
toutes les dépendances nécessaires à la compilation du code (jsf-api, javax.ejb et
javax.persistence) et précise que cette compilation utilisera la version 1.6 du
JDK. Avec JSF 2.0, le fichier faces-config.xml n’est plus obligatoire mais je le
donne à titre d’indication.
Le Fichier pom.xml de Maven pour compiler et assembler l’application web :
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>5.0.0</modelVersion>
<groupId>coursJEE.EJB</groupId>
<artifactId>Exemple</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.ejb</artifactId>
<version>3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>1.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
9
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Pour compiler et assembler les classes, il suffit d’ouvrir un interpréteur en ligne de
commande dans le répertoire contenant le fichier pom.xml et d’entrer la
commande Maven suivante :
mvn package
Cette commande crée le fichier Exemple-1.0.war dans le répertoire cible.
Ouvrez le et vous constaterez qu’il contient l’entité Livre, le bean ejbLivre, le
bean géré ControleurLivre, les deux descripteurs de déploiement
(persistence.xml et web.xml) et les deux pages web (AjoutLivre.xhtml et
AfficherLivres.xhtml).
VIII.
Déploiement dans GIassFish :
L’application web assemblée doit ensuite être déployée dans GlassFish. Après avoir
vérifié que Derby s’exécute et écoute sur son port par défaut, ouvrez un interpréteur
en ligne de commande, placez vous dans le répertoire target contenant le fichier
Exemple-1.0.war et entrez la commande suivante :
asadmin deploy Exemple-1.0.war
Si le déploiement réussit, la commande qui suit devrait renvoyer le nom et le type de
l’application. Ici, il y a deux types : web car c’est une application web et ejb car elle
contient un EJB :
asadmin list-components Exemple-1.0
retourne <ejb, web>
IX. Exécution de L’application :
Lorsque l’application a été déployée, ouvrez votre navigateur et faite seule pointer
vers l’URL suivante :
http://localhost:8080/Exemple-1.0/AjoutLivre.faces
10
Institut Supérieur De Gestion De Tunis
3ème LFIG
cours AJEE
BAYOUDHI Chaouki
Le fichier pointé est AjoutLivre.faces, pas AjoutLivre.xhtml, car avec l’extension
.faces JSF sait qu’il doit traiter la page avant de l’afficher (voir l’association de .faces
avec FacesServlet dans le code ci-dessous).
Lorsque la page AjoutLivre s’affiche, saisissez les informations et cliquez sur le
bouton d’envoi du formulaire pour être redirigé sur la page AfficherLivres.
X.
Configuration de FacesServlet :
La FacesServlet est interne aux implémentations de JSF ; bien que vous n’ayez pas accès à
son code, vous pouvez la configurer avec des métadonnées.
Vous savez désormais qu’il existe deux moyens d’indiquer des métadonnées avec Java EE 6
: les annotations et les descripteurs de déploiement XML (/WEB-INF/facesconfig.xml).
Avant JSF 2.0, le seul choix possible était XML mais, désormais, les beans gérés,…
pouvant utiliser les annotations, les fichiers de configuration XML sont devenus facultatifs.
Je vous conseille l’emploi des annotations mais, pour montrer à quoi ressemble un fichier
faces-config.xml, l’extrait ci-dessous définit une locale et un ensemble de messages
pour l’internationalisation et certaines règles de navigation.
Extrait d’un fichier faces-config.xml :
<?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>
<locale-config>
<default-locale>fr</default-locale>
</locale-config>
<resource-bundle>
<base-name>messages</base-name>
<var>msg</var>
</resource-bundle>
</application>
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>doCreerLivre-success</from-outcome>
<to-view-id>/AfficherLivres.htm</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
11
Téléchargement