Alain Tchana, [email protected]
Transcription
Alain Tchana, [email protected]
N7 2015 Programmation web Alain Tchana, Maître de Conférence Institut National Polytechnique de Toulouse IRIT / Équipe SEPIA [email protected] Inspiré des slides de Daniel Hagimont Alain Tchana, [email protected] N7 2015 Plan Apperçu HTML, CSS, CGI Rappel MCV JEE : servlet, JSP, EJB Alain Tchana, [email protected] N7 2015 Web et HTML Web et HTTP Alain Tchana, [email protected] N7 2015 Le web ● Système d’information hypermédia ( texte, son, images, etc.) ● Né en 1989, par Tim Berners-Lee au CERN ● Concept de base universelle d’information ● Accès aux bases d’information ● Accessibles à tous et partout ● Liens entre les informations Alain Tchana, [email protected] N7 2015 Le protocole HTTP HTTP : HyperText Transfer Protocol – Modèle client-serveur pour le transfert des documents hypertextes – Protocole utilisé par les serveurs Web depuis 1990 – Protocole minimaliste basé sur TCP/IP et utilisant des messages sous forme de chaînes de caractères – Utilise un ensemble de mots clés (méthode) pour discuter avec le serveur distant URL : Uniform ressource Locator – Syntax • method://machine[:port]/fichier[#ancre|?param] • Où method = file/ftp/http/telnet/news/mailto Client Web (Firefox) get/post catalogue.html Serveur Web (Apache) Alain Tchana, [email protected] N7 2015 Les méthodes HTTP GET Pour récupérer une ressource HEAD Pour obtenir des informations sur une ressource POST Pour récupérer une ressource OPTIONS, CONNECT, TRACE Pour interroger le serveur sur son état PUT Pour ajouter ou remplacer une ressource DELETE Pour supprimer une ressource Alain Tchana, [email protected] N7 2015 Exemple GET - client prompt>> telnet localhost 80 Trying ::1... Connected to localhost. Escape character is '^]'. GET /cgi-bin/test-cours?nom=toto&prenom=titi HTTP/1.0 Host: localhost HTTP/1.1 200 OK Date: Thu, 30 Sep 2010 11:10:01 GMT Server: Apache/2.2.16 (Debian) Vary: Accept-Encoding Connection: close Content-Type: text/html you submitted the following key-value pairs <br> - nom=toto <br> - prenom=titi <br> Connection closed by foreign host. Alain Tchana, [email protected] N7 2015 Exemple POST - client prompt>> telnet localhost 80 Connected to localhost. Escape character is '^]'. POST /cgi-bin/test-cours? HTTP/1.0 Host: localhost Content-length: 20 nom=toto&prenom=titi HTTP/1.1 200 OK Date: Thu, 30 Sep 2010 11:17:41 GMT Server: Apache/2.2.16 (Debian) Vary: Accept-Encoding Connection: close Content-Type: text/html you submitted the following key-value pairs <br> - nom=toto <br> - prenom=titi <br> Connection closed by foreign host. Alain Tchana, [email protected] N7 2015 Réponse HTTP Status HTTP_version code phrase En-tête Location : URL exacte de la ressource demandée Descriptif Server : Informations sur le serveur Content-Encoding : Type de codage du corps de la réponse Content-Length : Taille du corps de la réponse Content-Type : Type MIME du corps de la réponse Date : Date de la génération de la réponse Expires : Date d'expiration du document Last-Modified : ... Dernière modification du document Fin-Entête CRLF Ligne blanche Document ... Contenu du document demandé HTTP/1.1 200 OK Date: Fri, 09 Jan 1998 09:49:11 GMT Server: Apache/1.3b2 Last-Modified: Tue, 19 Aug 1997 11:57:17 GMT Content-Length: 118 Content-Type: text/html <html> ... Alain Tchana, [email protected] N7 2015 Code de retour Classe 1 : information (pas utilisé) Classe 2 : succès – 200 (OK), 201 (created), 204 (no content), . . . Classe 3 : redirection – 301 (moved permanently), 304 (not modified), . . . Classe 4 : erreur client – 400 (bad request), 401 (Unauthorized), 404 (not found), . . . Classe 5 : erreur serveur – 500 (internal serveur error), 501 (not implemented), 503 (service unavailable), . . . Alain Tchana, [email protected] N7 2015 Web et HTML HTML Alain Tchana, [email protected] N7 2015 ● Langage HTML HTML : Hyper Text Markup Language – Langage de description d’information structurée portable – Organisme de standardisation : WWW consortium – HTML 4.01 : http://www.w3.org/TR/html401/ ● <balise attributs> contenu </balise> – balise (tag), ex : <html> – attributs : représente des options, ex : <table width=”60%”> – contenu : texte, images ou d’autres balises – </balise> : fin de la balise Alain Tchana, [email protected] N7 2015 Syntaxe HTML (exemple) <HR> <IMG SRC=”monimage.gif” WIDTH=100 HEIGHT=120> <H1>Ceci est un titre</H1> <h2>Ceci est un soustitre</h2> <A HREF=”http://host/dir/file.html”>lien</A> <!−− Commentaire −−> XHTML est une transposition en syntaxe XML de HTML – http://www.w3.org/TR/2002/REC-xhtml1-20020801/ – syntaxe plus rigoureuse, notamment : • toute balise ouvrante doit être fermée (<img alt=”...”/>) • noms des balises et des attributs en minuscules • éléments HTML correctement imbriqués – Recommandé ! Alain Tchana, [email protected] N7 2015 ● ● ● Principales balises <a> lien hypertexte attribut : href pour une URL ou name pour une ancre <em> met en emphase une portion de texte <img> inclut une image dans le document, attributs : alt (texte alternatif) et src (chemin vers l’image) ● <div> conteneur générique de type bloc ● <p> paragraphe de texte ● <table> écriture d’un tableau voir aussi <tr>, <td>, <th> ● <h1>, <h2>, . . . <h6> niveaux de titres ● ● <ol>, <ul> listes ordonnées ou à puces simples, chaque élément (item) sera écrit <li> <form> formulaire interactif Alain Tchana, [email protected] N7 2015 Structure d'un document Bluefish Alain Tchana, [email protected] N7 2015 Mise en page CSS Alain Tchana, [email protected] N7 2015 ● Mise en page CSS : Cascading Style Sheet – Feuilles de style – Correctement pris en charge depuis 2000 – http://www.w3.org/TR/CSS2 ● Documentations – Valider son code HTML • http://validator.w3.org/ – Valider son code CSS • http://jigsaw.w3.org/css-validator/ – Tutoriels HTML – CSS • http://www.alsacreations.com/tutoriels/ Alain Tchana, [email protected] N7 2015 Syntaxe CSS /* les titres de types h1 seront en bleu et centrés */ h1 { color: blue ; text-align: center; } /* on peut appliquer des propriétés à des classes d'objet : ici seuls les paragraphes de classe 'note' auront cette propriété */ p.note { font-family: Arial, sans-serif; font-style: italic; <p class="note">Hello</p> } /* les balises html peuvent aussi être dotées d'un attribut id qui doit alors être unique dans la page */ p#menu { font-weight: bold; } <p id="menu">Call</p> /* ou encore */ #menu { font-weight: bold; } Alain Tchana, [email protected] N7 2015 Syntaxe CSS Dans l'entête du document <head > ... <style type="text/css"> h1 {color: blue;} </style> ... </head> Dans les balises <h1 style=" color: blue;"> Titre de la page </h1> Référence à une feuille externe <head> ... <link rel="stylesheet" type="text/css" href="styles.css "/> ... </head> Alain Tchana, [email protected] N7 2015 Syntaxe CSS <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http:// www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> <style type="text/css"> h1 {color: blue;} p.note {font-style: italic;} p#menu {font-weight: bold;} </style> </head> <body> <h1>Un titre</h1> <div>Un bloc. <p id="menu">Un paragraphe.</p> <p class="note">Un deuxième paragraphe (accent utf8).</p> <p>Un troisième paragraphe (accent html).</p> </div > </body> </html > Alain Tchana, [email protected] N7 2015 Premier Bilan Alain Tchana, [email protected] N7 2015 Premier bilan Initialement – Web statique • Requête limitée à la demande de ressources statiques – Principalement des serveurs • de page HTML • accédées par HTTP Evolution vers des sites dynamiques Alain Tchana, [email protected] N7 2015 ● Premier bilan Besoin d'exécuter une application sur le serveur HTTP ● Besoin de fournir des données ● Solutions initiales – Formulaires HTML pour la saisie – Scripts CGI pour l’exécution Alain Tchana, [email protected] N7 2015 Formulaires HTML <form action=”url” method=” methode ”> ... </ form> url : identifie le programme utilisé pour traiter le formulaire method : méthode à utiliser pour transmettre l’information au serveur – GET : données ajoutées à l’URL – POST : données envoyées dans le corps du message Alain Tchana, [email protected] N7 2015 Éléments de formulaire Éléments INPUT <input type=”type” name=”nom” size=”size” maxlength=”max” value=”val” /> Différents types possibles TEXT Champ de saisie de texte PASSWORD Champ de saisie de texte caché SUBMIT Bouton de soumission du formulaire RADIO Bouton à cocher de type radio (1 unique par name) CHECKBOX Bouton à cocher (plusieurs par name) HIDDEN Champ invisible On envoie dans la requête un ensemble de pairs nom=val Alain Tchana, [email protected] N7 2015 Éléments de formulaire Éléments SELECT <select name="select"> <option value="value1">Valeur 1</option> <option value="value2" selected>Valeur 2</option> <option value="value3">Valeur 3</option> </select> Élément TEXTAREA <textarea name="textarea" rows="10" cols="50"> Saisir un texte ici. </textarea> Alain Tchana, [email protected] N7 2015 Exemple <html> <head><title>MaBanque</title></head> <body> <form method="post" action="/cgi-bin/monCGI.cgi"> <p>numero de compte<input type="text" name= "num"> </p> <p>montant<input type="text" name= "val"></p> <p> <input type="submit" name="operation" value="solde"> <input type="submit" name="operation" value="debit"> <input type="submit" name="operation" value="credit"> </p> </form> </body> </html> Alain Tchana, [email protected] N7 2015 Exemple - résultat Alain Tchana, [email protected] N7 2015 Exemple GET - client prompt>> telnet localhost 80 Trying ::1... Connected to localhost. Escape character is '^]'. GET /cgi-bin/monCGI.cgi?operation=credit HTTP/1.0 Host: localhost HTTP/1.1 200 OK Date: Thu, 30 Sep 2010 11:10:01 GMT Server: Apache/2.2.16 (Debian) Vary: Accept-Encoding Connection: close Content-Type: text/html you submitted the following key-value pairs <br> - operation=credit <br> Connection closed by foreign host. Alain Tchana, [email protected] N7 2015 Exemple POST - client prompt>> telnet localhost 80 Connected to localhost. Escape character is '^]'. POST /cgi-bin/monCGI.cgi? HTTP/1.0 Host: localhost Content-length: 20 operation=credit HTTP/1.1 200 OK Date: Thu, 30 Sep 2010 11:17:41 GMT Server: Apache/2.2.16 (Debian) Vary: Accept-Encoding Connection: close Content-Type: text/html you submitted the following key-value pairs <br> - operation=credit <br> Connection closed by foreign host. Alain Tchana, [email protected] N7 2015 Scripts CGI ● Programme générant un contenu en réponse à une requête ● Programmé dans n'importe quel langage – Perl, C, C++, Java, shell, ... ● Placé dans un répertoire particulier du serveur Web (cgi-bin) ● Envoie le contenu sur STDOUT ● Doit envoyer entête (type mime) + contenu – Pour HTML: content-type : text/html Client Web exec → $QUERY_STRING → stdin get/post Serveur Web catalogue.html CGI stdout Alain Tchana, [email protected] N7 2015 ● Requête à un CGI Envoi de paramètres – champ1=valeur1&champ2=valeur2... ● Les requêtes GET et POST – GET : paramètres inclus dans l'URL • http://nom_du_serveur/cgi-bin/script.cgi?champ1=valeur1&... • Limitation à 255 catactères, visible, ... – POST : paramètres inclus dans le corps de la requête HTTP – Utilisation de formulaires (pour interactions) ● Réception des paramètres – GET : variable d'environnement QUERY_STRING – POST : STDIN, et variable d'environnement CONTENT_LENGTH Alain Tchana, [email protected] N7 2015 Exemple – serveur CGI #!/bin/bash function extract_parameter() { echo you submitted the following key-value pairs "<br>" str=$1 while [ "$str" != "" ]; do echo - `echo $str | cut -f1 -d'&'` "<br>" str=`echo $str | cut -s -f2- -d'&'` done } GET POST echo "Content-Type: text/html" echo "" extract_parameter $QUERY_STRING echo "" echo "Content-Type: text/html" echo "" read QUERY_STRING extract_parameter $QUERY_STRING echo "" Alain Tchana, [email protected] N7 2015 Web Dynamique Alain Tchana, [email protected] N7 2015 App. web dynamiques Caractéristiques d'une application web dynamique ➔ Les informations produites par le même lien varient d'un utilisateur à l'autre. 1) Les informations présentées sur la même page varient suivant les actions de l'utilisateur. Le site reconnaît chaque utilisateur Construit un contenu en fonction du user Alain Tchana, [email protected] 35 N7 2015 App. web dynamiques Caractéristiques d'une application web dynamique ➔ Les informations produites par le même lien varient avec le temps (peu être très court). 1) Les informations présentées sur la même page varient avec le temps (court). 2) Les informations présentées sur la même page varient suivant les actions de l'utilisateur. Le site se met à jour dynamiquement sans l'admin system L'utilisateur est directement à l'origine Alain Tchana, [email protected] 36 N7 2015 App. web dynamiques Caractéristiques d'une application web dynamique ➔ Les informations présentées sur la même page varient suivant les actions de l'utilisateur. 1) Les informations présentées sur la même page varient avec le temps (court). 2) Les informations présentées sur la même page varient suivant les actions de l'utilisateur. La vue prend des initiatives toute seule Modifie des bouts de la page Peut contacter un serveur distant L'utilisateur est indirectement à l'origine Alain Tchana, [email protected] 37 App. web dynamiques N7 2015 Comment était implantée une app. web dyn, à l'époque ? ➔ ➔ Un script côté serveur (CGI par exemple) ➔ Reçoit la requête ➔ Identifie l'utilisateur et génère une page HTML Toute action du client sur la page ➔ Nécessite le contact du serveur ➔ La régénération de la page (toute entière) ➔ Même si la modification était minime Alain Tchana, [email protected] 38 App. web dynamiques N7 2015 Comment était implantée une app. web dyn, à l'époque ? ➔ ➔ Conséquences (pour le développeur) ➔ Le script est volumineux ➔ Illisible ➔ Difficile à maintenir et à faire évoluer Pb. 1 Conséquences (pour le client web) ➔ Les temps de réponse sont longs (trafic sur le réseaux) ➔ Le serveur sature très vite (génération de la page entière, IO) Alain Tchana, [email protected] Pb. 2 39 N7 2015 Modèle MVC Alain Tchana, [email protected] Modèle MVC N7 2015 MVC : un guide de programmation au secours du développeur ➔ Organise le code de l'application en 3 catégories ➔ ➔ Les structures de données des informations que manipulent l'app. ➔ Contient le code métier ➔ C'est le Modèle Le code qui construit la façon dont le modèle est présenté ➔ ➔ C'est la Vue Les contrôles ➔ Contrôle des requêtes. MAJ modèle ➔ C'est le Contrôle Alain Tchana, [email protected] 42 Modèle MVC N7 2015 MVC : un guide de programmation au secours du développeur ➔ Organise le code de l'application en 3 catégories ➔ ➔ Les structures de données des informations que manipulent l'app. ➔ Contient le code métier ➔ C'est le Modèle Le code qui construit la façon dont le modèle est présenté ➔ ➔ C'est la Vue Les contrôles ➔ Contrôle des requêtes. MAJ modèle ➔ C'est le Contrôle Alain Tchana, [email protected] 43 Modèle MVC N7 2015 MVC : un guide de programmation au secours du développeur ➔ Organise le code de l'application en 3 catégories ➔ ➔ Les structures de données des informations que manipulent l'app. ➔ Contient le code métier ➔ C'est le Modèle Le code qui construit la façon dont le modèle est présenté ➔ ➔ C'est la Vue Les contrôles ➔ Contrôle des requêtes. MAJ modèle ➔ C'est le Contrôle Alain Tchana, [email protected] 44 N7 2015 MVC JEE Alain Tchana, [email protected] MVC avec JEE N7 2015 MVC : un guide de programmation au secours du développeur ➔ Plusieurs technos permettent de faire du MVC ➔ PHP ➔ JEE Le modèle Le controle Navigateur (1) HTML+ JS (2) (3) Selvlet (6) (5) Facade (4) Data (7) ➔ Etc. Codes : HTML+ JSP+ JS La vue Alain Tchana, [email protected] 46 JEE N7 2015 (1) (8) HTML+ Ajax+ JS 1er ctr+ JS modif. DOM Navigateur (9) (7) (2) (3) Selvlet (6) (5) Facade Codes : HTML+ JSP+ Ajax+ JS 1er ctr+ JS modif. DOM Alain Tchana, [email protected] (4) Data JEE N7 2015 (1) (8) HTML+ Ajax+ JS 1er ctr+ JS modif. DOM (2) Selvlet (9) (7) Navigateur (5) (6) Facade Codes : HTML+ JSP+ Ajax+ JS 1er ctr+ JS modif. DOM Tomcat Servlet server h h t t t t ... p p d d servlet servlet servlet servlet servlet JVM AJP12 HTTP Client (3) Apache Web server JDBC Tomcat Servlet server MySQL Database server Alain Tchana, [email protected] (4) Data N7 2015 JEE Servlet Alain Tchana, [email protected] N7 2015 Servlets Java S’exécute dans un “Servlet Container” sur une JVM – Tomcat ou Jetty – Soit utilisé comme un serveur intégré (web + servlets) – Soit utilisé comme un plug-in de Apache (séparé) Tomcat Servlet server h h t t t t p ... p d d JVM AJP12 HTTP Client servlet servlet servlet servlet servlet Apache Web server JDBC Tomcat Servlet server MySQL Database server Alain Tchana, [email protected] N7 2015 Servlet HTTP - API public void init() protected void doGet(HttpServletRequest req, HttpServletResponse resp) protected void doPost(HttpServletRequest req, HttpServletResponse resp) Paramètres – HttpServletRequest : permet de manipuler la requête reçue – HttpServletResponse : permet de générer la réponse Remarques – Attention, ces méthodes peuvent être exécutées en concurrence – Ces méthodes peuvent appeler des BD : JDBC Alain Tchana, [email protected] N7 2015 Exemple 1/3 <html> <head><title>Directory</title></head><body> <h1>Enter a person</h1> <form action= "Directory" method="post"> firstname<input type="text" name="firstname"><br/> lastname<input type="text" name="lastname"><br/> email<input type="text" name="email"><br/> <input type="submit" name="op" value="add"> <input type="submit" name="op" value="list"> </form> </body></html> Alain Tchana, [email protected] N7 2015 Exemple 2/3 public class Directory extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); try { Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/DirectoryDB"); Connection con = ds.getConnection(); response.setContentType("text/html"); out.print("<html><body><h1>Directory</h1>"); String op = request.getParameter("op"); if (op.equals("list")) { Statement stmt = con.createStatement(); ResultSet res = stmt.executeQuery("SELECT * FROM directory"); while(res.next()) { out.print("<p>"+res.getString("firstname")+" "+res.getString("lastname") +" "+res.getString("email")); } Alain Tchana, [email protected] N7 2015 } } Exemple 3/3 } else { PreparedStatement ps = con.prepareStatement("INSERT INTO directory VALUES(?,?,?)"); ps.setString(1, request.getParameter("firstname")); ps.setString(2, request.getParameter("lastname")); ps.setString(3, request.getParameter("email")); ps.executeUpdate(); out.print("Person was added"); } out.print("</body></html>"); } catch (Exception ex) { ex.printStackTrace(out); } Alain Tchana, [email protected] N7 2015 Session Notion de session – Une requête dépend du résultat des requêtes précédentes – Ex : caddie Création de session HttpSession HttpServletRequest.getSession () HttpSession HttpServletRequest.getSession(boolean create) Utilisation de la session Object getAttribute(String name) Enumeration getAttributeNames() long getCreationTime() int getMaxInactiveInterval() void invalidate() void removeAttribute(String name) void setAttribute(String name, Object value) void setMaxInactiveInterval(int interval) Alain Tchana, [email protected] N7 2015 Cookies Création / initialisation Cookie(java.lang.String name, java.lang.String value) void setValue(java.lang.String newValue) void setMaxAge(int expiry) void setDomain(java.lang.String pattern) java.lang.String getValue() java.lang.String getDomain() int getMaxAge() A l'exécution Cookie[] HttpServletRequest.getCookies() HttpServletResponse.addCookie(javax.servlet.http.Cookie) Alain Tchana, [email protected] N7 2015 Configuration d'une servlet web.xml (déclaration des servlets – en 2.5) <servlet> <display-name>Directory</display-name> <servlet-name>Directory</servlet-name> <servlet-class>directory.Directory</servletclass> </servlet> <servlet-mapping> <servlet-name>Directory</servlet-name> <url-pattern>/Directory</url-pattern> </servlet-mapping> ou // Annotation servlet @WebServlet("/Directory") Alain Tchana, [email protected] N7 2015 Packaging et déploiement d'une servlet Un répertoire par application – Pages web (html) – Répertoire "WEB-INF" • Répertoire "classes" : les classes des servlets • Répertoire "lib" : les librairies (jar) par exemple driver jdbc • "web.xml" : descripteur des servlets – Répertoire "META-INF" • "context.xml" : configuration du container par example datasource Création d'un fichier WAR (jar) Copie dans $CATALINA_BASE/webapps Le fichier WAR est expansé Alain Tchana, [email protected] N7 2015 ● Servlet - Bilan Facile à programmer – Un peu pareil que la page PHP – Programmation en Java – Manque l'insertion de code dans les pages HTML ● Mélange entre aspects présentation (génération HTML), code métier et code d’accès aux données persistantes (à priori pas très MVC …) – But séparer ces aspects Alain Tchana, [email protected] N7 2015 JEE JSP Alain Tchana, [email protected] N7 2015 Modèle MVC Model View Controler Séparation entre – Le contrôleur : servlet qui aiguille les requêtes – La vue : pages JSP pour l’affichage à l’écran – Le Modèle : les classes (beans) qui traitent les données Requête HTTP Réponse HTTP Controler (quel traitement ? quelle page ? ) Model (traitement) View (page web) Alain Tchana, [email protected] N7 2015 JSP (Java Server Page) Langage de script (proche de Java) – Générer des pages dynamiques – Intégré dans des pages web – Compilé dynamiquement en servlet Interaction avec des classes Java parseur Page.jsp JSP compilateur Servlet.java Servlet.class Alain Tchana, [email protected] N7 2015 Un petit exemple <%@ page language="Java" %> <html> <head> <title>First.jsp</title> </head> <body> <h1>Nombres de 1 à 10</h1> <% for(int i=1; i<=10; i++) { out.println(i + "<br>"); } %> </body> </html> Alain Tchana, [email protected] N7 2015 Les directives <%@ directive attribut1="valeur" attribut2="valeur"... %> 3 directives possibles : – page : informations relatives à la page • <%@ page import=”...”%> • <%@ page errorPage=”...”%> • <%@ page isThreadSafe=”...”%> – include : fichiers à inclure littéralement (file) • <%@ include file=”...”%> – taglib : permet d'utiliser des librairies de tags personnalisés • <%@ taglib uri=”...” prefix=”...”%> Alain Tchana, [email protected] N7 2015 Les déclarations <%! declaration %> variables et méthodes globales à la page Exemple <%! String Chaine = ”bonjour”; int Numero = 10 ; public void jspInit() { // instructions } %> Alain Tchana, [email protected] N7 2015 Les scripts Java Du code Java : <% code Java %> Des évaluations d'expression : <%= expression %> Des variables prédéfinies <%@ page language="Java" %> <html><head><title>First.jsp</title> </head><body> <h1>Nombres de 1 à 10</h1> <% for(int i=1; i<=10; i++) { %> <%= i %> <br/> <% } %> </body> </html> Variables prédéfinies – HttpServletRequest request – HttpServletResponse response – HttpSession session – ServletContext application – PrintWriter out – ServletConfig config – ... Alain Tchana, [email protected] N7 2015 Les actions Des tags standards des JSP de la forme <jsp:tag attribut1=”valeur” attribut2=”valeur”... /> <jsp:forward page=”page2.jsp” /> – Transfère le contôle à une autre page JSP (annule l’appelante) <jsp:include page=”page2.jsp” /> – Transfère le contrôle à une autre page JSP (inclusion) Peuvent prendre des paramètres avec – <jsp:param name=”...” value=”...” /> (une JSP ou une Servlet) Alain Tchana, [email protected] N7 2015 Les actions <jsp:usebean id="nomAttribut" class="package.classe" scope="portéeAttribut> <%-- code executé si l'attribut est créé --%> </jsp:usebean> Importe un attribut si il existe, le crée sinon <jsp:usebean id="personne" class="testjsp.Personne" scope="session/> équivaut à <% testjsp.Personne personne = (testjsp.Personne) session.getAttribute("personne"); if (personne == null) { personne = new testjsp.Personne(); session.setAttribute("personne", personne); } %> Alain Tchana, [email protected] N7 2015 Lien HTML/Servlet/JSP Une page HTML peut référencer une servlet ou une page JSP Une page JSP peut référencer une servlet – jsp :include ou jsp :forward Une servlet peut référencer une page JSP – RequestDispatcher disp = request.getRequestDispatcher(”page.jsp”) ; – disp.forward(request, response) ; Alain Tchana, [email protected] N7 2015 Exemple : annuaire Alain Tchana, [email protected] N7 2015 Exemple : architecture Une page JSP pour chaque écran – user.jsp, person.jsp, listusers.jsp Une servlet qui aiguille les requêtes vers les pages Deux objets Java (beans) pour gérer les données – Person.java, ListOfPerson.java Alain Tchana, [email protected] N7 2015 Exemple : user.jsp <%@ page language="java" %> <html> <body> <form action="Action" method="post"> User : <input type="text" name="user"/><br/><br/> <input type="submit" value="enter"/> <input type="hidden" name="form" value="user"/> </form> </body> </html> Alain Tchana, [email protected] N7 2015 Exemple : person.jsp <%@ page language="java" %> <html> <body> <jsp:useBean id="user" class="directory.Person" scope="session" /> <b> Enter a person</b> <br/><br/> User: <%= user.user %><br/> <form action="Action" method="post"> Firstname : <input type="text" name="firstname"/><br/> LastName : <input type="text" name="lastname"/><br/> Email : <input type="text" name="email"/><br/><br/> <input type="submit" value="add"/> <input type="hidden" name="form" value="person"/> </form> </body> </html> Alain Tchana, [email protected] N7 2015 Exemple : listusers.jsp <%@ page language="java" import="directory.*, java.util.*"%> <html><body> <jsp:useBean id="listOfUsers" class="directory.ListOfPerson" scope="application"/> <b> List of registered persons </b> <br/><br/> <table border="2"> <tr><th>User</th><th>Firstname</th><th>Lastname</th><th>Email</th></tr> <% Enumeration enu = listOfUsers.list.elements(); while (enu.hasMoreElements()) { Person p = (Person)enu.nextElement(); %> <tr> <td><%= p.user %></td> <td><%= p.firstname %></td> <td><%= p.lastname %></td> <td><%= p.email %></td> </tr> <% } %> </table> </body></html> Alain Tchana, [email protected] N7 2015 Exemple : action.java (servlet) public class Action extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String form = request.getParameter("form"); HttpSession session = request.getSession(); ServletContext context = getServletContext(); if (form == null) { RequestDispatcher disp = request.getRequestDispatcher("user.jsp"); disp.forward(request, response); return; } ListOfPerson listOfUsers = (ListOfPerson)context.getAttribute("listOfUsers"); if (listOfUsers == null) { listOfUsers = new ListOfPerson(); request.setAttribute("listOfUsers", listOfUsers); } Alain Tchana, [email protected] N7 2015 Exemple : action.java (servlet) if (form.equals("user")) { String u = request.getParameter("user"); if (listOfUsers.contains(u)) { RequestDispatcher disp = request.getRequestDispatcher("listusers.jsp"); disp.forward(request, response); return; } else { Person p = new Person(); p.user = request.getParameter("user"); session.setAttribute("user", p); RequestDispatcher disp = request.getRequestDispatcher("person.jsp"); disp.forward(request, response); return; } } Alain Tchana, [email protected] N7 2015 Exemple : action.java (servlet) if (form.equals("person")) { Person p = (Person)session.getAttribute("user"); p.firstname = request.getParameter("firstname"); p.lastname = request.getParameter("lastname"); p.email = request.getParameter("email"); listOfUsers.list.add(p); } } } RequestDispatcher disp = request.getRequestDispatcher("listusers.jsp"); disp.forward(request, response); Alain Tchana, [email protected] N7 2015 Exemple : les beans public class Person { public String user, firstname, lastname, email; } public class ListOfPerson { public Vector list = new Vector(); } public boolean contains(String user) { Enumeration enu = list.elements(); while (enu.hasMoreElements()) { Person p = (Person)enu.nextElement(); if (p.user.equals(user)) return true; } return false; } Alain Tchana, [email protected] N7 2015 Servlet/JSP - Bilan Présentation – Sous forme de pages HTML – Programmation en Java dans les pages Code métier – Sous forme de servlet – Échange de données avec les pages sous forme de javaBeans Modèle MVC donne une séparation claire entre – Présentation (page JSP) – Contrôle (servlet) – Métier (programmes Java) Le traitement des données récupérées de la BD peuvent être lourds (d'où les EJB) Alain Tchana, [email protected] N7 2015 EJB Enterprise Java Beans Alain Tchana, [email protected] N7 2015 Modèle MVC Model View Controler Séparation entre – Le contrôleur : servlet qui aiguille les requêtes – La vue : pages JSP pour l’affichage à l’écran – Le Modèle : les classes (beans) qui traitent les données Requête HTTP Réponse HTTP Controler (quel traitement ? quelle page ? ) Model (traitement) View (page web) Alain Tchana, [email protected] N7 2015 Architecture souhaitée Presentation (VC) Requête HTTP Business (M) Controler servlet result Réponse HTTP Facade View JSP/HTML Alain Tchana, [email protected] Data N7 2015 Architecture souhaitée Clients Serveur d'application (Jboss) Client Java RMI Client Web HTTP Client Web service SOAP SGBD (postgresql) EJB Container Web Container Servlet JSP BD EJB Facade Entity Web Services Alain Tchana, [email protected] N7 2015 Motivations Solutions clusterisées – Tolérance aux pannes – Passage à l'échelle Maintenance et évolution du code – Adaptation, extension – Portabilité (sur d'autres serveurs d'application) Différents types de client (Web, lourd, mobiles ...) Propriétés non-fonctionnelles (services techniques) – Persistance – Transactions – Sécurité Alain Tchana, [email protected] N7 2015 Les EJB Caneva (framework) logiciel pour gérer – Des Entity beans • Représentation des données stockées en base de donnée • Évite d'avoir à implanter l'accès à la BD avec JDBC – Des Session beans • Pour implanter la facade • Inclut le code de l'application qui utilise les données (Entity) – Des Message Driven beans • Pour des traitements asynchrones Alain Tchana, [email protected] N7 2015 Prise en compte de services techniques Services techniques appelé propriétés non-fonctionnelles – La distribution – Les transactions – La persistance – Le cycle de vie – La montée en charge – Le concurrence – Le sécurité – La sérialisation –… Implantation par le container, configuration Alain Tchana, [email protected] N7 2015 Trois types d'EJB Entity beans – Représentent les données manipulées par l’application – Chaque Entity est associé à une table au niveau de la base de données Session beans – Accessibles à distance (via RMI et IIOP) – Implémentent le code métier – Stateless session beans : sans état • Une instance pour plusieurs connexions clientes (allouée à partir d'un pool) • Ne conserve aucune donnée dans son état – Statefull session bean : avec état • Création d’une instance pour chaque connexion cliente • Conserve des données entre les échanges avec le client – Singleton: Instance Unique • Création d’une instance unique quelque soit le nombre de connexion. Message Driven Beans : Beans de messages – Un listener exécute des traitements à réception d'un message JMS Alain Tchana, [email protected] N7 2015 EJB session Interface Remote (annotation @Remote) – Accessible à distance Interface Local (annotation @Local) – Accessible en local uniquement (dans le serveur d'application) Classe du bean (annotations @Singleton, @Statefull, @Stateless) – Peut implanter les 2 interfaces Local et Remote JNDI – Les interfaces définies sont exportées dans JNDI – Nom de la classe utilisée, ou nom passé en attribut du tag • @Singleton(name="monBean") – Une recherche retourne une référence au bean (unique ou une copie) Alain Tchana, [email protected] N7 2015 Un exemple : application bancaire Gestion de compte – Données • numero, nom, solde – Méthodes • • • • • Ajouter un compte Consulter un compte Consulter tous les comptes Créditer sur un compte Débiter d'un compte Depuis un client lourd distant Depuis une application Web (on pourrait le faire avec un WS) Alain Tchana, [email protected] N7 2015 Les données manipulées public class Compte implements Serializable { private int num; private String nom; private int solde; public Compte() {} public Compte(int num, String nom, int solde) { this.num = num; this.nom = nom; this.solde = solde; } public String toString() { return "Compte [num="+num+", nom="+nom+", solde="+solde+"]"; } // setters and getters Alain Tchana, [email protected] N7 2015 Interface Remote / interface Local @Remote public interface IBanqueRemote { public void addCompte(Compte c); public List<Compte> consulterComptes(); public Compte consulterCompte(int num); public void debit(int num, int montant); public void credit(int num, int montant); } @Local public interface IBanqueLocal { public void addCompte(Compte c); public List<Compte> consulterComptes(); public Compte consulterCompte(int num); public void debit(int num, int montant); public void credit(int num, int montant); } Alain Tchana, [email protected] N7 2015 Implantation d'un EJB session @Singleton public class BanqueEjbImpl implements IBanqueLocal, IBanqueRemote { private Map<Integer, Compte> comptes = new Hashtable<Integer, Compte>(); public void addCompte(Compte c) { comptes.put(c.getNum(), c); } public List<Compte> consulterComptes() { return new ArrayList<Compte>(comptes.values()); } public Compte consulterCompte(int num) { Compte c = comptes.get(num); if (c == null) throw new RuntimeException("Compte introuvable"); return c; } Alain Tchana, [email protected] N7 2015 Implantation d'un EJB Stateless public void debit(int num, int montant) { Compte c = consulterCompte(num); if (c.getSolde()<montant) throw new RuntimeException("Solde insuffisant"); c.setSolde(c.getSolde()-montant); } public void credit(int num, int montant) { Compte c = consulterCompte(num); c.setSolde(c.getSolde()+montant); } @PostConstruct public void initialisation() { addCompte(new Compte(1, "dan", 2000)); addCompte(new Compte(2, "alain", 4000)); addCompte(new Compte(3, "luc", 6000)); } } Alain Tchana, [email protected] N7 2015 Un client web (servlet) Soit la servlet est dans une JVM séparée – Configuration comme un client lourd Soit la servlet est dans le serveur d'application (avec les EJB) – Injection de dépendance @EJB private IBanqueLocal facade; – Au déploiement, variable initialisée avec une instance • de stateless, statefull ou singleton Alain Tchana, [email protected] N7 2015 Un client web (servlet) @WebServlet("/Controller") public class Controller extends HttpServlet { private static final long serialVersionUID = 1L; @EJB private IBanqueLocal facade; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { String action=request.getParameter("action"); if (action.equals("consulter")) { int num=Integer.parseInt(request.getParameter("num")); request.setAttribute("num", num); request.setAttribute("compte", facade.consulterCompte(num)); } else if (action.equals("consultertous")) { request.setAttribute("comptes", facade.consulterComptes()); } else Alain Tchana, [email protected] N7 2015 Un client web (servlet) if ((action.equals("debit")) || (action.equals("credit"))) { int num=Integer.parseInt(request.getParameter("num")); int montant=Integer.parseInt(request.getParameter("montant")); request.setAttribute("num", num); request.setAttribute("montant", montant); if (action.equals("debit")) facade.debit(num, montant); else facade.credit(num, montant); } } catch (Exception ex) { request.setAttribute("exception", ex.getMessage()); } request.getRequestDispatcher("Banque.jsp").forward(request, response); } } Alain Tchana, [email protected] N7 2015 Une petite JSP <%@ page language="java" import="bk.*, java.util.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="Controller" method="get"> <table> <tr> <td> Code :</td> <td><input type="text" name="num" value="${num}"></td> <td><input type="submit" name="action" value="consulter"></td> <td><input type="submit" name="action" value="consultertous"></td> </tr> </table> </form> Alain Tchana, [email protected] N7 2015 Une petite JSP <% if (request.getAttribute("compte") != null) { %> <table> <tr><td> Num :</td><td>${compte.num}</td></tr> <tr><td> Nom :</td><td>${compte.nom}</td></tr> <tr><td> Solde :</td><td>${compte.solde}</td></tr> </table> <form action="Controller" method="get"> <table> <tr> <td><input type="hidden" name="num" value="${num}"></td> <td><input type="text" name="montant" value="${montant}"></td> <td><input type="submit" name="action" value="debit"></td> <td><input type="submit" name="action" value="credit"></td> </tr> </table> </form> <% } %> Alain Tchana, [email protected] N7 2015 Une petite JSP <% List<Compte> l = (List<Compte>)request.getAttribute("comptes"); if (l != null) { %> <table border="1" width="80%"> <tr> <th>Num</th><th>Nom</th><th>Solde</th></tr> <% for (Compte c : l) { %> <tr><td><%=c.getNum() %></td><td><%=c.getNom() %></td><td><%=c.getSolde() %></td></tr> <% } %> </table> <% } %> ${exception} </body> </html> Alain Tchana, [email protected] N7 2015 Exécution Alain Tchana, [email protected] N7 2015 Entity beans (JPA) Représentent des objets dans la base de donnée – Une classe correspond à une table – Une instance correspond à une ligne dans cette table – Un champ correspond à une colonne de la table Programmés comme des POJO (Plain Old Java Object) – Pas d'héritage ou d'implantations spéciales Sont serialisables et peuvent être échangés avec les applications clientes Ce sont des Java Beans – Implements java.io.Serializable – Possèdent un constructeur sans arguments – Possèdent des setters / getters Alain Tchana, [email protected] N7 2015 Entity beans La classe doit être annotée avec @Entity Un champ annoté avec @Id est la clé primaire qui sert d'identifiant unique dans la table – Cette clé primaire peut être un type primitif ou de type objet Les autres champs peuvent être associés aux colonnes de la table Les champs sont utilisables au travers des accesseurs (getters/setters) On peut décrire l'association – Entre le nom de la classe et le nom de la table – Entre le nom d'un champ et le nom d'une colonne – Mêmes noms par défaut La base de donnée peut être pré-existante ou générée Alain Tchana, [email protected] N7 2015 Annotation de mapping entre le bean et la table @Table – Préciser le nom de la table associée à une classe. Par défaut, c'est le nom de la classe. @Column – Préciser le nom de la colonne associée à un champ. Par défaut, c'est le nom du champ. @Id – Déclarer un champ (donc une colonne) comme clé primaire de la table. @GeneratedValue – Demander la génération automatique de la clé primaire par la BD (tag utilisé avec @Id). @Transient – Demander à ne pas tenir compte d'un champ (par défaut tous les champs sont associés à des colonnes) Alain Tchana, [email protected] N7 2015 Entity Compte @Entity public class Compte { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int num; private String nom; private int solde; public Compte() {} public Compte(String nom, int solde) { this.nom = nom; this.solde = solde; } // num est généré // constructors, setters and getters Alain Tchana, [email protected] N7 2015 Gestion avec l'EntityManager EntityManager permet de gérer la persistance @PersistenceContext private EntityManager em; Rendre un objet persistant dans la BD Compte c = new Compte() ; em.persist(c); Retrouver un objet à partir de sa clé primaire Compte c = em.find(Compte.class, num); Retrouver un ou plusieurs objets avec une requête JPQL TypedQuery<Compte> req = em.createQuery("select c from Compte c",Compte.class); – Il y a aussi des NativeQuery (SQL) Alain Tchana, [email protected] N7 2015 Facade BanqueEjbImpl avec EntityManager @Singleton public class BanqueEjbImpl implements IBanqueLocal, IBanqueRemote { @PersistenceContext private EntityManager em; public void addCompte(Compte c) { em.persist(c); } public List<Compte> consulterComptes() { TypedQuery<Compte> req = em.createQuery("select c from Compte c", Compte.class); return req.getResultList(); } Alain Tchana, [email protected] N7 2015 Facade BanqueEjbImpl avec EntityManager public Compte consulterCompte(int num) { Compte c = em.find(Compte.class, num); if (c == null) throw new RuntimeException("Compte introuvable"); return c; } public void debit(int num, int montant) { Compte c = consulterCompte(num); if (c.getSolde()<montant) throw new RuntimeException("Solde insuffisant"); c.setSolde(c.getSolde()-montant); } public void credit(int num, int montant) { Compte c = consulterCompte(num); c.setSolde(c.getSolde()+montant); } ... } Alain Tchana, [email protected] N7 2015 Etat des objets Objet transient – @Transient – Pas d'image dans la BD Objet attaché – Objet géré dans le container EJB est associé à une image dans la BD – Toute modification de l'objet est répercutée dans la BD Objet détaché – Objet associé à une image dans la BD, mais plus géré par le container – Lorsqu'un objet attaché est sérialisé, sorti du container, modifié, puis repassé au Container c = em.merge(c); Alain Tchana, [email protected] N7 2015 Exécution avec JPA Alain Tchana, [email protected] N7 2015 Gérer les associations entre les Entity @OneToMany @ManyToOne @OneToOne @ManyToMany Alain Tchana, [email protected] N7 2015 @OneToMany (unidirectionnel) pk=primary key fk=foreign key Un Entity (Client) possède un champ Collection de références vers des instances (d'un autre Entity (Compte)) Exemple : un client a plusieurs comptes @Entity public class Client { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) int id; String nom; @Entity public class Compte { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) int id; int solde; @OneToMany List<Compte> comptes; Peut être implanté par une fk ou une table de jointure (avec unicité pk Compte) public void ajoutCompte(int cli_id, Compte c) { em.persist(c); Client cli = em.find(Client.class, cli_id); cli.getComptes().add(c); } Alain Tchana, [email protected] N7 2015 @ManyToOne (unidirectionnel) Un Entity (Compte) possède un champ référence vers une instance (d'un autre Entity (Client)) Exemple : un compte appartient à un client (qui peut en avoir plusieurs car plusieurs comptes peuvent avoir le même propriétaire) @Entity public class Client { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) int id; String nom; @Entity public class Compte { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) int id; int solde; @ManyToOne Client owner; public void ajoutCompte(int cli_id, Compte c) { em.persist(c); Client cli = em.find(Client.class, cli_id); c.setOwner(cli); } Alain Tchana, [email protected] N7 2015 @OneToMany / @ManyToOne (bidirectionnel) Permet la navigation dans les 2 sens Exemple : un client a plusieurs comptes et un compte appartient à un client @Entity public class Client { @Entity public class Compte { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) int id; String nom; @Id @GeneratedValue(strategy= GenerationType.IDENTITY) int id; int solde; @OneToMany(mappedBy="owner") List<Compte> comptes; @ManyToOne Client owner; Alain Tchana, [email protected] N7 2015 @OneToMany / @ManyToOne (bidirectionnel) Le mappedBy indique le champ correspondant à la relation dans l'autre Entity On dit que le coté opposé au mappedBy (Compte) est le porteur de la relation On peut le faire dans l'autre sens, mais ce serait inefficace La mise à jour – Doit être faite du coté du porteur de la relation (Compte) – Elle est propagée de l'autre coté par le container (dans la liste de Client) public void ajoutCompte(int cli_id, Compte c) { em.persist(c); Client cli = em.find(Client.class, cli_id); c.setOwner(cli); } Alain Tchana, [email protected] N7 2015 @OneToOne Unidirectionnel – B1 doit pointer sur un B2 qui n'est pointé que par B1 – Deux implantations possible : fk dans B1 ou B2 – La BD ne vérifie pas forcément l'unicité de la fk – JBoss ne semble pas le faire pour unidirectionnel Bidirectionnel – Le schéma ci-dessous est utilisé (garantit unicité fk coté B2) // Client @OneToOne(mappedBy="owner") Compte compte; // Compte @OneToOne Client owner; public void changerCompte(int cli_id, Compte c) { em.persist(c) ; Client cli = em.find(Client.class, cli_id); Compte old = cli.getCompte(); old.setOwner(null); c.setOwner(cli); } sinon Exception Alain Tchana, [email protected] N7 2015 @ManyToMany Unidirectionnel – Comme un @OneToMany unidirectionnel (mais pas unicité du référençant) – @ManyToMany des 2 cotés sans mappedBy correspond a 2 relations indépendantes Bidirectionnel – @ManyToMany des deux cotés – Un porteur de l'association avec mappedBy – Forcément une table de jointure (peut être implanté sans table de jointure avec une fk pour unidirectionnel) – Une mise à jour est effectuée du coté du porteur et propagée à l'autre coté Alain Tchana, [email protected] N7 2015 @ManyToMany // Client @ManyToMany List<Compte> comptes; // Compte @ManyToMany(mappedBy="comptes") List<Client> owners; public void partagerCompte(int cli_id, int co_id) { Client cli = em.find(Client.class, cli_id); Client co = em.find(Compte.class, co_id); cli.getCompte().add(co); } Le compte apparaît dans la liste comptes du client Le client apparaît dans la liste owners du compte Alain Tchana, [email protected] N7 2015 Cascades / Fetch Entity Manager permet d'appeler les opérations persist(), merge(), remove() (notamment) – On peut contrôler la propagation de ces opérations sur les Entity référencés // Client @OneToMany(cascade=CascadeType.REMOVE) List<Compte> comptes; Que se passe t-il lorsqu'un Entity est sérialisé (sorti du container), pour ses références aux autres Entity – On peut contrôler le chargement des Entity // Client @OneToMany(mappedBy="owner", fetch=FetchType.EAGER) List<Compte> comptes; – Un client sérialisé aura une liste cohérente de comptes – Par défaut FetchType.LAZY (chargement paresseux lors de l'utilisation) Alain Tchana, [email protected] N7 2015 Attention Il faut toujours utiliser les setter/getter pour affecter des champs (notamment pour le maintien des relations bidirectionnelles) Alain Tchana, [email protected] N7 2015 L'essentiel Alain Tchana, [email protected] N7 2015 L'essentiel Tomcat Jboss Postgres Entity bean Servlet 1 Session bean (facade) n Entity bean @EJB table @Stateless @PersistenceContext new MyEntity em.persist() em.find() em.createQuery() @Entity @Id @OneToOne @OneToMany @ManyToOne @ManyToMany Alain Tchana, [email protected] table N7 2015 L'essentiel Jboss Postgres Facade @Stateless public class Mngr { @PersistenceContext EntityManager em; public void ajoutCompte ( String na, int nu, int ba) { Account a = new Account(nu,ba); em.persist(a); Person p = em.find(Person.class,na); p.getList().add(a); } } @Entity public class Person { @Id String name; String address; @OneToMany List<Account> list; } 1 n @Entity public class Account { @Id int num; int balance; } Alain Tchana, [email protected] Person name address Account num balance name N7 2015 Conclusion Alain Tchana, [email protected]