MVC 2 Par M.Youssfi
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) Les composants métiers pour les EJB (.JAR) Les archives de ressources (extension .RAR).
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 WEB-INF : 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.
Ainsi Struts verra ses propres ".jar" stockés dans ce dossier.
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 Struts-config.xml : pour la configuration de
struts
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/struts-config_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 rédaction des pages JSP.
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 contrôleur.
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 composants EJB (Enterprise Java Bean).
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 base de données.
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></body></html>
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"/></struts-config>
Implémentation de la vue : 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>Email</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> </tr></html:form>
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 validation ne détecte aucune erreur dans la saisie du formulaire.
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"/>
Ce qui permettra d’afficher la valeur de la clé x : <li>Vous de devez indiquer un login</li>
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 de tags struts-
logic: 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 struts-logic:
Exemple:<table width="100%" border="1"> <tr> <th>Identifiant article</th> <th>Désignation</th> <th>Marque</th> <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>
:CaddyForm
articles:Vector
:Article
idArticle
designation
marque
price
:Article
idArticle
designation
marque
price
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>