insat

Institut National des Sciences Appliquées et de Technologies

Développer une application avec Struts, JSF et Hibernate à l'aide de NetBeans

logo_java_tm_51_108

struts001

JavaServer Faces

hibernate

nb-logo2

 

Par Walid CHARFI

Olfa BEN HADJ ALAYA

cw www.glavance.tk


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

Configuration de Struts en quelques mots

Une application Web Java utilise souvent un descripteur de déploiement nommé « web.xml » permettant d’initialiser les ressources tel que les servlets (module de code Java exécuté sur un serveur d’application) et les taglibs (librairies de balises).

De la même manière, le framework utilise un fichier de configuration nommé « struts-config.xml » pour initialiser ses propres ressources. Ces ressources incluent les ActionForm pour la collecte des données entrées par l’utilisateur, les ActionMappings pour la direction de ses données vers les Actions côté serveur, et  les ActionForwards pour la sélection des pages de sortie.

 

Voici une explication de la terminologie employée dans Struts:

 

ActionForm

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.

ActionMapping

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 :

  • type : Nom complet de la classe Java d’implémentation de l’Action utilisé par le mapping.
  • name : Nom de l’ActionForm qu’utilisera l’Action. Ce nom est défini dans la balise <form-bean> du fichier struts-config.
  • path : Chemin utilisé pour désigner le mapping.
  • Balise forward : Couple Jeton/Chemin vers la cible.
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 :
  • mapping : La « carthographie » de sélection de la cible.
  • form : Le bean ActionForm associé à cette requête.
  • request : La requête HTTP traitée.
  • response : La réponse HTTP traitée.

(Source : http://struts.apache.org/1.x/index.html)

Struts est-il le meilleur choix pour tout type de projet ?

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.

 

//Action
Public 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 :

 

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/)

Visual Web Pack pour NetBeans 5.5 est l’un des supports leaders en matière de composants JavaServer Faces. Il permet, entre autre, de glisser-déposer (drag-and-drop) des composants JSF (tel que Table, Calendar, Tree ou Tab set), de les personnaliser et d’implémenter le code côté serveur des transporteurs d’événements (event handlers).

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 la DateSource et effectuer le traitement voulu on procède comme suit :

 

DataSource ds=(DataSource) new        InitialContext().lookup("java:comp/env/jdbc/grandhotel");

//creation de la DataSource avec l’url de la base

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]