PROJET JEE APPROFONDIE : FORUM

Mise en pratique des frameworks Stripes & Hibernate

par : JIANG Manjun, KOCZWARA Christian, LEFAUX Maxime, DELHOMME Fabrice Kei,  MORALES Christian

Sommaire :
I.Introduction
II.Frameworks
   1. Stripes
   2. Hibernate

I. INTRODUCTION

Le but du projet JEE Approfondi est de découvrir des exemples de Framework. Nous en avons sélectionné deux. 
Puis,  nous avons appris à les installer, à les configurer puis à les utiliser afin de développer un forum de discussion.

Voici le forum que nous avons implémenté : Forum
Voici le document récapitulatif des foncionnalités du forum : Document

Ce module est la prolongation du cours de JEE que nous avons eu au premier semestre et nous a permis d’approfondir nos connaissances dans le domaine du développement web et du JEE.

II. FRAMEWORKS

Pour développer notre forum en JEE, nous avons utilisé les Framework Hibernate et Stripes.

    1. Stripes

        1.1 Description

Stripes est un Framework basé sur MVC (Model View Controller), qui est performant et facile à apprendre avec des configurations très précises, 
mais de nos jours, il est encore peu utilisé comparé à ses concurrents(Struts notamment).

        1.2 Manuel d’installation

Télécharger Stripes à cette adresse : http://sourceforge.net/projects/stripes/files/ .

Créer un projet sous eclipse File » New » Dynamic Web Project.

Mettre les commons-logging.jar, cos.jar, stripes.jar dans WebContent\WEB-INF\lib de votre projet.

        1.3 Manuel d’utilisation

               1.3.1 configuration

Après l'ajout des .jar, il faut créer les .properties ci-dessous à mettre dans src :

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4Jlogger

 

### direct log messages to stdout ###

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.Target=System.out

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

 

### direct messages to file ###

#log4j.appender.file=org.apache.log4j.FileAppender

#log4j.appender.file.File=/tmp/stripes.log

#log4j.appender.file.layout=org.apache.log4j.PatternLayout

#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

 

### set log levels - for more verbose logging change 'info' to 'debug' ###

#log4j.rootLogger=INFO, stdout, file

#log4j.logger.net.sourceforge.stripes=DEBUG

 

Ces deux derniers fichiers sont des fichiers de configuration de logging.

Voici un exemple du fichier : 

 

# Resource strings used by the <stripes:errors> tag when there are no nested tags

stripes.errors.header=<div style="color:#b72222; font-weight: bold">Please fix the following errors:</div><ol>

stripes.errors.beforeError=<li style="color: #b72222;">

stripes.errors.afterError=</li>

stripes.errors.footer=</ol>

 

# Resource strings used by the <stripes:errors> tag when displaying errors for a

# specific field (e.g. <stripes:errors field="password"/>). If not supplied the

# values above will be used instead.

stripes.fieldErrors.header=

stripes.fieldErrors.beforeError=<span style="color: #b72222;">

stripes.fieldErrors.afterError=</span><br />

stripes.fieldErrors.footer=

 

# Resource strings used by the stripes:messages tag

stripes.messages.header=<ul class="messages">

stripes.messages.beforeMessage=<li>

stripes.messages.afterMessage=</li>

stripes.messages.footer=</ul>

 

# Validation error messages produced by Stripes' built-in converter classes. These

# are default error messages and can be overridden on per-field and per-form levels.

# Using the 'invalidNumber' error for a field 'age' of a form posting to

# '/user/Profile.action', the keys looked for (in order) would be:

#      1: /user/Profile.action.age.invalidNumber

#      2: /user/Profile.action.age.errorMessage

#      3: age.errorMessage

#      4: /user/Profile.action.invalidNumber

#      5: converter.number.invalidNumber

converter.number.invalidNumber=The value ({1}) entered in field {0} must be a valid number

converter.byte.outOfRange=The value ({1}) entered in field {0} was out of the range {2} to {3}

converter.short.outOfRange=The value ({1}) entered in field {0} was out of the range {2} to {3}

converter.integer.outOfRange=The value ({1}) entered in field {0} was out of the range {2} to {3}

converter.float.outOfRange=The value ({1}) entered in field {0} was out of the range {2} to {3}

converter.enum.notAnEnumeratedValue=The value "{1}" is not a valid value for field {0}

converter.date.invalidDate=The value ({1}) entered in field {0} must be a valid date

