MVC 2

Par M.Youssfi

Les API de J2EE

MVC

Si nous cherchons à mettre en œuvre une architecture MVC via un environnement J2EE, on peut donc faire les rapprochements suivants :
 

Un contrôleur est implémenté sous forme de servlet Java. Le modèle consiste en l'implémentation de la logique métier du site Web.

A ce niveau, l'architecture peut être plus ou moins souple en vous laissant opter pour le type de composants que vous souhaitez utiliser : composants Java Beans ou composants EJB (Enterprise Java Bean).

Chaque vue est implémentée via une JSP.

MVC2

Dans la pratique, on peut reprocher une chose aux API implémentant un modèle MVC sous environnement J2EE : il est nécessaire de coder un grand nombre de servlets Java pour réceptionner les requêtes clientes. Dans le but d'améliorer ce point, certains frameworks préfèrent implémenter une architecture MVC 2. Dans une telle architecture, il n'existe plus qu'un seul et unique contrôleur réceptionnant toutes les requêtes clientes. Le contrôleur redirige l'exécution vers différentes vues de manière déclarative, dans un fichier XML.

MVC2

Il existe un grand nombre de framework basés sur une architecture MVC ou MVC 2. Citons, à titre d'exemple le framework Baraccuda, WebWork, Coccoon … Utiliser le framework Struts peut s'avérer être un bon choix. Struts est développé par le groupe Apache. Ce groupe est aussi l'auteur du serveur Web du même nom. En fait, Struts fait partie du projet Jakarta d'Apache.

Structure d’une application J2EE

L’architecture J2EE définit un standart d'empaquetage et de déploiement d'applications WEB J2EE. Une application J2EE se compose généralement des archives suivantes:
 

.JAR : Java Archive; Archive qui contient les composants métiers ( EJB) ou qui regroupe des biliothèques de classes. .WAR : Web Archive; Archive qui contient les composants d’une application web:
 

Servlets, JSP, et descripteurs de déploiement (Fichiers XML) Images, Classes du modèle et autres bibliothèques (Fichiers.jar)

.EAR : Entreprise Archive; Archive principale de l’application J2EE qui est prête à être déployé sur un serveur d’application. Elle regroupe tous les composants de l’application à savoir:
 

Les archives web (.WAR)

Structure d’une application web J2EE

Dans la suite de ce cours, seules les l'archives Web nous intéresserons. C'est effectivement dans ces archives qu'ils va nous falloir installer le support pour le framework Struts. Un WAR est une archive qui contient donc lui-même un certain nombre de fichiers et de dossiers. La structure (la hiérarchie) de ces dossiers est en fait fortement imposée.

Structure d’une application Web J2EE

Ainsi, votre application Web se doit obligatoirement de contenir un répertoire WEBINF : c’est dans ce dossier que nous allons trouver le code Java de l'application. Mais encore une fois, des sous-dossiers précis doivent être présents. Parmi ces dossiers, citons notamment le répertoire classes. Il contient l'ensemble des ".class" utilisés par vos JSP et par vos servlets Un autre répertoire important est à signaler : le répertoire lib. Si votre application utilise des librairies additionnelles, c'est ici qu'elles devront être stockées.

Intégration de struts dans une application web

