Java - Struts Noël Macé Licence CC BY-NC-SA Version 1-30/05/12
Introduction Quoi, pourquoi, comment et depuis quand?
Plan Framework Qu'est ce? Pourquoi? Struts Qu'est ce? Pourquoi? Struts 1 Struts 2
Méthodes de validation Stuts méthodes de ActionForm disponible pour chaque formulaire void reset(actionmapping mapping, HttpServletRequest request) (ré)initialisation ActionErrors validate(actionmapping mapping, HttpServletRequest request) valider la saisie
Qu'est ce qu'un framework? Programmeurs système Pour les programmeurs d'applications Simplifier Bibliothèques + outils + règles
Pourquoi les frameworks? Respect des normes Bonnes pratiques Harmonisation du développement Combler les manques et faiblesses Ex : CGI, Servlet & JSP Améliorer le logiciel : Performances Qualité Maintenabilité Pérennité
Qu'est ce que Struts? Framework libre (Apache 2.0) Apache Fondation depuis Mai 2000 Développement JEE Extension des Servlets MVC : Modèle Vue Contrôleur Particulièrement adapté aux applications de taille importante
Pourquoi Struts? Décomposer Application complexe > composants plus simples Largement connu et reconnu Documentation abondante Quasiment un standard UNIQUEMENT pour des applications de taille importante
Struts 1 Sorti en Juin 2001 Framework Java EE le plus populaire du monde Connais de nombreuses limitations
Les forks de Struts 1 Moins populaires Pallient aux limites de Struts 1 Tests par navigateur uniquement Formulaires Gestion des JavaBeans Etc...* WebWork est l'un des meilleurs d'entre eux
Struts 2 Fin 2005 Fusion de Struts 1 et WebWork Refonte complète Nécessite un réapprentissage quasi total
Généralités Architecture générale de Stuts 1 et 2
Rappel : JavaBean élément de base de nombreux outils de développement simple et réutilisable convention : extends Serializable constructeur par défaut (sans paramètre) des accesseurs publiques doivent être crées pour chaque variable d'instance doit contenir les méthodes d'interception nécessaire
MVC Design Pattern / patron d'architecture Bonne pratique En réponse à un problème de conception précis Idem patron de couture Organise l'ihm Référence depuis 1979
MVC
Java EE & MVC
Java EE & MVC pour chaque action : Un Servlet Un ou plusieurs JavaBean modèle Une page JSP Développement lourd et complexe
Struts & MVC MVC 2 : un seul et unique contrôleur ie : une servlet pour gérer toutes les actions Vue : JSP Contrôleur : Servlet unique ActionServlet déjà codé Modèle : non implémenté (JavaBeans, EJB, etc ) Configuration : struts-config.xml - Central
Struts 1 L ancêtre toujours vaillant
Intro première approche
Plan Installation Vue Struts Taglibs ActionForms Contrôleur : Action Configuration
Encore une référence Dernière version : 1.3.10 Déc 2008 Struts 2, lui, est encore en développement Mais encore omniprésent en entreprise Migration vers Struts 2.0 complexe Manque de compétences
Installation Télécharger struts-1.3.10-all.zip Installation dans un projet existant : Librairies (.jar) /WEB-INF/lib Configurations (.xml) /WEB-INF Configurations (.properties) /WEB-INF/src Pour les premiers pas : projet Struts vide Prêt à l'emploi struts-blank.war
Vue MVC 2 : deux composants : Page JSP Javabean ActionForm (pour les formulaires)
Struts Taglibs Permet d'éviter tout code java dans la vue Simplifie le développement Au nombre de cinq : Bean, html, logic, nested, tiles Déclaration : <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%> Référence : http://struts.apache.org/1.x/struts-taglib/index.html
Struts Taglibs - Exemple <%@ taglib uri="http://struts.apache.org/tags bean" prefix="bean" %> <%@ taglib uri="http://struts.apache.org/tags html" prefix="html" %> <%@ taglib uri="http://struts.apache.org/tags logic" prefix="logic" %> <html:html> <head> <title>authentication</title> <html:base/> </head> <body> <html:form action="/auth"> Login : <html:text property="login" /><br/> Password <html:text property="password" /><br/> <html:submit value="envoyer" /> </html:form> </body> </html:html>
ActionForm JavaBean Permet de gérer les formulaires Inclus par Struts dans la page JSP Org.apache.struts.action.ActionForm
ActionForm - Exemple package actionform ; import org.apache.struts.action.actionform ; public class authform extends ActionForm { private String login = null ; private String password = null ; } public String getlogin(){ return login ; } public void setlogin(string login){ this.login = login ; } public String getpassword(){ return password ; } public void setpassword(string password){ this.password = password; }
Contrôleur Un seul Servlet : ActionServlet org.apache.struts.action Nécessite de définir des actions extends Action Point d'entrée : méthode execute ActionForward execute(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) Permet de définir une redirection conditionnelle return mapping.findforward("success") Doc : http://struts.apache.org/1.3.10/apidocs/org/apache/struts/action/action.html
Action - Exemple package action; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import org.apache.struts.action.action; import org.apache.struts.action.actionform; import org.apache.struts.action.actionforward; import org.apache.struts.action.actionmapping; import actionform.authform; public class AuthAction extends Action { public ActionForward execute(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { AuthForm authform =(AuthForm) form; if(authform.getlogin().equals("noel") && authform.getlogin().equals("passw0rd")){ } return mapping.findforward("success"); return mapping.findforward("erreurs"); } }
Configuration descripteur de déploiement (web.xml) une seule servlet, donc toujours identique cette servlet est configurée via strutsconfig.xml dans /WEB-INF/ lien entre classes Action, ActionForm et pages JSP
web.xml <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>struts Blank Application</display-name> <!-- Standard Action Servlet Configuration --> <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> <load-on-startup>2</load-on-startup> </servlet> <!-- Standard Action Servlet Mapping --> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!-- The Usual Welcome File List --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
struts-config.xml <form-bean> <action> <form-beans> déclaration d'un JavaBean ActionForm name type référence (instance) type java (votre classe ActionForm) <action-mappings> déclaration d'un JavaBean Action path type name scope input <forward> url sans extension ie : attribut action d'un formulaire ou lien type java (votre classe Action) référence d'actionform portée de l'instance ("request" ou "session") jsp à l'origine de l'action (appelé en cas d'erreur de saisie) redirection name path référence (chaine de caractère : "succes", "error", etc...) url de destination
struts-config.xml Exemple (1) <?xml version="1.0" encoding="iso 8859 1"?> <!DOCTYPE struts config PUBLIC " //Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts config_1_3.dtd"> <struts config> <! ================================================ Form Bean Definitions > <form beans> <form bean name="authform" type="actionform.authform"/> </form beans> <! ========================================= Global Exception Definitions > <global exceptions> <! sample exception handler <exception key="expired.password" type="app.expiredpasswordexception" path="/changepassword.jsp"/> end sample > </global exceptions> <! =========================================== Global Forward Definitions > <global forwards> <forward name="welcome" path="/welcome.do"/> </global forwards>
struts-config.xml Exemple (2) <! =========================================== Action Mapping Definitions > <action mappings> <action path="/welcome" forward="/pages/welcome.jsp"/> <action path="/auth" type="action.authaction" name="authform" scope="request" input="/pages/auth.jsp"> <forward name="error" path="/pages/error.jsp"/> <forward name="success" path="/pages/success.jsp"/> </action> </action mappings> <! ======================================== Message Resources Definitions > <message resources parameter="messageresources" /> <! =================================================== Validator plugin > <plug in classname="org.apache.struts.validator.validatorplugin"> <set property property="pathnames" value="/org/apache/struts/validator/validator rules.xml, /WEB INF/validation.xml"/> </plug in> </struts config>
Struts 1 "avancé" Parce qu'on peu toujours faire mieux
Plan Vue DynaForms properties Contrôle avancé classes Action filles methodes Helper Validations
Vues
Formulaires dynamiques methode "classique" (ActionForm) lourde à mettre en place grand nombre de JavaBeans minimalistes il est possible de se passer de leur écriture Java en utilisant struts-config.xml une classe dérivant de DynaActionForm sera dynamiquement crée, ainsi qu'une instance
DynaForm - Exemple <form beans> <form bean name="authdynaform" type="org.apache.struts.action.dynaactionform"> <form property name="login" type="java.lang.string" initial=""/> <form property name="password" type="java.lang.string" initial=""/> </form bean> </form beans>
Exercice : DynaForm & JavaBeans les DynaForms peuvent manipuler tout JavaBean A partir de l'exemple précédent, créez un JavaBean bean.utilisateur avec pour propriétés login et password Utilisez cette classe en lieu et place des strings précédentes
Properties permet de centraliser et "dynamiser" certains éléments statiques de vos pages texte images url etc très utile pour l'internationalisation, par exemple convention : nom_codelangue.properties ex : param_en.properties
Properties pas à pas créer un package spécifique (ex : resources) créer un fichier.properties dans ce package y inscrire une (ou plusieurs) clé / valeur ex : utilisateur.loginlabel=votre pseudonyme référencer ce fichier dans struts-config.xml ex : <message-resources parameter="resources.params" /> utiliser cette clé dans une JSP <bean:message key="utilisateur.loginlabel"/>
Properties - Exercice A partie du mini-projet précédent : remplacer tout les élements texte par des propriétés de langue anglais / français
Validations
Validation Stuts imposer des règles pour les champs de formulaire ex : le champs e-mail : xxx@xxxxx.xxx Permet : de ne pas permettre des entrées incorrectes de sécuriser l'application (ex : injections sql) complexe en Java EE (un servlet / action) 2 méthodes : par méthode de ActionForm - validate() et reset() par plugin Validators
reset() - Exemple public class AuthForm extends ActionForm { private String login = null; private String password = null; } //réinitialiser les valeurs de champs à chaque rechargement public void reset(actionmapping mapping, HttpServletRequest request) { } this.login = "noel"; this.password = "pwd";
validate() vérifier la concordance entre la valeur entrée et la syntaxe attendue uniquement pour les champs textes textes, listes déroulantes, textbox, etc renvoie une erreur si invalide vers une page adaptée affichée grâce à <html:errors>
validate() - Exemple public class AuthForm extends ActionForm { private String login = null; private String password = null; } public ActionErrors validate(actionmapping mapping, HttpServletRequest request) { } ActionErrors errors = new ActionErrors(); if(this.login == null this.login.isempty() this.login.matches("\\s*")){ } errors.add("login", new ActionMessage("error.login")); if(this.password == null this.password.isempty() this.password.matches("\\s*")){ } errors.add("password", new ActionMessage("error.password")); return errors;
validate() - Affichage <html:errors/> <h2> ActionForm </h2> <html:form action="/auth"> Login : <html:text property="login" /><br/> <html:errors property="login"/><br/> Password : <html:text property="password" /> <html:errors property="password"/><br/> <html:submit value="envoyer" /> </html:form>
Validators plug-in configuration XML global, plus adapté à de gros projets Deux fichiers : /WEB-INF/validation.xml : déclaration des validations de l'application /org/apache/struts/validator/validator-rules.xml : fichier de validations par défaut apache
validator constantes Permet de créer des références vers des expressions régulières courantes dans <global> général à toute l'application Exemple : <constant> <constant name>postalcode</constant name> <constant value>^\d{5}\d*$</constant value> </constant>
validator formulaires déclarer les formulaires et les propriétés à valider dans <formset> un <form name="refdeform"> par formulaire contenant un <field property="prop" depends="..."> par champ pour les regexp, voir : http://docs.oracle.com/javase/1.5.0/docs/api/java/util/regex/pattern.html
validator champs (1) <field property="prop" depends="..."> property : ref de la propriété du form depends : restrictions depends : required validwhen maxlength, minlength mask email, url, creditcard date, double, float, long, integer, etc...
validator champs (2) balises filles : <arg key="error.macle"> : message à afficher cf properties <arg name="..." key="${var :...}" resource="false"> paramétrage d'une restriction (cf depends) name = une des depends de la balise field key = la valeur de cette restriction ressource : si à true, tentera de retrouver la valeur de key dans les ressources messages <var> : définition d'une variable pour le field <var-name>...</var-name> : référence <var-value>...</var-value> : valeur
validator- Exemple <formset> <form name="authvalidform"> <field property="login" depends="required,minlength,maxlength,mask"> <arg key="errors.form.login"/> <arg name="minlength" key="${var:minlength}" resource="false"/> <arg name="maxlength" key="${var:maxlength}" resource="false"/> <var> <var name>minlength</var name> <var value>4</var value> </var> <var> <var name>maxlength</var name> <var value>10</var value> </var> <var> <var name>mask</var name> <var value>^\\p{alpha}{1}\\w*$</var value> </var> </field> </form> </formset>
validator & ActionForm Pour tout ActionForm : ajouter un paramètre validate=true à votre Action dans struts-config.xml pour déclencher un validator sur un ActionForm statique, il vous faudra : faire hériter votre form de ValidatorForm ne nécessite pas de redéfinir les méthodes reset et validate NB : ici, la valeur d'input est très importante, car définie la redirection en cas d'erreur
Exercice à partir du projet précédent : surcharger les méthodes reset et validate de AuthForm afin : d'initialiser les champs à votre compte admin vérifier que les champs ne soient pas vides A partir d'une copie d'authform - AuthValidForm: mettre en place un validator : required, mask=que des caractères ou des nombres, minlength=4, maxlength=10 sur le login ainsi que sur le password avec les paramètres de votre choix Effectuer la même opération avec authdynaform
classes Actions filles
Classes Action dérivées Permettent de simplifier le travail Représentent les actions les plus courantes Évite d'avoir à écrire soit même un code aussi généraliste
ForwardAction redirection Exemple : <action path="/authdynaform" name="authdynaform" validate="true" type="org.apache.struts.actions.forwardaction" parameter="/pages/home.jsp" input="/pages/authdynaform.jsp" scope="request" />
DispatchAction Permet de déclarer plusieurs points d'entrée dans une même classe l'appel de cette méthode se fait ensuite via le paramètre methode de l'url : <html:form action="/auth.do?methode=test"> Différences avec Action : la balise <action> de struts-config.xml doit prendre comme paramètre "methode" les points d'entrées seront en tout point semblables à execute(), excepté leurs noms
DispatchAction - Exemple struts-config.xml : <action path="/auth" type="action.authaction" name="authform" scope="request" input="/pages/authform.jsp" validate="false" parameter="methode"> <forward name="error" path="/pages/error.jsp"/> <forward name="success" path="/pages/success.jsp"/> </action> classe d'action : public class AuthAction extends DispatchAction { } public ActionForward test(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { }
MappingDispatchAction la plus utilisée définition des points d'entrée par l'attribut parameter de la balise <action> une balise <action> par point d'entrée Exemple : <action path="/auth1" type="action.authaction" name="authform" scope="request" input="/pages/authform.jsp" validate="false" parameter="test1"> </action> <forward name="error" path="/pages/error.jsp"/> <forward name="success" path="/pages/success.jsp"/> <action path="/auth2" type="action.authaction" name="authform" scope="request" input="/pages/authform.jsp" validate="false" parameter="test2"> </action> <forward name="error" path="/pages/error.jsp"/> <forward name="success" path="/pages/success.jsp"/> Tout le reste est similaire à DispatchAction
LookUpDispatchAction Semblable à DispatchAction l'appel du point d'entrée se fait par la sous-balise <bean:message key="..."/> de <html:submit property="action"> permet d attribuer plusieurs actions à un formulaire en fonction du bouton pressé Moins souple donc peu utilisé
SwitchAction Permet d'utiliser un second fichier de configuration struts permet de "cloisonner" la configuration ex : struts-config.xml pour le frontend et strutsconfig-back.xml pour le backend une action SwitchAction servira de "répartisseur" vers les actions de ce second fichier
SwitchAction Pas à Pas (2) Créer la SwitchAction correspondant à ce fichier dans struts-config.xml : <action path="/switch" type="org.apache.struts.actions.switchaction /> créer les actions nécessaires dans le second fichier
SwitchAction Pas à Pas (3) l'appel à une action du second module à partir d'une action du premier se fera par le SwitchAction : <action path="/authentification" type="action.authaction" name="authform" scope="request" input="/pages/auth.jsp" validate="false" parameter="authtest"> <forward name="error" path="/pages/error.jsp" /> <forward name="success" path="/switch.do? page=/successback.do&prefix=/admin" /> </action>
Les autres IncludeAction : similaire à un RequestDispatcher.include(request,response) ActionDispatcher : similaire à MappingDispatchAction mais quasi inutilisée car bien trop contraignante en comparaison
Méthodes Helper
Méthodes Helper méthodes d'action permettent : fournir des informations identifier les opérations réalisées par l'utilisateur manipuler les éléments HTTP (requète, réponse, transactions) http://struts.apache.org/1.x/apidocs/org/apache/struts/action/action.html
Exercice ajouter un bouton Cancel à votre formulaire en cas de clic sur ce bouton, l'utilisateur sera redirigé prioritairement vers une page de votre choix ajouter un attribut "language" à votre Bean Utilisateur lors de l'authentification, le backend devra automatiquement passer dans la langue de l'utilisateur et non du navigateur Bonus : dans le cas où la langue de l'utilisateur soit différente de celle du navigateur, afficher un message proposant de changer la langue de son compte ou de repasser temporairement dans la langue navigateur
Struts 2 retour vers le futur