Contenu A • Formulaires HTML • Interface CGI • Perl Applicatif côté serveur (Servlets) • PhP • Servlets TPI P. Reignier TPI P. Reignier A.1 Motivations • Java : langage de programmation généraliste A1 - Servlets • Permet le développement de grosses applications • Objectif : offrir un accès Web à ces applications TPI P. Reignier TPI P. Reignier A.3 Motivations (2) Motivations (3) • Java : support réseau (Sockets . . . ) • Application : – Prise en charge de tous les services communs – Evite de les redévelopper pour chaque application web – Container de servlets • Support Web : – Interpréteur HTTP – Codage + décodage MIME – Support des cookies, des sessions – ... • Interfaçage : – Plusieurs fournisseurs de container de servlet – Comment peux-t-on fournir ses classes pour étendre le container – Normalisation de l’interface ⇒ Les Servlets • Deux approches potentiellement possibles : 1. Ajout de bibliothèques (jar) à votre application 2. Ajout de vos classes à une application (serveur Web) TPI P. Reignier TPI P. Reignier A.4 A.5 Plan Servlet << interface >> Servlet + init ():void + destroy ():void + service (req :ServletRequest ,resp :SevletResponse ):void • Servlets + Container de servlets • JSP Classe abstraite GenericServlet • Architecture MVC + service (req :ServletRequest ,resp :ServletResponse ):void • JSP tags (Philippe Genoud) HttpServlet + doGet (req :HttpServletRequest ,resp :HttpServletResponse ):void + doPost (req :HttpServletRequest ,resp :HttpServletResponse ):void + doHead (req :HttpServletRequest ,resp :HttpServletResponse ):void TPI P. Reignier A.6 TPI Created with Poseidon for UML Community Edition. Not for Commercial Use. A.7 P. Reignier doGet, doPost : paramètres Cycle de vie • Géré par le container. • Initialisation : – Chargement de la classe (au démarrage ou sur requête). – Instantiation d’un objet. – Appel de la méthode init() (par exemple : ouverture de lien JDBC) • Utilisation : – Appel de la méthode service() – Dans le cas d’une HttpServlet : appel vers doGet(), doPost(). • Destruction : – Peut être provoquée pour optimiser la mémoire – Appel de la méthode destroy() TPI P. Reignier • HttpServletRequest : – Contexte de l’appel – Paramètres de formulaires – Cookies – Headers – ... • HttpServletResponse – Contrôle de la réponse – Type de données – Données – Cookies – Status – ... TPI P. Reignier A.8 A.9 Première Servlet SerlvetRequest / ServletResponse << interface >> ServletRequest import java.io.∗; import javax.servlet.∗; import javax.servlet.http.∗; public class PremiereServlet extends HttpServlet { public void doGet(HttpServletRequest requete,HttpServletResponse reponse) throws IOException, ServletException { reponse.setContentType("text/html"); PrintWriter pw = reponse.getWriter(); << interface >> ServletResponse + getParameterName (name :String ):String + getParameterNames (): + getReader (): + getInputStream (): + getContentLength ():int + getContentType ():String pw.print("<html>"); pw.print("<body bgcolor=\"white\">"); pw.print("<head>"); pw.print("<title>Ma première servlet</title>"); pw.print("</head>"); pw.print("<body>"); pw.print("<h1>Ca marche !</h1>"); pw.print("</body>"); pw.println("</html>"); } + setContentType (type :String ):void + getOutputStrem ():ServletOutputStream + getWriter ():PrintWriter << interface >> HttpServletRequest << interface >> HttpServletResponse + getCookies (): + getRequestURI ():String + addCookie (cookie :Cookie ):void + sendError (err :int ,mesg :String ):void + sendRedirect (location :String ):void Created with Poseidon for UML Community Edition. Not for Commercial Use. } TPI P. Reignier A.10 TPI P. Reignier A.11 Cookie Exemple Cookie protected void doGet(HttpServletRequest req, HttpServletResponse res) throws java.io.IOException, ServletException { + getName ():String + getValue ():String + getDomain ():String + getPath ():String + setValue (name :String ):void + setMaxAge (age:int ):void + setPath (path :String ):void << create >> + Cookie (domain :String ,name :String ,value :String ):void res.setContentType("text/html"); PrintWriter pw = reponse.getWriter(); Enumeration e = req.getParameterNames(); pw.setContentType("text/html") ; ... while (e.hasMoreElements()) { // récupération des paramètres String attribute = (String)e.nextElement(); pw.print("Attribut : " + attribute) ; pw.print("Valeur : " + req.getParameter(attribute)) ; } ... } • Une fois créé, le nom d’un cookie ne peut être changé TPI P. Reignier TPI A.12 P. Reignier A.13 Exemple (suite) Execution cookie = req.getCookies() ; if (cookie != null) { for (int i=0; i<cookie.length; i++) { pw.print("<TR><TD>\n") ; pw.print(cookie[i].getName()) ; pw.print("</TD><TD>\n") ; pw.print(cookie[i].getValue()+"</TD>\n") ; pw.print("</TR>\n") ; } } TPI • Serveur web multi-threadé – Un thread par requête • Attention à la gestion des ressources partagées • Lien Instance ⇔ Thread. Par défaut : – Une seule instance – Les attributs de la classe deviennent des ressources partagées P. Reignier A.14 TPI P. Reignier A.15 Exemple Exemple (suite) public class Factorielle extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); protected int nombre ; protected int factorielle(int x) { int res=1 ; try { this.nombre = x ; res = 1 ; for (int i =1; i<=nombre; i++) { Thread.sleep(1000) ; res ∗ = i ; } } catch (InterruptedException e) { e.printStackTrace() ; } return res ; } out.println("<html>"); out.println("<head>"); out.println("<title>Factorielle</title>"); out.println("</head>"); out.println("<body>"); int x = Integer.parseInt(request.getParameter("x")) ; int fact = factorielle(x) ; out.println(request.getParameter("x")+"! out.println("</body>"); out.println("</html>"); protected void goGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } = " + fact) ; out.close(); } } TPI P. Reignier TPI P. Reignier A.16 A.17 Solutions Sessions • Permet de simuler une connexion continue entre un navigateur et le serveur. • Sections critiques : • Sauvegarde d’objets (associés à un client) : – entre différentes pages – entre des appels successifs à une même page – Utilisation du mot clé synchronized • Identifiant unique transmis sous forme de cookie • Modèle d’exécution : 1 instance par thread • Utilisation de l’interface : – Implémenter l’interface SingleThreadModel javax.servlet.http.HttpSession TPI P. Reignier A.18 TPI P. Reignier A.19 Utilisation Utilisation(2) • Sauvegarde d’objets : – Association clé ⇔ instance • Session : associé à HttpServletRequest • Accès à la session : – HttpSession session = request.getSession(true) ; – Récupération de la session associée au navigateur – Création de la session si elle n’existe pas Obj o ; session.setAttribute("cle", o) • Extraction d’objets : Obj o ; o = (Obj) session.getAttribute("cle") ; • session.isNew() : – Permet de tester si la session vient d’être créée. ⇒ initialisation. • Fin de session : session.invalidate() ; TPI P. Reignier TPI A.20 P. Reignier A.21 Exemple : un compteur public class CompteurServlet extends HttpServlet { public void doGet( HttpServletRequest requete,HttpServletResponse reponse) throws IOException, ServletException { reponse.setContentType("text/html"); ServletOutputStream os = reponse.getOutputStream(); HttpSession session = requete.getSession(true) ; Compteur cpt = session.getAttribute("compteur") ; if (cpt == null) { cpt = new Compteur() ; session.setAttribute("compteur", cpt) ; } A2 - Container de Servlets os.print("<HTML>\n") ; . . .. cpt.incrCpt() ; if (cpt.getCpt() == 5) session.invalidate() ; } } TPI P. Reignier A.22 TPI P. Reignier Définition Jakarta-Tomcat • Container de Servlet : – Application Java – Normalisation Sun (J2EE) – Prise en charge du protocole Http – Permet d’utiliser vos propres objets pour le traitement des requêtes – Plusieurs “applications web” par container • Deux aspects : – Où doit on mettre ses fichiers .class pour que le container les trouve : ∗ le déploiement – A quelle URL sera associée les classes, quels sont les paramètres de lancement, quelle sécurité . . . ∗ le descripteur de déploiement TPI P. Reignier • Tomcat : un des plus célèbre container de servlet • Conçu par Apache • Reconnu implémentation de référence par Sun de la norme Servlet • http://jarkata.apache.org/tomcat/index.html • Actuellement en version 5 : – 5.0 : fonctionne sous jdk1.4 – 5.5 : ne fonctionne que sous jdk1.5 TPI A.24 P. Reignier A.25 Déploiement d’une application Web Arborescence de Tomcat • bin • Normalisation de l’arborescence des fichier binaires • common : packages java communs à l’ensemble des applications – classes – endorsed – lib MyApplication/ classes/ WEB−INF/ lib/ • conf index.html • common : packages java communs à l’ensemble des application – classes – lib web.xml javadoc/ • webapps : ensemble des applications web TPI P. Reignier A.26 TPI P. Reignier A.27 Déploiment (suite) Arborescence Binaire (2) • Sommet : fichiers HTML et JSP (voir plus loin) – Des sous répertoires peuvent être créés pour structurer le stockage de ces fichiers. • javadoc : documentation développeur des servlets. • WEB-INF : – classes : servlet compilées. – lib : jar nécessaires à l’application (cf JDBC) – Remarque : ces deux répertoires sont directement accessibles à la machine virtuelle exécutant le container de servlet. – web.xml : description du déploiement. TPI P. Reignier • 3 solutions (on ne s’intéressera qu’à la troisième) : 1. Copie de l’arborescence binaire dans le répertoire webapps – Redémarrer Tomcat pour prendre en compte la nouvelle application 2. Création d’une archive war déposée dans le répertoire webapps – Redémarrer Tomcat pour prendre en compte la nouvelle application – Décompression automatique du fichier war par Tomcat 3. Utilisation de l’interface admin de Tomcat – Permet d’indiquer le répertoire où se trouve l’application – Pas besoin de redémarrer Tomcat TPI A.28 P. Reignier A.29 Descripteur de déploiement Quelques éléments de web.xml • Application web = mise à disposition de servlets • Accès aux servlets : – Par URL – http://localhost/Application/NomSymboliqueVersServlet – Application = contexte. En général, le nom du répertoire – NomSymboliqueVersServlet : fichier de configuration • Fichier de configuration de l’application – Association URL ⇔ Servlets – Paramétrage – ... <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app> <context-param> <param-name>webmaster</param-name> <param-value>[email protected]</param-value> <description> The EMAIL address of the administrator to whom questions and comments about this application should be addressed. </description> </context-param> • Fichier web.xml du répertoire WEB-INF TPI P. Reignier A.30 TPI P. Reignier A.31 Quelques éléments de web.xml (2) Quelques éléments de web.xml (3) <servlet> <servlet-name>formulaire</servlet-name> <description> Repond au formulaire </description> <servlet-class>Formulaire</servlet-class> <!-- Load this servlet at server startup time --> <load-on-startup>1</load-on-startup> </servlet> <context-param> <param-name>webmaster</param-name> <param-value>[email protected]</param-value> </context-param> • Paramètres accessibles par la servlet. • Optionnel. • Evite de recompiler. <servlet-mapping> <servlet-name>formulaire</servlet-name> <url-pattern>*.form</url-pattern> </servlet-mapping> • Accès : String value = getServletContext().getInitParameter("webmaster"); </web-app> // exemple d’utilisation pw.print("Contact : <a HREF=\"mailto:"+value+"\">"+value+"</a>") ; TPI P. Reignier TPI P. Reignier A.32 A.33 Quelques éléments de web.xml (4) Quelques éléments de web.xml (4) <servlet> <servlet-name>formulaire</servlet-name> <servlet-class>Formulaire</servlet-class> <!-- Load this servlet at server startup time --> <init-param> <param-name>param1</param-name> <param-value>value1</param-value> </init-param> <load-on-startup>10</load-on-startup> </servlet> <servlet-mapping> <servlet-name>formulaire</servlet-name> <url-pattern>/action.form</url-pattern> </servlet-mapping> • associe une URL à un nom symbolique de servlet • Accessible par : • Déclaration des servlets disponibles. http://localhost:8080/MyApplication/action.form • Paramètres optionnels : – Relecture par : getServletConfig().getInitParameter("param1") ; • Attention : le fichier action.form n’existe pas • Permet de les pré-charger. TPI P. Reignier A.34 TPI P. Reignier A.35 Quelques éléments de web.xml (5) Arborescence source <servlet-mapping> <servlet-name>formulaire</servlet-name> <url-pattern>/*.form</url-pattern> </servlet-mapping> • associe une URL à un nom symbolique de servlet • Accessible par : http://localhost:8080/MyApplication/action.form http://localhost:8080/MyApplication/autre.form • Permet de gérer plusieurs URL par une même servlet • Aiguillage dans la servlet par req.getRequestURI(). TPI P. Reignier A.36 • Cycle de développement : 1. Ecriture du code source 2. Compilation vers le répertoire build 3. Déploiement sous tomcat (soit par recopie vers webapps, soit en utilisant directement le répertoire build) 4. Test 5. Retour si nécessaire au point 1 6. Une fois terminé, création de l’archive war sous dist. P. Reignier A.38 P. Reignier A.37 Développement TPI TPI