|
|
Institut National des Sciences
Appliquées et de Technologies
|
|
|
|
JavaServer Faces
|
|
|
Dans ce TP, nous allons mettre
en œuvre les frameworks Struts 1.2, JSF 1.1 et Hibernate 3.0 en utilisant
comme IDE NetBeans 5.5.
|
Sommaire
1. Généralités
1.1.
Le modèle MVC2
1.2.
Frameworks pour applications Web J2EE
1.2.1. Struts
1.2.2. JSF
1.2.3. Hibernate
1.3. NetBeans
et Visual Web Pack
2. Première partie : Struts et
JSF
2.1.
Problématique
2.2.
Schéma de base de données
2.3.
Architecture avec le modèle MVC2
2.4.
Mise en œuvre de Struts 1.2
2.4.1.
Ce à quoi on veut arriver
2.4.2.
Couche de présentation
2.4.3.
Couche métier
2.4.4.
Couche d’accès aux données
2.5.
Mise en œuvre de Struts 2.0
2.5.1.
Ce à quoi on veut arriver
2.5.2.
Couche de présentation
2.5.3.
Couche métier
2.5.4.
Couche d’accès aux données
2.6.
Mise en œuvre de JSF 1.1
3. Deuxième partie : Hibernate
3.1.
Intégration de Hibernate
3.2.
Mise en œuvre de Hibernate 3.0
3.2.1. Ce à quoi on veut arriver
3.2.2. Couche de présentation
3.2.3. Couche métier
3.2.4. Couche d’accès aux données
|
1. Généralités |
|
1.1. Le modèle MVC2 |
Le
modèle Model-View-Control model 2 ou MVC2 de Sun propose de n'utiliser qu'une
seule et unique servlet comme contrôleur. Cette servlet se charge d'assurer le
worflow des traitements en fonction des requêtes http reçues.

