framework MVC pour applications Web Servlets JSP Philippe GENOUD UJF Février 2010 1
Rappel Architecture MVC Serveur Internet (Serveur HTTP + Serveur Servlet/JSP) Serveur SGBD Requête HTTP Controleur Controleur (Servlet) (Servlet) 1 Construit Modifie 2 Transfert Modèle Modèle (Java (Java Bean) Bean) Driver JDBC Réponse HTTP Vue Vue (JSP) (JSP) 3 Consulte Bonne séparation des différents composants d une application Web Modularité réutilisation évolutivité Séparation des compétences Philippe GENOUD UJF Février 2010 2
Frameworks Web mais mettre en œuvre une "bonne" architecture MVC reste un tâche complexe surtout si plusieurs applications doivent profiter de cette architecture nombreux frameworks pour faciliter le développement d'applications Web C'est quoi un framework? Dans le monde Java : Struts (Apache) Java Server Faces (SUN) Spring MVC Tapestry (Apache) Stripes Wicket (Apache) mais aussi dans de nombreux autres langages : Symfony (PHP) Ruby On Rails (Ruby) Django (Python) Grails (Groovy) Philippe GENOUD UJF Février 2010 3
Framework Framework (cadre d'application) "ensemble de bibliothèques et de conventions permettant le développement rapide d'applications. Il fournit suffisamment de briques logicielles et impose suffisamment de rigueur pour pouvoir produire une application aboutie et facile à maintenir. Ces composants sont organisés pour être utilisés en interaction les uns avec les autres" http://www.techno-science.net/ Différence framework / bibliothèque (librairie) avec une librairie : exécution est dirigée par le code écrit par le développeur qui fait appel aux classes de la librairie avec un framework : exécution est dirigée par le code du framework qui fait appel au code écrit par le développeur le développeur doit compléter les classes et ressources préexistantes dans le framework Philippe GENOUD UJF Février 2010 4
Struts c'est quoi? Serveur Internet (Serveur HTTP + Serveur Servlet/JSP) Serveur SGBD Requête HTTP Controleur Controleur (Servlet) (Servlet) 1 Construit Modifie 2 Transfert Modèle Modèle (Java (Java Bean) Bean) Driver JDBC Réponse HTTP Vue Vue (JSP) (JSP) 3 Consulte Struts : Framework open source (fondation apache) pour le développement d'applications Web Java respectant le modèle MVC Architecture générique pour la partie contrôleur Facilités pour la réalisation des vues Philippe GENOUD UJF Février 2010 5
Struts c'est quoi? Le framework Struts encourage les architectures basées sur l'approche Model 2 (une variante du modèle classique MVC appliquée aux applications web). Le cœur du framework Struts est une couche contrôleur basée sur les technologies les plus acceptées Servlet/JSP, JavaBeans, ResourceBundles, XML. Struts fournit son propre composant contrôleur Struts intègre d'autres technologies pour offrir le Modèle et la Vue. Pour le Modèle, Struts peut interagir avec toutes les techniques d'accès aux données comme JDBC, EJB (Entreprise JavaBeans), Hibernate Pour la Vue, Struts n'est pas limité aux JSP, il peut fonctionner aussi avec les Velocity Templates, le XSLT et d'autres systèmes de présentation. Philippe GENOUD UJF Février 2010 6
Exemple d'application Struts Philippe GENOUD UJF Février 2010 7
Documentation site de Struts http://struts.apache.org/ Struts 2.x réécriture du framework struts Struts 1.x dernière version : 1.3.10 version intégrée à NetBeans (6.7): 1.3.8 au 2/02/1020 http://struts.apache.org/1.3.8 http://struts.apache.org/1.3.8/apidocs/index.html guide utilisateur Philippe GENOUD UJF Février 2010 8
Architecture générale de Struts Fichier xml mapping vers les actions et les vues traitement la requête Regroupent les paramètres de la requête, qu'ils peuvent valider La requête est transmise au contrôleur 1 struts-config.xml struts-config.xml consulte ActionForm ActionForm ActionForm1 ActionForm1 ActionForm2 ActionForm2 Font le lien entre le contrôleur et la logique métier Serveur SGBD ActionServlet 2 ActionServlet Action Action Controleur générique (étend javax.servlet. http.httpservlet) «package» et aiguille le trafic HTTP vers le gestionnaire approprié 4 Contrôleur Action1 Action1 Action2 Action2 Modèle Modèle (Java (Java Bean) Bean) Choix et paramétrage de la vue selon la réponse de l'action et l état du contrôleur Vue Vue (JSP) (JSP) 3 Création modification des objets modèle Philippe GENOUD UJF Février 2010 9
Architecture générale de Struts 5 Génération de la page HTML Envoi au client de la présentation issue de la vue 6 page page.jsp.jsp consulte Modèle Modèle (Java (Java Bean) Bean) Struts propose des bibliothèques de Tags pour faciliter la construction des pages JSP JSTL JSTL Struts Struts html, logic,beans html, logic,beans biblio biblio perso perso Bibliothèques de tags properties.en properties.en properties.fr properties.fr Ressources Vue Fichiers de ressources pour messages utilisés dans les vues Philippe GENOUD UJF Février 2010 10
Struts par l'exemple: l application histogramme de notes serveur Web Serveur SGBD Histogramme des notes image gif Page HTML avec fréquences des notes dans un tableau Philippe GENOUD UJF Février 2010 11
Création d'un projet Struts Netbeans offre un support pour Struts (version 1.2.9) Fichiers de configuration struts Fichier de ressources pour les messages Philippe GENOUD UJF Février 2010 12 Librairies struts
Configuration : web.xml Définition du contrôleur de l'application dans le fichier web.xml Le contrôleur est une servlet générique ActionServlet ou sous classe d'actionservlet. <web-app <web-app version="2.5" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"> xmlns="http://java.sun.com/xml/ns/javaee"> <servlet> <servlet> <servlet-name>action</servlet-name> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.actionservlet</servlet-class> <servlet-class>org.apache.struts.action.actionservlet</servlet-class> <init-param> <init-param> <param-name>config</param-name> <param-name>config</param-name> <param-value>/web-inf/struts-config.xml</param-value> <param-value>/web-inf/struts-config.xml</param-value> </init-param> </init-param> </servlet> </servlet> <servlet-mapping> <servlet-mapping> <servlet-name>action</servlet-name> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> <url-pattern>*.do</url-pattern> </servlet-mapping> </servlet-mapping> </web-app> </web-app> La localisation du fichier de configuration struts-config.xml Toutes les URL se terminant par le suffixe ".do" sont orientées vers ce contrôleur Possibilité de définir plusieurs contrôleurs dans une application struts Philippe GENOUD UJF Février 2010 13
Configuration : struts-config.xml Une action est un traitement obtenu suite au passage d'une requête au contrôleur Struts Les actions sont décrites dans le fichier struts-configs dans la section <action-mappings> </action-mappings> Au moyen de la balise <action> différents attributs de la balise <action> sont à renseigner selon que la requête et avec ou sans paramètres name : nom d'un objet ActionForm pour la récupération/validation des paramètres, défini dans la section <form-beans> </form-beans> du fichier struts-config.xml la requête nécessite un traitement ou une simple redirection path : le path (relatif au contexte de l'application) auquel est associée l'action type : la classe de l'objet Action qui effectue le traitement associé à la requête forward : url de redirection Philippe GENOUD UJF Février 2010 14
Simple redirection Action correspondant à une requête sans paramètres nécessitant une simple redirection accueil.html formulaireanneematiere.do struts-config.xml <struts-config> <struts-config> <action-mappings> <action-mappings> </action-mappings> </action-mappings> </struts-config> </struts-config> ActionServlet ActionServlet <action path="/formulaireanneematiere" forward="/formulaireanneematiere.jsp"/> formulaireanneematiere.jsp.jsp définit le nom de l URL correspondant à l'action (suffixe «.do» implicite) l URL à laquelle est relayée la demande Philippe GENOUD UJF Février 2010 15
Simple Redirection assistant NetBeans pour ajout d'une action pour une requête sans paramètres nécessitant une simple redirection 2 1 Clic bouton droit 3 Philippe GENOUD UJF Février 2010 16
Action avec traitement Action correspondant à une requête avec paramètres nécessitant un traitement notesanneematiere.do tableau.jsp formulaireanneematiere.jsp HistogramImager (servlet) Philippe GENOUD UJF Février 2010 17
Action avec traitement ActionServlet ActionServlet Action Action NotesAnneeMatiere NotesAnneeMatiere ActionForm ActionForm NotesAnneeMatiereForm NotesAnneeMatiereForm notesanneematiere.do? annee=2005& matiere=bd& présentation=tableau struts-config.xml struts-config.xml Instancie et initialise setannee( ), setmatiere( ) formulaireanneenote.jsp validate( ).jsp ActionErrors Si erreur sinon execute( ) Consulte getannee( ), getmatiere( ) Histogramme Histogramme Initialise le modèle tableau.jsp ActionForward.jsp HistogramImager struts-config.xml Selon struts-config.xml l'actionforward Philippe GENOUD UJF Février 2010 18
ActionForm JavaBean qui permet de stocker les propriétés des formulaires ActionForm ActionForm Hérite de org.apache.struts.action.actionform NotesAnneeMatiereForm NotesAnneeMatiereForm vérifie la validité des propriétés par sa méthode validate ActionErrors validate(actionmapping, HttpServletRequest) ActionMapping : objet image de la configuration de l action en cours stockée dans struts-config.xml HttpServletRequest : requête du client transmise par la Servlet de contrôle ActionErrors : permet de retourner des messages erreurs au client La classe dispose également d autres méthodes ActionServlet getservlet() : retourne la Servlet qui gère le contrôle reset(actionmapping, HttpServletRequest) : initialise les propriétés Philippe GENOUD UJF Février 2010 19
ActionForm ActionForm ActionForm public class NotesAnneeMatiereForm extends ActionForm { public class NotesAnneeMatiereForm extends ActionForm { private private String String annee; annee; private String presentation; private String presentation; private String matiere; private String matiere; public void setannee(string annee) { public void setannee(string annee) { this.annee = annee; this.annee = annee; public public String String getannee() getannee() { { return annee; return annee; public public void void setmatiere(string setmatiere(string matiere) matiere) { { this.matiere this.matiere = = matiere; matiere; propriété modifieur et accesseur pour la propriété NotesAnneeMatiereForm NotesAnneeMatiereForm Chaque paramètre du formulaire est défini comme une propriété de l'objet ActionForm associé qui doit être un JavaBean Philippe GENOUD UJF Février 2010 20
public class NotesAnneeMatiereForm extends ActionForm { public class NotesAnneeMatiereForm extends ActionForm { private private String String annee; annee; private String presentation; private String presentation; private private String String matiere; matiere; Redéfinition (overriding) de la méthode validate @Override @Override public public ActionErrors ActionErrors validate(actionmapping validate(actionmapping mapping, mapping, HttpServletRequest request) { HttpServletRequest request) { ActionErrors errors = new ActionErrors(); ActionErrors errors = new ActionErrors(); ActionForm ActionForm ActionForm NotesAnneeMatiereForm NotesAnneeMatiereForm Création d'un objet erreur vide if if (annee == null annee.length() < 1) { (annee == null annee.length() < 1) { errors.add("année", new ActionMessage("error.annee.required")); errors.add("année", new ActionMessage("error.annee.required")); else { else { try { Selon les paramètres ajout de try { numeroannee numeroannee = = Integer.parseInt(annee); messages d'erreur Integer.parseInt(annee); catch catch (NumberFormatException (NumberFormatException e) e) { { errors.add("année", errors.add("année", new new ActionMessage("error.annee.isNotANumber")); ActionMessage("error.annee.isNotANumber")); if if ((!matiere.equals("graphic")) ((!matiere.equals("graphic")) && && ((!matiere.equals("tableau")) ((!matiere.equals("tableau")) { { errors.add("année", errors.add("année", new new ActionMessage("error.annee.required")); ActionMessage("error.annee.required")); Le message est défini dans un fichier.properties return return errors; errors; Renvoie des erreurs (vide si la validation a réussi) Philippe GENOUD UJF Février 2010 21
les messages d'erreurs sont définis dans le fichier properties de l'application errors.add("année", new ActionMessage("error.annee.isNotANumber")); errors.header=<ul> errors.header=<ul> errors.prefix=<li><span errors.prefix=<li><span style="color: style="color: red"> red"> errors.suffix=</span></li> errors.suffix=</span></li> error.annee.required=indiquez error.annee.required=indiquez l'année l'année error.annee.isnotanumber=l'année doit être un nombre error.annee.isnotanumber=l'année doit être un nombre formulaireanneematiere.jsp pl2/notes/applicationresource.properties ActionForm <%@ <%@ taglib taglib uri="http://struts.apache.org/tags-html" uri="http://struts.apache.org/tags-html" prefix="html" prefix="html" %> %> <html> <html> <body> <body> <H1>Histogramme des notes</h1> <H1>Histogramme des notes</h1> <HR> <HR> <form action="notesanneematiere.do" method="post"> <form action="notesanneematiere.do" method="post"> </form> </form> <HR> <HR> Tag de bibliothèque html <html:errors/> <html:errors/> de Struts pour afficher les </body> </body> messages d'erreur </html> </html> Philippe GENOUD UJF Février 2010 22
ActionForm l'utilisation du fichier properties facilite la localisation (i18n) de l'application pl2/notes/applicationresource.properties errors.header=<ul> errors.header=<ul> errors.prefix=<li><span style="color: red"> errors.prefix=<li><span style="color: red"> errors.suffix=</span></li> pl2/notes/applicationresource.properties.en errors.suffix=</span></li> errors.header=<ul> errors.header=<ul> error.annee.required=indiquez l'année error.annee.required=indiquez l'année errors.prefix=<li><span style="color: red"> errors.prefix=<li><span style="color: red"> error.annee.isnotanumber=l'année doit être un nombre error.annee.isnotanumber=l'année doit être un errors.suffix=</span></li> errors.suffix=</span></li> nombre formhisto.title=histogramme de notes formhisto.title=histogramme de notes error.annee.required=year required error.annee.required=year required error.annee.isnotanumber=year error.annee.isnotanumber=year is is not not a a number number formhisto.title=marks formhisto.title=marks Histogram formulaireanneematiere.jsp Histogram <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> <%@ taglib uri="http://struts.apache.org/" prefix="bean" %> <html> <html> <body> <body> <H1> <bean:message Histogramme key="formhisto.title"/> des notes </H1> <H1> Histogramme des notes </H1> <HR> <HR> <form <form action="notesanneematiere.do" action="notesanneematiere.do" method="post"> method="post"> </form> </form> <HR> <HR> <html:errors/> <html:errors/> </body> </body> </html> </html> un fichier ressource par langue Philippe GENOUD UJF Février 2010 23
ActionForm Les ActionForms doivent être déclarées dans le fichier struts-config.xml balise <form-bean> dans la section <form-beans> </form-beans> <struts-config> <struts-config> <form-beans> <form-beans> <form-bean <form-bean name="notesanneematiereform" name="notesanneematiereform" type="pl2.notes.struts.forms.notesanneematiereform"/> type="pl2.notes.struts.forms.notesanneematiereform"/> </form-beans> </form-beans> <struts-config> <struts-config> Nom pour identifier l'action form Nom de la classe Java Philippe GENOUD UJF Février 2010 24
assistant NetBeans pour créer une ActionForm ActionForm 1 nom de la classe 2 3 Philippe GENOUD UJF Février 2010 25
Action Permet d'associer un traitement à une requête Hérite de org.apache.struts.action.action Action Action NotesAnneeMatiere NotesAnneeMatiere Effectue le traitement par sa méthode execute ActionForward execute(actionmapping, ActionForm,HttpServletRequest, HttpServletResponse) ActionMapping : objet image de la configuration de l action en cours stockée dans struts-config.xml ActionForm : JavaBean qui stocke l information du formulaire HttpServletRequest : référence de la requête HttpServletResponse : référence de la réponse ActionForward :objet identifiant la destination que le contrôleur (l' ActionServlet) doit choisir Philippe GENOUD UJF Février 2010 26
Action public class NotesAnneeMatiere extends Action { Action Action private final static String HISTO_TABLE = "histotableau"; private final static String HISTO_GRAPHIC = "histographique"; NotesAnneeMatiere NotesAnneeMatiere public ActionForward execute(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { NotesAnneeMatiereActionForm f = (NotesAnneeMatiereForm) form; INotesDAO notesdao = DAOFactory().getNoteDAO(); Histogramme histo = notesdao.gethistogramme(f.getnumeroannee(), f.getmatiere() ); request.setattribute("notes", histo); if (f.getpresentation().equals("graphic")) { return mapping.findforward(histo_graphic); else { return mapping.findforward(histo_table); Le modèle est transmis via la requête Choix de la prochaine redirection Récupération de l'objet ActionForm grâce au paramètre form Construction du modèle Philippe GENOUD UJF Février 2010 27
Action Declaration de l'action dans le fichier struts-config.xml <struts-config> <struts-config> <form-beans> <form-beans> <form-bean <form-bean name="notesanneematiereactionform" name="notesanneematiereactionform" type="pl2.notes.struts.forms.notesanneematiereactionform"/> type="pl2.notes.struts.forms.notesanneematiereactionform"/> </form-beans> </form-beans> <action-mappings> <action-mappings> <action forward="/formulaireanneematiere.jsp" path="/formulaireanneematiere"/> <action forward="/formulaireanneematiere.jsp" path="/formulaireanneematiere"/> <action path="/notesanneematiere" <action path="/notesanneematiere" type="pl2.notes.struts.actions.notesanneematiere" type="pl2.notes.struts.actions.notesanneematiere" name="notesanneematiereform" name="notesanneematiereform" input="/formulaireanneematiere.jsp" input="/formulaireanneematiere.jsp" scope="request" scope="request" > > <forward <forward name="histotableau" name="histotableau" path="/tableau.jsp"/> path="/tableau.jsp"/> <forward <forward name="histographique" name="histographique" path="/histographic"/> path="/histographic"/> </action> </action> </action-mappings> </action-mappings> Etiquette de redirection if (f.getpresentation().equals("graphic")) { return mapping.findforward("histotagraphique"); else { return mapping.findforward("histotableau"); Chemin de redirection tableau.jsp.jsp HistogramImager URL correspondant à l'action (suffixe «.do» implicite) Classe de l'action Nom de l'actionform associée Vue vers laquelle le contrôleur redirige en cas d'echec de la validation <servlet> <servlet-name>graphic</servlet-name> <servlet-class> pl2.notes.servlets.histogramimager </servlet-class> </servlet> <servlet-mapping> <servlet-name>graphic</servlet-name> <url-pattern>/histographic</url-pattern> </servlet-mapping> Philippe GENOUD UJF Février 2010 28 web.xml
Action assistant NetBeans pour créer une Action 1 2 3 Philippe GENOUD UJF Février 2010 29
Action assistant NetBeans pour créer une Action suite Clic bouton droit 3 1 2 Philippe GENOUD UJF Février 2010 30
Exceptions public class NotesAnneeMatiere extends Action { Action Action private final static String HISTO_TABLE = "histotableau"; private final static String HISTO_GRAPHIC = "histographique"; NotesAnneeMatiere NotesAnneeMatiere public ActionForward execute(actionmapping mapping, ActionForm form, l'exception est relancée HttpServletRequest request, HttpServletResponse response) throws Exception { NotesAnneeMatiereActionForm f = (NotesAnneeMatiereForm) form; INotesDAO notesdao = DAOFactory().getNoteDAO(); Histogramme histo = notesdao.gethistogramme(f.getnumeroannee(), f.getmatiere() ); request.setattribute("notes", histo); if (f.getpresentation().equals("graphic")) { return mapping.findforward(histo_graphic); else { return mapping.findforward(histo_table); Que se passe-t'il si une DAOException est levée? Philippe GENOUD UJF Février 2010 31
Exceptions Si l'exception est relancée et qu'aucun traitement n'est mis en place pour celleci, une ServletException est créée par le contrôleur, chaînée avec l'exception originale et relancée, Servlet Exception Cause mère Philippe GENOUD UJF Février 2010 32
Exceptions Possibilité de mettre en oeuvre un traitement spécifique des exceptions en redirigeant l'application vers une page spécifique struts-config.xml clé pour message d'erreur dans le fichier ressources la ressource vers laquelle l'application est redirigée le type de l'exception concernée pl2/notes/applicationresource.properties erreur_1.jsp Philippe GENOUD UJF Février 2010 33
Exceptions Possibilité de mettre en oeuvre un traitement spécifique des exceptions en exécutant un gestionnaire d'erreur : une classe héritant de org.apache.struts.actions.exceptionhandler redéfinition de la méthode execute la redirection s'effectue à l'aide d'un élément forward défini dans le fichier struts-config.xml La redirection peut être vers une action ou une page jsp struts-config.xml le type de l'exception concernée le lien entre un gestionnaire d'erreur et un type d'erreur est effectué dans le fichier struts-config.xml le gestionnaire d'exceptions invoqué Philippe GENOUD UJF Février 2010 34
Exceptions Une exception est traitée par le gestionnaire d'exception le plus spécifique Exceptions de n'importe quel autre type Exceptions de type DAOException (classe DAOException ou n'importe quelle sous classe de DAOException) Philippe GENOUD UJF Février 2010 35
Exceptions Possibilité de rédéfinir un gestionnaire spécifique au niveau d'une action gestionnaire général pour les DAOException gestionnaire spécifique pour les DAOException levées par l'action notesanneematière Philippe GENOUD UJF Février 2010 36
Exceptions assistant NetBeans pour définir un gestionnaire d'exceptions Clic bouton droit struts-config.xml 1 2 3 Philippe GENOUD UJF Février 2010 37
Struts TagLibs Struts propose des bibliothèques de Tags Personnalisés qui aident les développeurs d'applications basées sur des formulaires Struts propose 4 bibliothèques de tag HTML Tags pour création d'interface utilisateur HTML, en particulier pour créer des formulaires de saisie Logic Tags pour la génération conditionnelle de texte, génération répétitive de texte en itérant sur des collections d'objets, gestion du flux de contrôle de l'application Bean Tags pour la définition de nouveaux objets JavaBeans dans différentes portées (application, session, requête ) et à partir de différentes sources Tags pour afficher un bean (ou une proriété d'un bean) sur la réponse de sortie. Nested Tags qui étendent les tags de base de Struts pour leur mise en relation lors d'imbrication Philippe GENOUD UJF Février 2010 38
Exemple d'utilisation des tags HTML formulaireannneematiere.jsp Struts TagLibs Il faudrait intégrer dans la page de la logique permettant de réaffecter les éléments du formulaire avec les valeurs qui avaient été transmises Problème : les différents éléments du formulaire reprennent leur valeur initiale En cas de saisie incorrecte on revient sur cette page qui affiche alors les messages d'erreur Philippe GENOUD UJF Février 2010 39
Exemple d'utilisation des tags HTML formulaireannneematiere.jsp Struts TagLibs Les tags HTML de Sruts prennent en charge l'initialisation des éléments du formulaire en cas de retour Philippe GENOUD UJF Février 2010 40