converter.email.invalidEmail=The value ({1}) entered is not a valid email address

converter.creditCard.invalidCreditCard=The value ({1}) entered is not a valid credit card number

 

# Validation error messages produced by Stripes' annotation based validations. These

# are default error messages and can be overridden on per-field and per-form levels.

# Using the 'valueNotPresent' required field error for a field 'username' of a form

# posting to '/user/Register.action', the keys looked for (in order) would be:

#      1: /user/Register.action.username.valueNotPresent

#      2: /user/Register.action.username.errorMessage

#      3: username.errorMessage

#      4: /user/Register.action.valueNotPresent

#      5: validation.required.valueNotPresent

validation.required.valueNotPresent={0} is a required field

validation.minlength.valueTooShort={0} must be at least {2} characters long

validation.maxlength.valueTooLong={0} must be no more than {2} characters long

validation.minvalue.valueBelowMinimum=The minimum allowed value for {0} is {2}

validation.maxvalue.valueAboveMaximum=The maximum allowed value for {0} is {2}

validation.mask.valueDoesNotMatch=<em>{1}</em> is not a valid {0}

validation.expression.valueFailedExpression=The value supplied ({1}) for field {0} is invalid

validation.file.postBodyTooBig=Total upload size of {3} KB exceeds the maximum size of {2} KB

 

 

Exemple de la gestion des langues dans le StripesRessource.properties

Si dans votre jsp, vous avez la balise

<stripes:label name="nom1"/>

 

alors dans  « StripesResources.properties » , à la place de « … » , mettez

nom1= bonjour

Ainsi, vous verrez « bonjour » apparaître lors de compilation à la place des label de votre projet.

Maintenant, modifier la configuration par défaut du fichier « web.xml » situé dans WebContent\WEB-INF, de la facon suivante :

<?xml version="1.0" encoding="UTF-8"?>

 

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee

         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"

         version="2.4">

 

    <description>

      Projet_forum

    </description>

    <display-name>Projet_forum</display-name>

   

    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->

    <!--              Configuration of the Stripes Filter.                   -->

    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->

    <filter>

        <description>

            Provides essential configuration and request processing services

            for the Stripes framework.

        </description>

        <display-name>Stripes Filter</display-name>

        <filter-name>StripesFilter</filter-name>

        <filter-class>net.sourceforge.stripes.controller.StripesFilter</filter-class>

 

        <!-- REQUIRED init parameter for the Stripes Filter. -->

        <init-param>

            <param-name>ActionResolver.Packages</param-name>

            <param-value>actionBean</param-value>

        </init-param>

 

        <!-- Optional init parameter for the Stripes Filter. -->

       

        <init-param>

            <param-name>ActionBeanContext.Class</param-name>

            <param-value>actionBean.ForumActionBeanContext</param-value>

        </init-param>

       

    </filter>

 

    <filter-mapping>

        <filter-name>StripesFilter</filter-name>

        <url-pattern>*.jsp</url-pattern>

        <dispatcher>REQUEST</dispatcher>

    </filter-mapping>

 

    <filter-mapping>

        <filter-name>StripesFilter</filter-name>

        <servlet-name>StripesDispatcher</servlet-name>

        <dispatcher>REQUEST</dispatcher>

    </filter-mapping>

 

    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->

    <!--         Configuration of the Stripes dispatcher Servlet.            -->

    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->

    <servlet>

        <servlet-name>StripesDispatcher</servlet-name>

        <servlet-class>net.sourceforge.stripes.controller.DispatcherServlet</servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

 

    <servlet-mapping>

        <servlet-name>StripesDispatcher</servlet-name>

        <url-pattern>*.action</url-pattern>

    </servlet-mapping>

   

    <welcome-file-list>

    <welcome-file>/accueil.jsp</welcome-file>

  </welcome-file-list>

</web-app>

Ajouter notamment le nom du package dans lequel se trouvent vos actionBeans entre les balises <param-value> comme ceci :

        <init-param>

            <param-name>ActionResolver.Packages</param-name>

            <param-value>nomPackage</param-value>

        </init-param>

 

L'information contenue dans le "init-param" permet de spécifier l'endroit où le contexte (get / set) a été centralisé. Il n'est pas obligatoire, mais permet d'externaliser le context du projet, et ainsi de ne pas surcharger vos classes actionBeans

     <init-param>

            <param-name>ActionBeanContext.Class</param-name>

            <param-value>actionBean.ForumActionBeanContext</param-value>

     </init-param>


            1.3.2 JSP

 