(Source : http://www.jmdoudoux.fr/)
|
1.2. Frameworks pour applications Web J2EE |
Un
framework est « une structure permettant de soutenir ou de contenir
quelque chose, en particulier un squelette pouvant servir de base à une
construction » (Source : dictionnaire anglais).
|
1.2.1. Apache Struts |
Apache
Struts est un framework open-source gratuit pour la création d’applications Web
en Java. Il a été initialement développé par Craig Mc
Clanahan qui l'a donné au projet Jakarta d'Apache en mai 2000.
Le
framework fournit son propre contrôleur Web et s’intègre avec d’autres
technologies proposant le modèle et la vue.
Pour
le modèle, le framework peut interagir avec des technologies d’accès aux
données tel que JDBC (Java Database Connectivity), EJB (Enterprise Java Beans)
et Hibernate.Pour la vue, le framework fonctionne aussi bien avec les
JavaServer Pages, incluant les JSTL (Java Standard Tag Libraries) et JSF.
Le
contrôleur de Struts agit comme un pont entre le modèle de l’application et la
vue Web. Lorsqu’une requête est reçue, le contrôleur invoque la classe Action.
La classe Action consulte alors le modèle pour examiner et mettre à jour l’état
de l’application. Le framework fournit une classe ActionForm pour faciliter le
transfert de données entre le modèle et la vue. Dans la plupart des cas, le
modèle est représenté par un ensemble de JavaBeans (Source :
http://struts.apache.org/1.x/index.html).
Voici une explication de la terminologie employée dans
Struts:
|
Il représente un formulaire HTML avec lequel
l’utilisateur interagit à travers une ou plusieurs pages. On devra y fournir
les attributs permettant de garder l’état du formulaire avec des getters et
des setters pour y accéder. Le framework remplit les attributs par les paramètres
de la requête et envoi le formulaire après validation à la méthode execute de l’action appropriée. L’objet ActionForm
offre peut agir aussi en tant que « firewall » entre HTTP et Action
en fournissant un mécanisme de validation automatique des données d’un
formulaire. Grâce à la méthode validate
le ActionForm produit des messages
d’erreurs prédéfinis dans l’application. Bien entendu, cette validation peut
être ignorée. |
|
|
A
fin de fonctionner correctement, notre servlet contrôleur a besoin de savoir
comment chaque URI (uniform resource identifier) de requête doit être
acheminé (mapped) à la classe Action appropriée. Les informations nécessaires
sont encapsulées dans une classe Java appelée
ActionMapping, qui elle-même tire ses informations de la balise action du fichier
« struts-config.xml ». Les propriétés les plus importantes de cette
balise sont les suivantes :
Exemple de balise action :<action input="/LoginForm.jsp" name="NewStrutsActionForm" path="/login" type="com.myapp.actions.NewStrutsAction"><forward name="success" path="/loginsuccessful.jsp"/></action>
|
|
|
Actions |
Le but de la classe Action est de
traiter une requête via sa méthode execute
et de retourner un ActionForward
qui détermine où le contrôle doit être dirigée (par exemple une JSP ou une
autre Action) pour produire la réponse voulue. public ActionForward execute(ActionMapping mapping, ActionForm form, ServletRequest request, ServletResponse response) throws Exception;Voici l’explication des objets en paramètres :
|
(Source :
http://struts.apache.org/1.x/index.html)
Non.
Si on a besoin de réaliser une application très simple, avec peu de pages,
alors on pourrait considérer une solution MVC1 qui utilise seulement des JSP et
des servlets simples. Par contre, si on désire construire une application
complexe, avec des dizaines de pages, qui auraient besoin d’être maintenue,
alors Struts serait plus convenable.
Qu’en est t’il de Struts 2 ?
En
décembre 2005, les équipes de Struts 1 et de WebWork ont mis en commun leurs compétences
pour développer un nouveau framework baptisé WebWork2, renommé par la suite
Struts 2, dont la première version stable est sortie le 22 février 2007, sous
le label 2.0.6. Pour sa part, Struts 1 continue son évolution et est
actuellement dans sa huitième version officielle (1.3.8) depuis le 10 Mars
2007.
Les
principaux changements introduits dans Struts 2 sont les suivants :
§ Les ActionForm
sont désormais directement intégré aux classes d’action : xWork 2 fournit une interface «
ModelDriven » qui peut être implémentée par une action en fournissant le type
d’objet à mapper.
//ActionPublic class PersonneAction extends ActionSupport implements ModelDriven<Personne> { public String execute(){ return SUCCESS; }
} |
L’objet fourni
est directement accessible dans la vue à l’aide du langage OGNL (Object Graph
Navigation Language).
<!—JSP--><%@ page contentType=“text/html;charset=UTF-8″%><%@ taglib prefix=“s” uri=“/struts-tags”%><s:textfield name=“model.nom” label=“nom”/><s:textfield name=“model.prenom” label=“prénom”/>
<s:submit key=“button.submit”
value=“Enregistrer”/> |
Au sein
de la JSP, les attributs de l’objet « personne » sont directement passés en
paramètre à travers le model. Avec OGNL, « model.nom » représente à la fois le
getter et le setter de l’attribut nom.
§ Les classes
d’action peuvent être appelées à travers toutes leurs méthodes,
§ Les classes
d’action ne sont plus obligées d’hériter la classe abstraite Action, elles
peuvent désormais hériter d’autres classes tout en implémentant l’interface
Action,
§ Des intercepteurs
ou des piles d’intercepteurs peuvent être configurés. Ils sont utilisés pour
effectuer des pré/post traitements sur la requête.
(Source :
http://blog.valtech.fr/wordpress/2007/06/28/struts-1-vs-struts-2/)
|
1.2.2 Java Server Faces : JSF |
La
création des applications web dynamique
est une source de développement continu que ce soit pour les applications
internes ou commerciaux. Face à la diversité des demandes concernant ce
domaine, plusieurs technologies sont apparues comme ASP puis ASP.NET ou encore
PHP.
Dans
le monde JAVA et suite à cette montée en technologie, l’introduction des
servlets à été rapidement complété par les JSP pour mieux gérer les sorties
HTML.
Mais
la maintenance et la montée en complexité des applications posait de nombreux
problèmes et il a fallu reprendre les éternelles bonnes pratiques (ou Design
Patterns) comme le modèle MVC (Modèle Vue Contrôleur) et les adapter un peu à
cette nouvelle problématique (MVC2).
Une
fois arrivé à ce stade, il aurait été dommage de s’arrêter alors qu’il
suffisait de faire un petit effort afin d’utiliser les éléments de présentation
comme les taglibs et de simplifier la syntaxe des pages JSP.
Bien
évidemment si on n’est pas passé par toutes ces étapes, on a souvent
l’impression que le développement J2EE est hors de portée et c’est dans ce
contexte que vient JSF.
Afin de
réagir aux ambitions
de Microsoft de
croquer une plus
grosse part du
marché du développement web avec
ASP et ASP.NET et de proposer enfin un framework web standard dans le monde
J2EE, une JSR (Java Specification Request) est formée qui donne lieu en 2003 à
la première version de Java Server Faces. Depuis, la version actuelle est la
1.1 et nous nous dirigeons vers une version 1.2.
La
norme JSF 1.0 fournit avant tout un framework web et un modèle de programmation
permettant de créer des composants réutilisables.
Le
framework web JSF dispose d’une architecture de type MVC2 (Model View
Controller 2).
Dans
notre cas :
-Le
controleur JSF s’appelle Faces Servlet.
-Les
objets du modèles sont des objets java (ou POJO) appelés aussi les managed beans
ce qui signifie tout simplement que l’on laisse, le cas échéant à JSF le soin
de les instancier et de les initialiser.
-
les vues : les vues sont principalement créées a partir de pages JSP et
elles sont réellement représentées par un arbre d’objets gérés coté serveur. Au
sein de JSF, les classes responsables
de la présentation
graphique (HTML ou
autre) des composants
graphiques sont appelés des «
renderers ».
Comme
le fichier web.xml, dans JSF on trouve un fichier de configuration XML qui
s’appelle généralement faces-config.xml.
Cycle de vie d’une
requête JSF :

|
1.2.3. Hibernate |
Hibernate
est un projet professionnel open-source. C’est un service de requête et de
persistance objet/relationnel qui permet d'interfacer le code métier avec une
source de données.
Il
permet de développer des classes différentes respectant la programmation
orientée objet y compris l’association, l’héritage, le polymorphisme et les
collections.
Voici
comment se présente l’architecture du framework Hibernate :

(Source : http://hibernate.org)
|
1.3. NetBeans et Visual Web Pack |
NetBeans est
un environnement de développement logiciel gratuit et open-source spécialisé
dans la technologie Java. Il est multi plateforme et permet de développer des
applications professionnelles pour le web ou le mobile.
(Source :
http://www.netbeans.org/)
Il permet
aussi de faciliter le travail avec les bases de données grâce aux requêtes
personnalisées, à la prévisualisation de résultat et au support de
drag-and-drop pour la reliure avec des sources de données hétérogènes.
(Source :
http://netbeans.org/products/visualweb/)
|
2.
Première partie : Struts et JSF |
|
2.1.
Problématique |
On désire développer une application
web (nommée Grand Hôtel) permettant à une institution hôtelière de gérer les
réservations et les chambres en ligne.
|
2.2. Schéma de base de données |
Le
problème traité mets en jeu deux acteurs principaux : le visiteur et
l’administrateur. Le diagramme de use case suivant détaille les cas
d’utilisation propre à chacun d’eux :

Diagramme de use case
A
partir du diagramme de use case et après une brève recherche sur la manière de
réserver dans un hôtel, nous déduisons les classes et les attributs dans le
diagramme de classes suivant :

Diagramme de classes
Astuce : comment générer
un script SQL sous Rational Rose à partir d’un diagramme de classe ?
Il
suffit de suivre la démarche suivante :
1.
Rendre toutes les classes persistantes (pour chaque classe, cliquer le bouton
droit puis « open standard specifications », puis dans l’onglet
« detail », activer le radio « persistent »),
2.
Mettre toutes les classes dans un même package,
3.
Cliquer le bouton droit sur le package, puis « transorm to data
model »,
4.
Faire un « forward engeneering » à partir du schéma généré (cliquer
le bouton droit, puis « data modeler » et « forward
engeneering »),
Un
fichier .ddl contenant le script SQL voulu est alors généré. Il ne reste plus
qu’à le déployer sur un serveur de base de données comme MySQL dans notre cas.
|
2.3.
Architecture avec le modèle MVC2 |
L’application est structurée selon le modèle MVC2 qui se base sur un modèle à 3 couches :

Le
diagramme de séquence suivant mets en œuvre le modèle MVC2 pour le use case « l’administrateur
s’authentifie » :

Diagramme de séquence du use case
« l’administrateur s’authentifie »
Pour
confirmer le fait que nous utilisons bien MVC2 et le framework Struts, voici le
diagramme de séquence du use case « l’administrateur consulte les chambres
» :

Diagramme de séquence du use case
« l’administrateur consulte les chambres »
Nous
remarquons que dans les deux diagrammes, le contrôle passe toujours par une
servlet centrale appelée ActionServlet conformément
au framework Struts.
Bien
évidement, cette servlet est gérée par le framework qui se charge de la
déclarer dans le descripteur de déploiement et nous n’aurons pas y toucher.
Dans
tout ce qui suit, nous utilisons le serveur Apache Tomcat 5.5 et le connecteur
mysql-connector 5.
|
2.4. Mise en œuvre de Struts 1.2 |
|
2.4.1.
Ce à quoi on veut arriver |
Voici
les interfaces successives que l’administrateur rencontrera lors de son authentification et
de la consultation des chambres :
|
|
|
|
|
|
|
2.4.2.
Couche de présentation |
Commençons
par la partie « vue » de la couche de présentation.
A
fin de faciliter la gestion et la maintenance des pages JSP, nous nous proposons
d’inclure dans chaque page deux fichiers JSP, l’un appelé xHeader.jsp contenant le code de l’entête (librairies de tag,
fichier de style, bannière et menu principal) et l’autre nommé footer.jsp contenant le pied de page.

Les
pages xHeader.jsp font incluent à
leur tour les taglibs bean, html et logic de Struts comme suit :
<%@taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%><%@taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@taglib
uri="http://jakarta.apache.org/struts/tags-logic"
prefix="logic" %> |
Dans
un scénario classique, l’administrateur se connecte en utilisant la JSP
loginForm.jsp suivante :
|
<%@ include
file="includes/frontOfficeHeader.jsp" %> <strong>Veuillez
entrer votre login et password:</strong> <html:form action="login"> <table
border="1">
<thead>
<tr>
<th><bean:message key="login.name" /></th> <th><bean:message
key="login.password" /></th>
</tr>
</thead>
<tbody>
<tr>
<td><html:text property="name" /></td>
<td><html:password property="password"
/></td>
</tr>
</tbody>
</table>
<html:submit><bean:message key="button.submit"
/></html:submit>
<html:errors property="nameEmpty" />
<html:errors property="passwordEmpty" /> </html:form> <%@ include file="includes/footer.jsp"
%> |
Nous
remarquons l’utilisation du taglib html
de Struts à travers la propriété form qui représente un formulaire classique en
html (balise <form>).
La balise <bean:message
key="login.name"> permet quant à elle d’afficher un message en
fouillant dans le fichier de propriétés « ApplicationResource » la valeur de la clé fournie.
La reliure
(binding) avec le bean de formulaire LoginActionForm
(spécifié dans la balise action de struts-config) est réalisée simplement en
donnant comme properties les mêmes attributs de ce bean :
|
<html:text property="name" /> <html:password property="password"
/> |
Enfin, en cas
d’erreur détecté dans la méthode validate de LoginActionForm, le message
approprié est affiché :
|
<html:errors property="nameEmpty" /> <html:errors property="passwordEmpty"
/> |

Nous
étudierons plus tard comment les messages d’erreur sont générés.
Une
fois connecté, l’administrateur se trouve sur la page loginsuccessful et peut alors cliquer sur le lien suivant, lien qui
lui permettra de lister les chambres de l’hôtel :
|
<html:link action="/DSChambres"
linkName="Chambres"> Gérer les
chambres </html:link> |
Nous
remarquons que la propriété action vaut « /DSChambres », cette valeur correspond au chemin (path) de
l’action déclarée dans struts-config.
Voici la déclaration complète de cette action struts-config :
|
<action
input="/loginsuccessful.jsp"
scope="request"
path="/DSChambres"
type="com.myapp.actions.ChambreLoadAction">
<forward name="success"
path="/afficherChambres.jsp"/> </action> |
D’après
cette déclaration, l’action utilise le contrôleur ChambreLoadAction et dirige en cas de bon déroulement vers la page afficherChambres. Nous remarquons que
nous avons omis d’utiliser un ActionForm
car il ne s’agit pas d’un cas où l’utilisateur saisit des données.
L’affichage
de la liste des chambres se base sur la balise iterate du taglib logic
qui facilite l’accès à la collection de chambres et son parcours (à
l’image de la balise foreach du
taglib core de JSTL) :
|
<logic:present name="chambres"> <table border="1"> <logic:iterate id="chambre" name="chambres"> <tr> <td><bean:write
name="chambre" property="type"/></td> <td><bean:write name="chambre"
property="prix"/></td>
</tr>
</logic:iterate>
</table> </logic:present> |
Passons
maintenant à la partie « contrôleur ». Cette partie comprend deux
volets :
Nous avons vu
que la page loginForm contient un
formulaire dont l’action vaut /login.
Voici le mapping
correspondant à cette action :
|
<action
input="/loginForm.jsp" name="LoginActionForm" path="/login" scope="request"
type="com.myapp.actions.LoginAction"> <forward name="success"
path="/loginsuccessful.jsp"/> <forward name="failure"
path="/loginfailed.jsp"/> </action> |
Le sous
contrôleur de cette action est la classe LoginAction
tant dit que le container associé au formulaire est LoginActionForm.
La classe LoginAction contient la méthode execute chargée de réaliser le
traitement désiré et de diriger le contrôle vers la ressource appropriée.
|
public ActionForward execute (ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception { LoginActionForm newStrutsActionForm =
(LoginActionForm) form; if
(SecurityManager.AuthenticateUser(newStrutsActionForm.getName(),newStrutsActionForm.getPassword())){ return mapping.findForward(SUCCESS); } else { ActionMessages errors = new
ActionMessages(); ActionMessage error = new
ActionMessage("errors.login.invalid");
errors.add("loginWrong",error); saveErrors(request.getSession(),errors); return
mapping.findForward(FAILURE); } } |
Le
choix de la ressource dépend de la valeur du jeton. Dans notre cas, si le jeton
vaut success alors le contrôle est
dirigé vers la page loginsuccessful
(comme indiqué dans struts-config). Dans le cas contraire, le contrôle nous
mène à la page loginFailed (valeur de
jeton égale à failure).
L’exemple
que nous avons réalisé mets le jeton à success
si le login et le password sont corrects. Ce buisness control est réalisé grâce
à une classe de contrôle métier que nous nommons SecurityManager qui vient
compléter la méthode validate de la classe LoginActionForm.
En
effet, la méthode validate, par souci de bonne pratique, ne doit s’intéresser
qu’à la validité syntaxique des champs login et password (champs vides/non
vides, nuls/non nuls,…).
Voici
comment une erreur est générée en cas de login ou de password vide :
|
public ActionErrors
validate(ActionMapping m, HttpServletRequest request) { ActionErrors errors = new
ActionErrors(); if (getName() == null ||
getName().length() < 1) { errors.add("nameEmpty",
new
ActionMessage("error.name.required")); } if (getPassword() == null ||
getPassword().length() < 1) {
errors.add("passwordEmpty", new
ActionMessage("error.password.required")); } return errors; } |
Les valeurs
des clés tel que « error.name.required »
sont indiquées dans le fichier de propriétés (ApplicationRessources.properties).
|
2.4.3.
Couche métier |
Cette couche
est particulièrement simple. Elle comporte les beans Chambre, Reservation et Client sans aucune particularité.
|
2.4.4.
Couche d’accès aux données |
Cette couche
comporte une classe ChambreDAO (Data
Access Object) à laquelle nous faisons appel dans l’action ChambreLoadAction par la méthode getChambres.
Cette classe
utilise le contexte initial pour obtenir le pool de connexion et pouvoir ainsi
accèder à la base de données.
Le pool de
connexion est déclaré dans le fichier web.xml
comme suit :
|
<resource-ref>
<description>DB Connection</description> <res-ref-name>jdbc/grandhotel</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> |
L’URL, le nom
d’utilisateur, le mot de passe ainsi que le driver de la base de données
concerné par ce pool sont déclarés dans le fichier context.xml comme suit:
|
<Context
path="/StrutsGrandHotel"> <Resource auth="Container"
driverClassName="com.mysql.jdbc.Driver"
name="jdbc/grandhotel"
type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/grandhotel"
username="root"
password="" /> </Context> |
Il s’agit en
fait d’une ressource utilisant un driver JDBC
et une source de données basique pour accéder à la base de données grandhotel. Cette ressource est
identifiée par son name, soit "jdbc/grandhotel".
C’est ce même
nom que nous utilisons pour récupérer à tout moment une source de données prête
à accéder à cette base de données.
La classe ChambreDAO utilise justement ce pool de
connexion pour obtenir la liste des chambres :
|
public static ArrayList
getChambres(){ … try { source = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/grandhotel");
connection=source.getConnection();
etat=connection.createStatement(); rs=etat.executeQuery("SELECT
* FROM chambre;"); while (rs.next()) { Chambre chambre = new
Chambre(rs.getString("type"), rs.getString("prix"),
rs.getString("vue"), rs.getString("etat")); chambreList.add(chambre); } … } catch ( SQLException e ) {…} return chambreList; } |
|
2.5.
Mise en œuvre de Struts 2.0 |
|
Dans
l’exemple qui suit, nous utiliserons les generics. Nous devons donc nous
assurer que le source level de Java est bien au dessus de 1.4. Pour
cela, il faut afficher les propriétés du projet et vérifier le niveau comme
le montre la figure ci-contre. |
|
Dans
cette partie, nous allons traiter le use case « le client réserve une
chambre ».
Installation et
configuration de Struts 2.0 pour notre application :
A
fin de pouvoir profiter des fonctionnalités de Struts 2, nous procédons comme
suit :
1.
Déclaration dans le fichier web.xml
du dispatcheur de filtre et d’un filtre en *.action qui dirigera le contrôle
vers la servlet principale de Struts 2 :
|
<filter>
<description>Struts 2.0 Filter</description> <filter-name>Struts 2.0
Filter</filter-name> <filter-class>
org.apache.struts2.dispatcher.FilterDispatcher </filter-class> </filter> <filter-mapping> <filter-name>Struts 2.0
Filter</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> |
2.
Ajout des librairies Struts 2 suivantes au répertoire WEB-INF/lib du
projet :
3.
Création du fichier struts.xml dans le package par défaut et ajout du code
suivant :
|
<?xml version="1.0"
encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts
Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="sample"
extends="struts-default"> … <action
name="insertReservation"
class="com.control.ReservationInsertAction"> <result name="error">/insertReservation.jsp</result>
<result>/insertSuccess.jsp</result> </action> </package> </struts> |
|
|
|
|
2.5.1.
Couche de présentation |
La
page de saisie de réservation est la suivante :
|
<%@ taglib
prefix="s" uri="/struts-tags" %> <html> <body> <s:form
action="insertReservation" method="POST"
validate="true">
<tr>
<td colspan="2">
Veuillez remplir votre réservation : </td> </tr> <s:hidden
name="date_enregistrement" value="2007-12-12"/> <s:textfield
name="date_arrivee" label="Date d'arrivée
(AAAA-MM-JJ):"/> <s:hidden name="montant"
value="150" /> <s:hidden
name="petit_dejeuner" value="non" /> <s:textfield
name="nb_nuits" label="Nombre de nuits:" /> <s:hidden name="etat"
value="en attente"/> <s:submit
value="Envoyer" align="center"/> </s:form> </body> </html> |
Nous
y utilisons le taglib struts-tags contenant
entre autres les contrôles html.
Une
fois que le bouton « Envoyer » est cliqué, l’action insertReservation est enclenchée :
d’après struts-config, cette action
utilise la classe ReservationInsertAction.
Cette
classe appelle sa propre méthode « execute ».
En cas d’insertion réussie dans la base de données, la page insertSuccess est affichée, sinon la
page source est réaffichée.
Intéressons
nous maintenant de près au sous contrôle ReservationInsertAction.
Cette classe d’action, à partir de la version 2, hérite de ActionSupport et peut implémenter n’importe quelle interface. Dans
notre cas, nous choisissons d’implémenter l’interface ModelDriven en fournissant en paramètre générique, la classe Reservation. Voici le code de
l’action ReservationInsertAction :
|
package com.control; import
com.dao.ReservationDAO; import
com.model.Reservation; import
com.opensymphony.xwork2.ActionSupport; import
com.opensymphony.xwork2.ModelDriven; public class ReservationInsertAction extends ActionSupport implements
ModelDriven<Reservation> { Reservation reservation = new
Reservation(); public String execute() throws Exception
{ int val =
ReservationDAO.insert(reservation); if(val == 0){ return "error"; } else{ return "success"; } } public Reservation getModel() { return this.reservation; }
} |
L’interface
ModelDriven permet en réalité de
réaliser un mapping entre le modèle Réservation
et l’action concernée. Nous pouvons dès lors récupérer directement le bean
provenant du formulaire en entrée.
(Source :
http://www.groovesystems.com/training/java4/webwork.ppt)
|
2.5.2.
Couche métier |
Il
s’agit d’implémenter le bean Reservation
sans rien de particulier.
|
2.5.3.
Couche d’accès aux données |
L’action
ReservationInsertAction fait appel à
la méthode insert de la classe ReservationDAO
:
|
public static int
insert(Reservation reservation) throws Exception{ int val=0; DataSource source=null; Connection connection = null; Statement
etat = null; ResultSet rs = null; try{ source = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/grandhotel"); connection=source.getConnection(); etat=connection.createStatement(); val = etat.executeUpdate("INSERT
INTO reservation " +
"VALUES('"+reservation.getDate_enregistrement()+"','"
+reservation.getDate_arrivee()+"','" +reservation.getMontant()+"','"
+reservation.getPetit_dejeuner()+"','"
+reservation.getNb_nuits()+"','"
+reservation.getEtat()+"',0,0)"); } catch(Exception e){ System.out.println(e.getMessage()); } return val; } |
Nous
y utilisons le pool de connexion déclaré préalablement dans le fichier de
contexte et le descripteur de déploiement.
|
2.5.
Mise en œuvre de JSF 1.1 |
Un
client quand il se connecte à l’application, devra entrer des informations
personnelles tel que sont nom, son prénom , email puis ,choisir sa réservation
qui inclut la date d’enregistrement, la date d’arrivée, le type de la chambre ,
la vue. Etc
Arborescence
d’une application JSF :

Les
pages JSP se trouvent par défaut sous le répertoire Web Pages. Ce répertoire contient un dossier WEB-INF qui contient les fichiers de configurations tel que web.xml, faces-config.xml, managed-beans.xml, et navigation.xml.
Il
est primordial de comprendre l’intérêt de chacun de ses fichiers au sein de
n’importe quelle application web sous JSF.
Faces-config.xml
Le
fichier de configuration propre à JSF est le fichier faces-config.xml.
Dans ce fichier, on ajouter des navigation
rules, des navigation cases et
des managed beans.
Voici
un exemple : le contenu du fichier faces-config.xml de notre application :
|
<faces-config> <managed-bean>
<managed-bean-name>BeanReservation</managed-bean-name>
<managed-bean-class>BeanReservation</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope> </managed-bean> <navigation-rule> <description> passage de la page d’acceuil à la page
réservation </description>
<from-view-id>/Page1.jsp</from-view-id> </navigation-rule> </faces-config> |
Managed-beans.xml
Les
managed beans se trouvent aussi dans le fichier managed-beans.xml.
Remarque :
Les
managed-beans sont des beans ordinaires dont le cycle de vie est géré par JSF.
JSF instancie ces beans en fonctions de leurs scope que ce soit request,
session ou application puis les stocke dans le contexte de
l’application.
L’utilité
des beans managées vient dans l’affichage des données provenant de la couche
métier ou de la saisie de données par un utilisateur.
Navigation.xml
Le
fichier navigation.xml peut
s’afficher en mode xml ou en mode design. Il permet de créer les
pages en mode design et d’établir les liens entre ses pages.
|
|
<faces-config> <navigation-rule>
<from-view-id>/Page1.jsp</from-view-id> <navigation-case>
<from-outcome>case1</from-outcome> <to-view-id>/Reservation.jsp</to-view-id> </navigation-case> </navigation-rule> </faces-config> |
Etapes
de création de notre application :
Création de la base de données sous
MySQL

Etablissement de l’interface
utilisateur sous netbeans.
L’interface
utilisateur a été crée sous l’environnement netbeans et avec le plugin Visual
web pack.
Chaque
page jsp possède 3 vues :
![]()
·
Une page. jsp (comme
le code behind en ASP.NET)
·
Une page .java
(contenant le code correspondant au traitement des évènements des composants de
la page tel que les actions sur un bouton,etc).
·
Et une page en mode design
Les liens de navigation
entre les pages de l’application :
|
|
Le scénario :
Un utilisateur accède à la page
d’accueil du site (index.jsp), il clique sur le lien réservation qui lui permettra d’accéder au formulaire de
réservation FormReservation.jsp, il
devra par la suite entrer les informations nécessaires et cliquer sur réserver pour envoyer sa demande. Ce
lien l’enverra à la page Confirmreservation.jsp
pour confirmer sa demande de réservation.
Création
des managed beans
Pour
chaque table de la base de données on crée un managed bean(ou encore un session
bean dans notre cas).
La
raison pour laquelle on a crée un bean de session
et non pas un bean de requête(request) ou encore d’application
est que dans le bean de session on peut stocker des informations qui seront
utilisées par les autres pages durant une session utilisateur.
Remarque : Si on utilise une bean de requête,
ce qu’on stocke dans la requête disparaîtra aussi tôt que la requête sera fini.
On
crée le managed bean soit dans le fichier faces-config.xml , soit directement
dans l’arborescence.

On
doit générer pour chaque attribut du bean les getters et les setters pour
pouvoir réaliser le binding par la
suite avec le formulaire.
Faire
le binding entre l’interface utilisateur et le bean
Dans
cette partie, on va expliquer comment on arrive à récupérer les informations
saisies par l’utilisateur, les « binder »dans le bean pour pouvoir
les récupérer par la suite et les insérer dans la base de données.
Donc,
pour associer un contrôle (un component) à une propriété du bean on procède
comme suit :
-
on clique avec le bouton droit sur le composant
-
on choisit Property
binding
-
une fenêtre s’affiche contenant les différentes
propriétés disponibles avec les beans disponibles.
-
il suffit de choisir la propriété à binder (bindable
property) et la propriété cible (binding target).

Après
cette manip, une instance du bean SessionBeanReservation
est crée au niveau du de notre page jsp FormReservation, il suffit par la suite de récupérer ce bean pour
pouvoir récupérer les valeurs de ses propriétés.
|
SessionBeanReservation
beanR=(SessionBeanReservation)this.getBean("SessionBeanReservation"); String vue=beanR.getVue(); String type=beanR.getType(); |
Etablir
les contrôles nécessaires : validation de contenu
Parmi
les particularités de JSF, c’est la présence de composants réutilisables. Parmi
ces composants, on trouve les convertisseurs et les validateurs.
Dans
notre application, on a mis en œuvre les validateurs pour les dates et pour un
champ de type entier.
Pour
les types dates, on a utilisé le composant Calendar qui possède 2 propriétés minDate
et maxDate.
On
a définit pour minDate la date du jour puis en utilisant le binding on a fait
l’association entre cette propriété et la variable date crée ci-dessous ;
|
private
Date d1=java.util.Calendar.getInstance().getTime(); |
Pour afficher le message d’erreur, il suffit
d’utiliser le composant message
de la barre d’outils. De faire un drag
drop dans le formulaire puis faire un ctrl-shift
et le lier au composant sur lequel on va effectuer la validation.

On peut aussi
utiliser des validateurs propre à JSF comme doubleRangeValidator.
On glisse un
composant doubleRangeValidator sur le champ à valider.
On choisi le
contrôle doubleRangeValidator dans le outline et on défini le maximum et le
minimum.

![]()
Etablir
un accès à la base de données pour l’insertion
On
voudrait réaliser une connexion avec la base de données MySQL en utilisant JNDI.
Configuration du
fichier web.xml :
Pour
pouvoir faire la connexion, on doit créer une référence à la source de données
dans le fichier web.xml.
|
|
<resource-ref> <res-ref-name> jdbc/grandhotel </res-ref-name> <res-type> javax.sql.DataSource
</res-type> <res-auth>Container</res-auth> <res-sharing-scope> Shareable </res-sharing-scope> </resource-ref> |
Une
fois la référence crée, on remarque qu’un morceau de code a été ajouté au
fichier context.xml faisant aussi
référence à la source de données.
|
<Context
path="/JSFGrandHotel"> <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" maxActive="100"
maxIdle="30" maxWait="10000" name="jdbc/grandhotel"
password="" type="javax.sql.DataSource"
url="jdbc:mysql://localhost:3306/grandhotel" username="root"/> </Context> |
Pour
créer maintenant
|
DataSource ds=(DataSource) new
InitialContext().lookup("java:comp/env/jdbc/grandhotel"); //creation de Connection c= ds.getConnection();//création de la connexion Statement
st = c.createStatement(); String req="INSERT INTO reservation ……
nb=st.executeUpdate(req); //execution d’une
requête d’insertion Statement st1=c.createStatement(); String req1="INSERT INTO client …… nb1=st1.executeUpdate(req1); c.close();//fermeture
de la connexion st.close();//fermeture
du statement st1.close(); |
Remarque :
L’IDE
Netbeans nous permet d’établir la connexion avec la base et d‘afficher directement
la liste des tables ainsi que les données contenues dans les différentes
tables.

|
3.
Deuxième partie : Hibernate |
|
3.1.
Intégration de Hibernate |
Dans
cette partie, nous allons intégrer Hibernate 3.2 à l’application
StrutsGrandHotel et traiter le cas d’utilisation « l’administrateur ajoute
une chambre à l’hôtel ».
Installation et
configuration de Hibernate pour notre application :
1.
Création du fichier hibernate.cfg.xml dans le package par défaut et ajout du
code suivant :
|
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration
DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property
name="hibernate.connection.url">jdbc:mysql://localhost:3306/grandhotel</property> <property
name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property
name="hibernate.connection.username">root</property> <property
name="hibernate.connection.password"></property> <property
name="show_sql">true</property> <property
name="dialect">org.hibernate.dialect.MySQLDialect</property> <property
name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property> <mapping
resource="./com/myapp/beans/Chambre.hbm.xml"/> </session-factory> </hibernate-configuration> |
Il
s’agit du fichier de configuration de Hibernate. Le framework pourra y trouver
les informations nécessaires sur la base de données et les différents fichiers
de mapping objet/relationnel.
2.
Ajout des librairies Hibernate suivantes au répertoire WEB-INF/lib du
projet :
3.2. Mise en œuvre de Hibernate 3.0 |
|
3.2.1.
Ce à quoi on veut arriver |
|
|
|
|
|
|
|
3.2.2.
Couche de présentation |
Le
contrôleur ChambreInsertAction se charge de faire appel à la méthode insert de
la classe d’accès aux données ChambreDAO en lui fournissant en paramétre la
chambre à insérer :
|
public ActionForward
execute(ActionMapping mapping, ActionForm
form, HttpServletRequest request,
HttpServletResponse response) throws Exception { Chambre chambre =
(Chambre) form;
ChambreDAO.insert(chambre); return mapping.findForward(SUCCESS); |
|
3.2.3.
Couche métier |
Le
use case que nous avons choisi de traiter concerne l’insertion d’une chambre.
Nous
devons alors préparer un bean Chambre
et un fichier de mapping objet/relationnel pour ce bean qu’on appelle
« Chambre.hbm.xml » (ce type
de nommage doit être respecté) :
|
<?xml
version="1.0"?> <!DOCTYPE
hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD
3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.myapp.beans.Chambre"
table="chambre"> <id name="id_chambre"
type="int" column="id_chambre"
unsaved-value="0"> <generator
class="assigned"/> </id> <property
name="type"> <column name="type"
length="55" not-null="true"/> </property> <property
name="prix"> <column name="prix"
length="55" not-null="true"/> </property> <property name="vue"> <column name="vue"
length="55" not-null="true"/> </property> <property
name="etat"> <column name="etat"
length="55" not-null="true"/> </property>
</class> </hibernate-mapping> |
Ce
fichier comporte des méta données concernant les colonnes de la table chambre.
|
3.2.4.
Couche d’accès aux données |
Hibernate
étant un outil de persistance, il doit s’assurer que la session de travail est
unique. Voici l’utilitaire de création et d’obtention de la session en
cours :
|
package com.dao; import
org.apache.commons.logging.Log; import
org.apache.commons.logging.LogFactory; import org.hibernate.*; import org.hibernate.cfg.*; public class HibernateUtil { private static Log log =
LogFactory.getLog(HibernateUtil.class); private static final SessionFactory
sessionFactory; static { try { // Create the SessionFactory sessionFactory = new
Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Make sure you log the
exception, as it might be swallowed ex.printStackTrace(); log.error("Initial
SessionFactory creation failed." + ex); throw new
ExceptionInInitializerError(ex); } } public static final ThreadLocal session =
new ThreadLocal(); public static Session currentSession() { Session s = (Session) session.get(); // Open a new Session, if this Thread
has none yet if (s == null) { s = sessionFactory.openSession(); session.set(s); } return s; } public static void closeSession() { Session s = (Session) session.get(); if (s != null) s.close(); session.set(null); } } |
Nous ajoutons
ensuite la méthode insert à la classe
ChambreDAO :
|
import org.hibernate.Transaction; import javax.naming.InitialContext; public static void
insert(Chambre chambre) {
Session session;
Transaction tx; //Creation
de notre objet Session grâce à notre HibernateUtil try{
session = HibernateUtil.currentSession();
//Ouverture de notre transaction avec Hibernate grace //
a la session tx
= session.beginTransaction(); //
On sauve, on renvoi notre bean à la session Hibernate
session.save(chambre); //
Nous commitons la transaction vers la base
tx.commit();
//Enfin on ferme la session HibernateUtil.closeSession(); } catch (Exception
ex){ex.printStackTrace();} } |
Outils utilisés |
Rational
Rose Enterprise Edition 2003
NetBeans
IDE 5.5.1
Tomcat
5.5
JDK
1.6
Struts
1.2
Struts
2.0.6
JSF
1.1
Hibernate
3.0
PHPMyAdmin
2.6.1
|
Documents utilisés |
Apache
[http://struts.apache.org/1.x/index.html]
Developpez
[http://brabant.developpez.com/tutoriel/java/netbeans/5.0/struts]
JMDoudoux
[http://www.jmdoudoux.fr/java/dej/indexavecframes.htm]
Labo-Sun [http://www.labo-sun.com/resource-fr-essentiels-859-5-java-j2ee-struts-un-framework-mvc-pour-vos-applications-j2ee.htm]
Roseindia
[http://www.roseindia.net/struts/struts2/index.shtml]