Il est maintenant le temps de débuter notre installation. Pour ce faire, connectez vous sur le site de Struts (donc sur http://jakarta.apache.org/struts/ index.html) et téléchargez l'installation du module Struts. Une fois l'archive sur votre machine, désarchivez-là. Vous devriez y trouver un certain nombre de fichiers d'extensions diverses. Dans le répertoire qui va contenir votre application Web, créez les différents dossiers dont nous venons de parler précédemment. Nous allons maintenant y ajouter certains fichiers du module Struts.

Intégration de struts dans une application web

Copier toutes les archives Java (d'extension .jar) dans le répertoire lib de votre application.

A ce stade, tout le code Struts est disponible, mais ce n'est pas tout

Une possibilité intéressante de JSP est de pouvoir définir nos propres tags XML

pour ce faire, il faut aussi fournir des fichiers .tld (Tag Library Definition) dans WEB-INF Struts exploitant cette possibilité, il vous faut donc aussi copier l'ensemble des fichiers d'extension .tld dans le répertoire WEB-INF.

Enfin, il faut définir des descripteurs de déploiement compatible avec J2EE et Struts. Ces fichiers (d'extension .xml) doivent être aussi placés dans le répertoire WEB-INF à savoir:.

web.xml : descripteur de déploiement de servlets

Composants fondamentaux de l’architecture struts

Struts-config.xml
Fichier struts-config.xml :

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/strutsconfig_1_1.dtd"> <struts-config> </struts-config>

Déploiement de la servler web.xml

Fichier web.xml :

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/dtd/web-app_2_2.dtd"> <web-app> <display-name>StrutsWAR</display-name>

<servlet>

<servlet-name>action</servlet-name> <servlet-class> org.apache.struts.action.ActionServlet </servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param>
<init-param> <param-name>debug</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>application</param-name> <param-value>ApplicationResources</param-value> </init-param> <load-on-startup>2</load-on-startup>

</servlet>

Web.xml
<servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
<taglib> <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri> <taglib-location>/WEB-INF/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri> <taglib-location>/WEB-INF/struts-html.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri> <taglib-location>/WEB-INF/struts-logic.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-template.tld</taglib-uri> <taglib-location>/WEB-INF/struts-template.tld</taglib-location> </taglib> </web-app>

Concepts généraux de struts

Struts étant basé sur un architecture MVC 2, un seul contrôleur principal se doit d'être définit. Le contrôleur de notre application est donc la servlet org.apache.struts.action.ActionServlet. Ce contrôleur est configuré à travers le fichier struts-config.xml Dans le descripteur de déploiement web.xml, nous avons associé toutes les requêtes HTTP qui se termine par .do à cette servlet. Ensuite on déclare les librairies de tag XML que nous allons utiliser pour faciliter la

Concepts généraux de struts
 

Dans le fichier de configuration struts-config.xml, chaque URL doit être associée à une action Pour chaque requête, le contrôleur place les données envoyées par le client dans un objet qu’on appelle The Form Bean (Bean de formulaire). C’est un objet d’une classe que vous allez développer et qui hérite de la classe ActionForm. Ensuite le contrôleur fait appel à une objet de la classe d’action. Une autre classe que vous aller développer qui hérite de la classe Action.

Dans cette classe, nous pouvons implémenter les actions à exécuter pour cette requête. Ces actions font généralement appel au modèle. Pour placer ensuite les données à afficher dans le bean de formulaire A la fin, elle fait une redirection vers la vue correspondante qui est une page JSP qui se servira du bean de formulaire pour afficher les résultats. Cette classe d’action est appelée également un sous

Concepts généraux de struts

Les vues sont généralement des pages JSP qui utilisent les librairies de tags offertes par struts. Ces fichiers on des extensions .tld Enfin, pour ce qui est du modèle, le Framework Struts ne vous impose rien et aucune classe ne vous est fournie. Cela vous laisse une totale liberté sur les choix des technologies à utiliser pour l'implémentation du modèle. Ainsi, vous pouvez opter pour un codage basique en implémentant des composants Java standard. Mais si le besoin s'en fait ressentir, vous pouvez aussi opter pour l'utilisation de

Exemple d’application

Supposant que nous souhaitions créer une application web, basée sur struts, qui permet de faire

L’authentification d’un utilisateur enregistré dans une base de donnée. L’ajout et l’affichage des utilisateurs.

Chaque utilisateur est défini par un identifiant, le login, le mot de passe, email et sa ville

Base de données
Table UTILISATEURS

Modèle

 

Une classe persistante Utilisateur, Une classe non persistante GestUsers qui contient les méthode métiers et une classe utilitaire qui contient les paramètres de connexion à la

Authentification

Le formulaire : Login.jsp

Login.jsp
<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%> <html> <body> <html:form action="login.do" method="post" > Login:<html:text property="login" /><br/> Pass :<html:password property="pass" /><br/> <html:submit value="Valider" /> </html:form> </body> </html>

Action Form : LoginForm.java

Ce bean permet de stocker les données du formulaire à savoir login et pass Il permet également de stocker l’objet Utilisateur s’il existe dans la base de données

L’action associée: LoginAction.java
import javax.servlet.http.*; import mod.app.GestUsers; import mod.app.Utilisateur; import org.apache.struts.action.*; public class LoginAction extends Action { public ActionForward execute( ActionMapping map, ActionForm form, HttpServletRequest request, HttpServletResponse response)throws Exception{ LoginForm lf=(LoginForm)form; GestUsers gu=new GestUsers(); Utilisateur u=gu.loadUser(lf.getLogin(),lf.getPass()); if(u!=null){ lf.setUser(u); return map.findForward("bienvenue"); } else{ return map.findForward("notAutorised"); } } }

Struts-config.xml
<struts-config> <form-beans> <form-bean name="logFor" type="LoginForm"/> </form-beans> <global-forwards> <forward name="bienvenue" path="/BienVenue.jsp"/> <forward name="notAutorised" path="/Login.jsp"/> </global-forwards> <action-mappings> <action path="/login“ name="logFor" type="LoginAction“ scope="request" /> </action-mappings> <message-resources parameter="ApplicationResources"/> </struts-config>

Bienvenue.jsp
<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <html> <head> <title>Bien Venue</title> </head> <body bgcolor="#FFFFFF"> <h3> Id User :<bean:write name="logFor" property="user.idUser" /><br/> Login :<bean:write name="logFor" property="user.login" /><br/> Pass :<bean:write name="logFor" property="user.pass" /><br/> Email:<bean:write name="logFor" property="user.email" /><br/> Ville :<bean:write name="logFor" property="user.ville" /><br/> </h3>

Ajout et affichage des utilisateurs

Aperçu de la vue à réaliser

Form bean : UsersForm.java

D’après notre vue, nous avons, dans le form bean, des attributs qui permettent de :

stocker les données du formulaire : login, pass, email et ville Stocker les utilisateurs à afficher dans un vecteur. La propriété users, de type Vector serait utilisée pour ce fait

Action associée : UsersAction.java
import javax.servlet.http.*; import mod.app.GestUsers; import mod.app.Utilisateur; import org.apache.struts.action.*; public class UsersAction extends Action { public ActionForward execute( ActionMapping map, ActionForm form, HttpServletRequest request, HttpServletResponse response)throws Exception { UsersForm uf=(UsersForm)form; GestUsers gu=new GestUsers(); gu.addUser(uf.getLogin(),uf.getPass(),uf.getEmail(),uf.getVille() ); uf.setUsers(gu.selectAll()); return map.findForward("afficheUsers"); }

Mise à jour de struts-config.xml
<struts-config> <form-beans> <form-bean name="logFor" type="LoginForm"/> <form-bean name="usersForm" type="UsersForm"/> </form-beans> <global-forwards> <forward name="bienvenue" path="/BienVenue.jsp"/> <forward name="notAutorised" path="/Login.jsp"/> <forward name="afficheUsers" path="/Affiche.jsp"/> </global-forwards> <action-mappings> <action path="/login" name="logFor" type="LoginAction" scope="request" input="/Login.jsp" validate="true« /> <action path="/addUser" name="usersForm" type="UsersAction" scope="request" /> </action-mappings> <message-resources parameter="ApplicationResources"/>

Affiche.jsp
<%@ page language="java" %> <%@ page import="mod.app.*" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%> <!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en"> <html><head><title>Utilisateurs</title></head> <body bgcolor="#FFFFFF"> <table border="1" width="75%" align="center"> <tr> <td>Id</td><td>Login</td><td>Pass</td><td>Ville</td><td>E mail</td> </tr> <html:form action="addUser.do" > <tr> <td></td> <td><html:text property="login" /></td> <td><html:text property="pass" /></td> <td><html:text property="email" /></td> <td><html:text property="ville" /></td> <td><html:submit value="Ajouter" /></td>

Implémentation de la vue : Affiche.jsp (suite)
….(suite) <logic:iterate id="user" name="usersForm" property="users" type="Utilisateur" > <tr> <td><bean:write name="user" property="idUser" /></td> <td><bean:write name="user" property="login" /></td> <td><bean:write name="user" property="pass" /></td> <td><bean:write name="user" property="email" /></td> <td><bean:write name="user" property="ville" /></td> </tr> </logic:iterate> </body> </html>

Validation de formulaires

Un des problèmes classique à gérer, si vous fournissez des formulaires Web, consiste à valider que les données nécessaires ont bien été renseignées. Le framework Struts propose, dans cet objectif, des mécanismes directement intégrés dans l'architecture de base.

Classe ActionForm
 

La classe ActionForm définie une méthode validate : A ce niveau, le corps de cette méthode est vide. Celle-ci accepte deux paramètres comme le montre l'exemple ci-dessous. Le framework Struts invoque automatiquement cette méthode après avoir chargé les données du formulaire dans le bean, mais avant l'invocation de la méthode execute. En fait, la méthode execute ne sera invoquée que et uniquement que si la méthode de

Méthode validate() de ActionForm
public ActionErrors validate( ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors(); if (this.getUsername() == null || this.getUsername().equals("") errors.add("username", new ActionError("x")); System.out.println("Error : bad username");} if (this.getPassword() == null || this.getPassword().equals("")) { errors.add("password",new ActionError("y")); System.out.println("Error : bad password");} return errors; }

Modification du fichier de configuration
<action-mappings> <action path="/login“ name="LoginForm" type="LoginAction" input="/Login.jsp" validate="true"> </action> </action-mapping> <message-resources parameter="ressources.miage"/>

Fichier de ressources

/WEB-INF/classes/ressources/miage.properties

x=<li>Vous devez indiquer un Login</li> y=<li>Vous devez indiquer un Mot de passe</li>

Ce fichier a pour rôle d’assurer la correspondance entre les identifiants des erreurs et les messages à afficher. En utilisant la librairie struts-bean.tld, on peut affichier la valeur d’une clé en écrivant:

<bean:message key="x"/> <li>Vous de devez indiquer un login</li>

Ce qui permettra d’afficher la valeur de la clé x :

Pour afficher les erreurs dans la page correspondant à l’attribut input de l’élément action càd. dans la page Login.jsp, on écrit  <html:errors />

Internationalisation via Struts
 

Outre la mise en œuvre d'une architecture MVC, Struts permet aussi de prendre en charge l'internationalisation de vos applications Web. Cela signifie que vous avez à votre disposition un mécanisme simple permettant de générer un contenu adapté à la localisation de l'utilisateur. Notez aussi, à ce sujet, qu'il n'y a pas que les textes qui peuvent être amenés à changer d'une langue à une autre. Les images aussi peuvent varier. Effectivement, si l'on considère une image associée au concept de mails : les français préféreront voir une petite lettre alors que les américains reprendront la symbolique de boîte à lettre. Mais, si l'on y réfléchit, vis-à-vis du tag <IMG> c'est le contenu du paramètre src qui devra varier : donc une chaîne de caractères.

Internationalisation via Struts

La mise en œuvre de l'internationalisation passe par la définition de fichiers de ressources. Chacun des fichiers sera associé à une langue particulière : cette information se retrouvera dans le nom du fichier. Tous les noms de fichiers de ressources devront avoir le même préfixe. Celui-ci est spécifié dans le fichier web.xml sous forme de paramètre de la servlet de contrôle. Les noms se continuent avec un caractère _ puis le code de la langue (codé sur deux caractères) et enfin ils se terminent via l'extension .properties.

Définition des fichiers de resources
 

Ces fichiers de ressources se doivent d'être placés dans le répertoire classes de votre application Web pour pouvoir être pris en charge par le serveur. Ils contiennent, comme leur nom l'indique, des ressources : en fait il s'agit de paires de données clé/valeur. Dans votre programme, vous référencerez les clés afin d'injecter les valeurs associées. Dans l'exemple ci-dessous, deux fichiers de ressources sont définis. Ils sont, certes, très simplistes : une seule ressource est définie dans chaque fichier. Mais notez bien que la clé est identique d'un fichier à un autre.  Fichier "ApplicationResources.properties"
CaddieVirtuel.Test.Title=Virtual Caddy

Fichier "ApplicationResources_fr.properties"
CaddieVirtuel.Test.Title=Caddie Virtuel

Web.xml

<servlet>
<servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet </servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <init-param> <param-name>debug</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>application</param-name> <param-value>ApplicationResources</param-value> </init-param> <load-on-startup>2</load-on-startup>

</servlet>

Utilisation des ressources
 

Le framework Struts définit plusieurs possibilités d'utilisation de ces ressources. Citons notamment l'emploie du tag <bean:massage> définit dans la librairie /WEB-INF/struts-bean.tld. Ce tag injecte la valeur associée à une clé donnée : vous spécifiez la clé recherchée par l'intermédiaire de l'attribut key.

<html:html locale="true"> <!-- Suite de la page --> Injection d'une valeur : <bean:message key="searchKey" /> <!-- Suite de la page --> </html:html>  Le tag <html:html> accepte notamment un paramètre local. Fixez lui la valeur true afin d'autoriser l'internationalisation.

Autres concepts Struts

La bibliothèque logic:

de

tags

struts-

Cette librairie de tags permet principalement d'obtenir des structures de contrôles au sein des JSP. Vous pouvez ainsi exécuter des boucles, pour mettre en forme des ensembles de données, exécuter des conditions et de tester des expressions régulières.

La bibliothèque de tags strutslogic:
:CaddyForm
 :Article
idArticle designation marque price

Exemple:

articles:Vecto r

<table width="100%" border="1"> :Article <tr> idArticle <th>Identifiant article</th> designation <th>Désignation</th> marque <th>Marque</th> price <th>Prix unitaire</th> </tr> <logic:iterate id="art" name="CaddyForm" property="articles" type="Article" > <tr> <td><bean:write name="art" property="idArticle" /></td> <td><bean:write name="art" property="designation" /></td> <td><bean:write name="art" property="marque" /></td> <td><bean:write name="art" property="price" /></td> </tr> </logic:iterate> </table>

La bibliothèque de tags struts-logic:

L'exemple précédent vous montre comment présenter un ensemble de données sous forme de tableau HTML. Pour ce faire, nous utilisons le tag Struts <logic:iterate>. Ce tag accepte quelques attributs. Citons notamment
 

name : permet de retrouver un bean à partir de la requête property : permet de dire qu'elle est la propriété qui retourne la collection d'éléments à traiter.

Le code HTML compris entre les tags <logic:iterate> et </logic:iterate> sera répété autant de fois qu'il y aura d'objets dans la collection.

La bibliothèque de tags struts-logic:
Dans ce second exemple, une ligne de code HTML ne sera injectée dans le flux HTML que si la propriété age d'un bean nommé User, est supérieur à 17 ans. Dans le cas contraire, rien ne sera injecté dans le flux. <logic:greaterThan name="User" property="age" value="17"> <B>Vous êtes majeurs</B> </logic:greaterThan>