Maintenant on va passer aux fichiers clients. Voici l'exemple que vous propose le site de Stripes :  Calculer la somme de 2 nombres.

<%@ page contentType="text/html;charset=UTF-8" language="java"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

 

<html>

  <head><title>Mon Premier Stripe</title></head>

  <body>

    <h1> Entrez nos identifiants pour accéder à votre comptre :</h1>   

 

    <stripes:form beanclass="actionBean.LoginActionBean" focus="">

               

     <table>

                 <tr>

                                <td>Login :</td>

                                <td>

              <stripes:text name="pseudo" value="${actionBean.pseudo}"/>

              <stripes:errors field="pseudo"/>

             </td>

                </tr>

                <tr>

                               <td>Mot de passe :</td>

                               <td>

             <stripes:password name="pass" />

             <stripes:errors field="pass"/>

            </td>

                </tr>

      <tr>

              <td colspan="2">

                 <stripes:submit name="connect" value="Connection" />

              </td>

      </tr>

  </table>

</stripes:form>

</body>

</html>

 

Ceci est l'équivalant en Stripes du tag HTML <input type="text"/>, mais qui a une fonction de pre-population et re-population de la data formulaire, et peut modifier la façon dont un tag s'affiche quand il y a des erreurs. Le nom pseudo est le même que celui de la propriété dans l'ActionBean qui reçoit la requête.

Comme vous pouvez constater, on peut aussi utiliser les "Expression Language" (EL) pour montrer la propriété pseudo de l’actionBean si celle-ci est présente.

Le tag stripes:submit a aussi pour fonction de placer le texte localisé sur le bouton, dont on n'a pas besoin ici, donc le tag utilise tout simplement l'attribut de 'value' qui est 'Connection'. Le nom du bouton submit, 'connect', est très important, car il est lié à la méthode qui sera exécutée dans l'ActionBean attaché au formulaire.

 

 

            1.3.3 ActionBean

L'actionBean est l'objet qui va traiter les données transmises par l'intermédiaire du formulaire client. Il définit à la fois les propriétés et la logique de traitement du formulaire.

Stripes n'a pas besoin de configuration externe pour connaître les implémentations de l'actionBean dans une application, ni pour faire une liaison entre le JSP et l'actionBean. Toute l'information nécessaire à propos du form et de l’action est dans l'actionBean lui-même. C’est pourquoi Stripes est facile à apprendre.

Voici un actionBean « LoginActionBean.java » qui traite de la jsp précédente :

package actionBean;

 

import net.sourceforge.stripes.action.ActionBean;

import net.sourceforge.stripes.action.ActionBeanContext;

import net.sourceforge.stripes.action.DefaultHandler;

import net.sourceforge.stripes.action.ForwardResolution;

import net.sourceforge.stripes.action.Resolution;

import net.sourceforge.stripes.validation.Validate;

 

 

public class LoginActionBean implements ActionBean{

 

                @Validate(required=true)private String pseudo;

                @Validate(required=true)private String pass;

                private ActionBeanContext context;

               

                public String getPseudo() {

                               return pseudo;

                }

 

                public void setPseudo(String pseudo) {

                               this.pseudo = pseudo;

                }

 

                public String getPass() {

                               return pass;

                }

 

                public void setPass(String pass) {

                               this.pass = pass;

                }

               

    public ActionBeanContext getContext() { return context; }

    public void setContext(ActionBeanContext context) { this.context = context; }

               

   

    @DefaultHandler

                 public Resolution connect() {

                               return new ForwardResolution("/accueil.jsp");

                              

                 }

}

 

·         Une implémentation d’ActionBean est obligatoire.

·         @Validate(required=true) indique que c’est un champ obligatoire, si jamais ce champ n’est pas rempli, il va faire appel au fichier .properties et ensuite renvoyer le message d’erreur.

    

2. Hibernate

        2.1 Description

Hibernate est un projet open source visant à proposer un outil de mapping entre les objets et des données stockées dans une base de données relationnelle. Pour notre projet, nous avons utiliser Hibernate Tools afin de générer nos beans automatiquement. Toutefois, il est possible d'en utiliser d'autres commes par exemple Hibernate Synchronizer (vu en cours de JEE Approfondi).

        2.2 Manuel d’installation

Dans un premier temps, il vous faut télécharger puis installer hibernate (V3) :

                                                                                                                http://www.hibernate.org

Ensuite faites help > software updates > available softwares > add Site, puis entrez l'url suivante : http://download.jboss.org/jbosstools/updates/stable

Faites ok, puis sélectionnez le tout et installez.

Ajoutez les librairies Hivernates suivantes à votre projet dans Web-Content/WEB-INF/librairies :
Pour MySQL, ajouter mysql-connector-java-5.1.9.jar comme librairie.
                                                                                       

        2.3 Manuel d’utilisation

               2.3.1 Configuration de la connexion entre le workspace et la base de données

Dans un premier temps, avant de générer nos beans, il faut configurer le lien entre la base de données et le workspace. Pour ce faire, passez en "vue" Hibernate. Puis dans l'onglet hibernate configuration, faites clic droit "add configuration". Ensuite, donnez un nom à votre configuration puis sélectionnez le projet sur lequel vous travaillez.
Entsuite pour le champ database connexion, faite new (ou sélectionner en une si déjà existante). Dans la nouvelle fenêtre qui apparait, nous avons sélectionné MySQL pour notre projet (voir partie suivante). Puis nous avons remplacé le nom et l'url par défaut ("database") par le nom de notre bdd. Faites ensuite apply, puis ok.

Attention : Si vous n'arrivez pas à voir votre base de données lorsque vous dérouler votre configuration hibernate, faites clic droit sur votre config, "édit configuration" puis aller dans le classpath et ajouter avec le boutton addJar la librairie pour MySQL (voir sous-partie précécente).

               2.3.2 Générer automatiquement les beans et les fichiers de mapping correspondant

Ce qui est pratique avec hibernate tools, c'est que vos beans, vos fichiers de mappings et le fichier "hibernate.cfg.xml" sont générés automatiquement. Le dernier fichier cité est celui qui contient vos paramètres de connexion et le classpath des fichiers de mapping.

Astuce : Prévoyer un package où stocker vos nouveaux fichiers

Toujours sur votre "vue eclipse" hibernate. A côté du run last tool que vous utilisez habituellemnt est apparu le boutton run_NewConfiguration. Sélectionnez "Hibernate Code Generation Configurations" dans le menu déroulant.
Dans la nouvelle fenêtre, sélectionnez le nom de la configuration hibernate que vous allez utiliser. Ensuite l'endroit où vous allez générer vos fichiers.

Dans l'onglet exporters, cocher :
Faites apply, puis run. Et c'est parti !

Attention : N'oubliez pas de rajouter le nom du package à chacun de vos fichiers de classes si ce n'est pas fait automatiquement. Et si vous choisissez de séparer vos beans de vos fichiers de mapping, n'oubliez pas de changer les classpath dans le XML ! Sinon, votre fichier .cfg.xml ne retrouvera plus vos fichiers de mapping. En clair, ça ne fonctionnera pas.
   

               2.3.3HibernateUtil.java

Dans cette classe vous trouvez les méthodes de création et fin de session qui vous seront nécessaires à chaque fois que vous voudrez faire une interaction avec la base de données (lecture/écriture).


import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
public class HibernateUtil {
 
    private static final SessionFactory sessionFactory = buildSessionFactory();
 
    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
 
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
 
    public static void shutdown() {
        // Close caches and connection pools
        getSessionFactory().close();
    }
 
}



               2.3.4 HQL


Hibernate possède son propre langage, le HQL. Il est plus facile et intuitif que SQL. HQL manipule des beans, aussi bien pour l'insertion (INSERT) que la suppression de données (DELETE) en BDD. Cependant, on doit manipuler les champs de table pour la mise à jour (UPDATE).

               2.3.5 Exemple d'utilisation

Voici un exemple d'utilisation d'hibernate dans un projet. On remarque bien qu'il faut dans un premier temps ouvrir un session hibernate puis intéragir avec la base de données. N'oubliez pas de commiter votre transaction avant de fermer la session.

Ajout d'un utilisateur dans une table. Le paramètre le la fonction est un bean utilisateur.

public void ajouterUtilisateur(Utilisateur u)

    {

        Session session = HibernateUtil.getSessionFactory().openSession();

        Transaction tx = session.beginTransaction();   

        session.save(u);

        session.flush();

         tx.commit();

         session.close(); 

    }



Nous vous laissons découvrir par vous même les fonctionnalité de Stripes et d'Hibernate.
Bonne utilisation !