JSP+JSTL - Java au Cnam
Transcription
JSP+JSTL - Java au Cnam
GLG 203 JSP et la JSTL S. Rosmorduc 1 Rappel : les servlets • Serveur application java • une servlet est associée à une URL (ou plusieurs) • la servlet dispose de méthodes comme doGet(requete,reponse) ou doPost(requete,reponse) • … qui doivent traiter une requête et produire la réponse correspondante • mais la production de html est pour le moins pénible… 2 Les JSP • en gros: du php, mais en java • une jsp, c’est du code HTML, avec des vrais bouts de java dedans • • des scriptlets, introduites par <% ….%>, avec des instructions java • des expressions, introduites par <%= … %> pour faire de l’affichage plus facilement plus adapté que les servlets pour l’affichage du résultat (mais pas pour son calcul !) 3 <!DOCTYPE html> <html> <head> <title>JSP Page</title> </head> <body> <h1>Table de multiplication par <%= request.getParameter("n")%></h1> <ul> <% for (int i = 1; i <= 10; i++) { int val = Integer.parseInt(request.getParameter("n")); %> <li> <%= "" + val + " x " + i + "= " + (val * i)%> </li> <%}%> </ul> </body> </html> 4 Déploiement des JSP • La jsp est placée dans l’application • elle est a priori accessible par son chemin. • exemple : une jsp à la racine de l’application a comme URL http://localhost:8080/exemple-jstl/simple.jsp • une jsp dans un dossier nommé « forum » aura comme URL http://localhost:8080/exemple-jstl/forum/page.jsp 5 JSP : fonctionnement • la première fois qu’un utilisateur visite une page gérée par une jsp, le serveur crée le code java de la servlet correspondante • pour glassfish, c’est dans generated/jsp/exemple-jstl/org/apache/jsp • le code est dans un sous-package de org.apache.jsp ; • le code java est compilé, puis exécuté ; • la première visite d’une jsp prend un peu de temps ; • à la visite suivante, la servlet est déjà disponible. 6 Code engendré package org.apache.jsp; … public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase … { … public void _jspService(HttpServletRequest request, HttpServletResponse response) throws …{ … out.write("<!DOCTYPE html>\n"); out.write("<html>\n"); out.write(" <head>\n"); … out.write(" <h1>Table de multiplication par "); out.print( request.getParameter("n")); out.write("</h1>\n"); … for (int i = 1; i <= 10; i++) { int val = Integer.parseInt(request.getParameter("n")); 7 Scriptlets • forme : <% …. %> • contiennent des instructions java ; • recopiées à l’intérieur de la méthode _jspService • ne peuvent donc pas contenir de déclaration de méthodes ou de classes, juste des instructions. 8 Expressions • forme <%= …. %> • contiennent une expression au sens java du terme • donc pas de « ; » final ! • l’expression est insérée dans _jspService par une instruction : out.print(expression); • pour les objets, out.print(…) appelle toString() 9 Code engendré package org.apache.jsp; … public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase … { … public void _jspService(HttpServletRequest request, HttpServletResponse response) throws …{ … out.write("<!DOCTYPE html>\n"); out.write("<html>\n"); out.write(" <head>\n"); … out.write(" <h1>Table de multiplication par "); out.print( request.getParameter("n")); out.write("</h1>\n"); … for (int i = 1; i <= 10; i++) { int val = Integer.parseInt(request.getParameter("n")); 10 Code engendré package org.apache.jsp; … public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase … { … public void _jspService(HttpServletRequest request, HttpServletResponse response) throws …{ … out.write("<!DOCTYPE html>\n"); HTML out.write("<html>\n"); out.write(" <head>\n"); … out.write(" <h1>Table de multiplication par "); out.print( request.getParameter("n")); out.write("</h1>\n"); … for (int i = 1; i <= 10; i++) { int val = Integer.parseInt(request.getParameter("n")); 10 Code engendré package org.apache.jsp; … public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase … { … public void _jspService(HttpServletRequest request, HttpServletResponse response) throws …{ … out.write("<!DOCTYPE html>\n"); out.write("<html>\n"); out.write(" <head>\n"); … out.write(" <h1>Table de multiplication par "); out.print( request.getParameter("n")); out.write("</h1>\n"); … for (int i = 1; i <= 10; i++) { int val = Integer.parseInt(request.getParameter("n")); 10 Code engendré package org.apache.jsp; … public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase … { … public void _jspService(HttpServletRequest request, HttpServletResponse response) throws …{ … out.write("<!DOCTYPE html>\n"); out.write("<html>\n"); out.write(" <head>\n"); … out.write(" <h1>Table de multiplication par "); out.print( request.getParameter("n")); Expression out.write("</h1>\n"); … for (int i = 1; i <= 10; i++) { int val = Integer.parseInt(request.getParameter("n")); 10 Code engendré package org.apache.jsp; … public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase … { … public void _jspService(HttpServletRequest request, HttpServletResponse response) throws …{ … out.write("<!DOCTYPE html>\n"); out.write("<html>\n"); out.write(" <head>\n"); … out.write(" <h1>Table de multiplication par "); out.print( request.getParameter("n")); out.write("</h1>\n"); … for (int i = 1; i <= 10; i++) { int val = Integer.parseInt(request.getParameter("n")); 10 Code engendré package org.apache.jsp; … public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase … { … public void _jspService(HttpServletRequest request, HttpServletResponse response) throws …{ … out.write("<!DOCTYPE html>\n"); out.write("<html>\n"); out.write(" <head>\n"); … out.write(" <h1>Table de multiplication par "); out.print( request.getParameter("n")); out.write("</h1>\n"); … for (int i = 1; i <= 10; i++) { Scriptlet int val = Integer.parseInt(request.getParameter("n")); 10 Code engendré package org.apache.jsp; … public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase … { … public void _jspService(HttpServletRequest request, HttpServletResponse response) throws …{ … out.write("<!DOCTYPE html>\n"); out.write("<html>\n"); out.write(" <head>\n"); … out.write(" <h1>Table de multiplication par "); out.print( request.getParameter("n")); out.write("</h1>\n"); … for (int i = 1; i <= 10; i++) { int val = Integer.parseInt(request.getParameter("n")); 10 Variables disponibles • Regardons le code de _jspService… public void _jspService(HttpServletRequest request, HttpServletResponse response) … PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; … application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); 11 Variables disponibles • Votre code peut utiliser : • request et response • out pour écrire • session pour accéder à la session • application pour accéder à l’objet ServletContext • page désigne la servlet elle-même • config pour accéder à l’objet ServletConfig 12 Déclarations • pour créer des méthodes auxiliaires (mauvaise idée: ne pas les mettre dans la jsp) ou des variables d’instance (très mauvaise idée) : • <%! …. %> • le code entre <%! … %> est recopié à l’intérieur de la classe. 13 Import • problème : comment utiliser, par exemple, une ArrayList ? • toujours noter java.util.ArrayList ??? lourd. • les imports se placent avant la classe dans une classe java. • Notation : <%@page import="java.util.ArrayList"%> 14 La balise <%@page …%> • permet d’écrire des directives qui concernent la classe engendrée (et non le code de la méthode _jspService) • peut être répétée. Par exemple, si plusieurs imports : <%@page import=« java.util.ArrayList"%> <%@page import="java.util.Set"%> 15 Attributs de <%@page …%> • contentType : le content type (ex: "text/html") • pageEncoding : codage du texte de la page (ex : "UTF-8") • session : true ou false, pour créer une session (ou non). true par défaut. • errorPage : nom d’une autre JSP, qui sera appelée si une exception est levée sur la jsp courante • isErrorPage : déclare que la jsp sert à afficher un message d’erreur. Elle dispose alors d’une variable exception. 16 errorPage et isErrorPage • Exemple : dans notre première jsp, qui affiche la table de multiplication, nous ajoutons <%@page errorPage="erreur.jsp"%> • dans erreur.jsp : <%@page isErrorPage="true" %> <!DOCTYPE html> <html> <body> <h1>Erreur : <%= exception.getClass()%></h1> </body> </html> 17 inclusion de jsp • Deux méthodes • <%@include file="toto.jsp" %> : recopie directement le code de toto.jsp dans la servlet courante (risque de conflits avec les noms de variables) • <jsp:include page="toto.jsp"/> inclut le résultat de l’exécution de la jsp toto.jsp dans la sortie de la jsp courante. La page incluse est déterminée à l’exécution (possibilité d’utiliser une variable) 18 Les beans • les jsp peuvent accéder au beans (page, request, session et application) • une des manière de le faire est de déclarer le bean dans la jsp : <!DOCTYPE html> <html> <body> <jsp:useBean id="compteur" scope="session" class="demo.Compteur"/> <%= compteur.nextVal() %> </body> </html> 19 jsp:useBean • id : nom du bean. La jsp aura accès à une variable du même nom par la suite • class : classe du bean ; s’il n’existe pas, il sera créé par son constructeur par défaut • scope : • page • request • session • application 20 M/V/C • JSP n’est pas adapté à l’écriture de code • C’est un langage de template, pour décrire le contenu d’une page • Architecture M/V/C web : • Modèle : vos classes métier java, souvent derrière une façade • Vue : une JSP • Contrôleur : une servlet. Reçoit une requête, extrait les paramètre, délègue le traitement au modèle, puis l’affichage à une JSP. 21 Collaboration JSP/Servlet • la servlet reçoit la requête puis la traite • elle utilise ensuite un requestDispatcher pour déléguer la fin du traitement à une jsp (en gros, elle appelle la méthode jspService de la jsp) • elle doit dire à la jsp quoi afficher • problème : passer des information de la servlet à la jsp • solution : les passer en bean request 22 Servlet @WebServlet(urlPatterns = {"/somme"}) public class Somme extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int a= Integer.parseInt(req.getParameter("a")); int b= Integer.parseInt(req.getParameter("b")); req.setAttribute("resultat", (a+b)); req.getRequestDispatcher("somme.jsp").forward(req, resp); } } 23 JSP • La jsp ne calcule plus rien… elle affiche. <!DOCTYPE html> <html> <body> <jsp:useBean id="resultat" class="Integer" scope="request"/> La somme est <%= resultat %> </body> </html> 24 Organisation du code • Comme la JSP est uniquement visitée à travers une servlet, elle n’a pas besoin d’avoir une URL « légale » ; • il est d’usage de placer ces JSP dans le dossier WEB-INF/jsp • elles ne sont alors plus visibles « directement ». 25 Redirection • Exemple : un forum en ligne. Le formulaire pour envoyer un message est en mode POST, à l’adresse http:// localhost/forum/message/add • quand l’utilisateur a envoyé un message, le forum va lui montrer le résultat: le message tel qu’il apparaîtra désormais. • mais… si l’utilisateur recharge cette page résultat (url: http://localhost/forum/message/add) il « rejoue » la requête POST • du coup, le message est envoyé deux fois ??? 26 Redirection • Solution: que le résultat ait une autre URL, en mode GET • Techniquement : utiliser une redirection • dans le protocole http : une redirection est une réponse envoyée par le serveur. Le client a demandé une URL A, et le serveur lui dit que tout compte fait, il doit demander une URL B • à l’origine, prévu pour gérer le cas d’une page déplacée. 27 Version sans redirection @WebServlet public class AddMessage extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String titre= req.getParameter("titre"); String contenu= req.getParameter("contenu"); ForumFacade f= ForumFacade.getInstance(); Message m= f.creer(titre, contenu); req.setAttribute("message", m); req.getRequestDispatcher("vue.jsp").forward(req, resp); } } • l’affichage se fait dans la même requête • en réaffichant, on rejoue la requête 28 Version avec redirection @WebServlet public class AddMessage extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String titre= req.getParameter("titre"); String contenu= req.getParameter("contenu"); ForumFacade f= ForumFacade.getInstance(); Message m= f.creer(titre, contenu); resp.sendRedirect("voir?id="+m.getId()); } } • on renvoie sur une nouvelle URL • l’affichage se fait avec une nouvelle requête (voir?id=…) • on peut la recharger sans risque 29 forward et redirect • forward est en gros un include. le chemin qu’on donne est un chemin local (pas une URL) • redirect est un élément du protocole HTTP. On renvoie une nouvelle adresse au client, qui va charger cette nouvelle page. 30 Suppression du Java dans les JSP : la JSTL 31 L’expression language (première approche) • Dans la JSP, on peut écrire : <%= request . getAttribute ( ” nomCapitalise ” ) %> • Mais c’est long et peu lisible. • de plus, on souhaite éliminer le code java des JSP : la JSP ne fait que de l’affichage. • Un langage spécial est disponible : ${nomCapitalise} • affiche la valeur du bean. 32 Expression language • Quand un bean est un objet avec des accesseurs... ; • par exemple un bean personne de classe Personne avec les accesseurs getNom() et getPrenom() ; • alors ${personne.nom} affiche le nom de la personne en appelant personne.getNom() 33 <!DOCTYPE html> <html> <head> <title >JSP Page</title > </head> <body> <jsp:useBean id="resultat" scope="request" class="Integer"/> Le résultat est <%= resultat %></body> </html> <!DOCTYPE html> <html> <head> <title >JSP Page</title > </head> <body> Le résultat est ${resultat} </body> </html> 34 Récapitulation • la servlet reçoit une requête, extrait les arguments, et décide quoi faire ; • elle délègue le traitement effectif à des classes métiers, qui ne connaissent rien du web ; • puis elle range les valeurs à afficher dans des beans request, enfin, elle passe la main à une JSP. 35 Du traitement des formulaires 36 Exemple de formulaire • Application qui • saisit le nom et le prénom d’une personne; • vérifie que les champs sont remplis; • calcule le texte de la salutation ; • l’affiche avec une jsp ; • réaffiche le formulaire avec des messages d’erreur et les données erronées en cas de problème. • C’est la même servlet qui affiche le formulaire et le traite. Deux jsp : le formulaire et le résultat. • souvent, doGet() est appelé pour le premier affichage, et doPost pour les traitements. 37 public class Saluer extends HttpServlet { protected void doGet(.........) { // A priori, premier appel... req.getRequestDispatcher("/WEB-INF/jsp/ saluerForm.jsp") .forward(req, resp); } protected void doPost(..........) { String jsp; String nom= req.getParameter("nom"); String prenom= req.getParameter("prenom"); if (nom == null || prenom == null || "".equals(nom) || "".equals(prenom)) { req.setAttribute("message", "les champs doivent être remplis"); jsp= "/WEB-INF/jsp/saluerForm.jsp"; } else { req.setAttribute("nom", nom.toUpperCase()); req.setAttribute("prenom", prenom); jsp= "/WEB-INF/jsp/saluer.jsp"; } req.getRequestDispatcher(jsp).forward(req, resp); } } 38 Servlet Formulaire si pas de message, <!DOCTYPE html> chaîne vide <html> <head> <title>Saluer</title> </head> <body> <p style="color:red">${message}</p> <form method="POST"> <p>nom : <input type="text" name="nom" value="${param.nom}"/></p> <p>prenom : <input type="text" name="prenom" value="${param.prenom}"/></p> <p><input type="submit"/></p> </form> </body> paramètre </html> « prenom » de la requête 39 Améliorations possibles • ranger les messages d’erreurs dans une map nomParamètre -> message d’erreur • facilite la création de messages liés à un paramètre particulier 40 Expression language • Dans les JSP, écrites entre ${….} • L’opérateur ≪ a.b ≫ a des effets variés selon le type de a. • si a est une Map, a.b • si a est un objet, a.b • a.get(b) a.getB() si a est un tableau, a.b a[b] (ex. ${tab.3}) • On peut utiliser « . » en cascade : <p> rue $ {facture.adresse.rue}.... • Le langage d’expression est aussi utilisable pour des calculs : prix TTC : ${facture . montant ∗ 1.196} 41 Expression Language • Opérateurs • empty : savoir si un bean est défini ou non. • ${empty facture} ⟺y-a-t-il un bean facture ? • opérateurs arithmétiques:+,-,*,/,%; • opérateurslogiques: and, or, not; • comparaisons : eq (equal), ne (not equal), lt (less than), gt (greater than), ge (greater or equal), le (lesser or equal) 42 Valeurs prédéfinies • param : valeur des paramètres. à utiliser pour les paramètres mono-valués ; par exemple ${param.nom} • paramValues : valeur des paramètres. à utiliser pour les paramètres multi-valués (résultat de sélections multiples). • cookie : permet l’accès aux cookies. 43 JSTL • Java Standard Tags Library ; • jeu de tags pour remplacer la plupart des constructions java dans les JSP ; • travaille de très près avec l’expression language. • Utilisation : mettre la ligne <%@taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> • vers le début du fichier jsp. • éventuellement ajouter la bibliothèque JSTL à votre projet. 44 Comparaison… 45 Boucle en JSTL • boucle forEach • une variable dont le nom est donné par var=… prend une série de valeurs Parcours d'une liste à partir de l'élément numéro 4 : <ul> <c:forEach var="e" items="${promotion}" begin="4"> <li> ${e} </li> </c:forEach> </ul> Parcours d'une map : <ul> <c:forEach var="a" items="${param}"> <li> ${a.key} : ${a.value}</li> </c:forEach> </ul> Numérique : affiche 0 3 6 9 12 <c:forEach var="i" begin="0" end="12" step="3"> ${i} </c:forEach> 46 Test en JSTL 47 Protection contre l’injection de javascript • le code • <p> ${message} </p> • est dangereux • un utilisateur peut saisir le message <script> document.location.href="http://sitePirate.com" </script> • solution : transformer les < et > en caractères normaux 48 Protection contre l’injection javascript • Solution : la balise <c:out value="..."/> • le code devient <p> <c:out value="${message}"/></p> sortie: • <p>< ;SCRIPT language="Javascript"> document.location.href="http://sitePirate.com" ; < ;/SCRIPT></p> • très moche, mais inoffensif. 49 c:set • permet de fixer la valeur d’un bean • paramètres : • var : nom du bean • scope : portée • value : valeur à lui donner 50 c:url • permet de « construire » proprement une URL pour l’affichage • gère les url relativement à la racine de l’application • injecte proprement des paramètres GET dans l’URL en les protégeant correctement. <c:url var="url1" value="/message/vue"> <c:param name="id" value="${message.id}"/> </c:url> 51 Étendre JSP avec des bibliothèques de tag • • • • On peut écrire ses propres tags pour alléger ses jsp on crée un dossier tags dans WEB-INF (et éventuellement des sous-dossiers, « custom » dans l’exemple qui suit) chaque tag est défini par un fichier « .tag » la JSP doit déclarer la bibliothèque de balises : <%@taglib prefix="perso" tagdir="/WEB-INF/tags/perso" %> 52 Définition du tag • plus ou moins comme une JSP <%@tag import="java.time.LocalDate"%> <%@tag description="affiche la date" pageEncoding="UTF-8"%> <span class="date"> <%= LocalDate.now() %> </span> 53 Utilisation <%@ taglib prefix="perso" tagdir="/WEB-INF/tags/perso" %> <!DOCTYPE html> <html> <body> <h1>Hello World!</h1> <perso:date /> </body> </html> 54 Paramètres… • On peut passer des paramètres à notre tag <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@tag import="java.time.LocalDate"%> <%@tag description="affiche la date" pageEncoding="UTF-8"%> <%@attribute name="color" %> ou plus simplement: if (color == null) {color= "blue";} <c:if test="${empty color}"> <c:set var="color" value="blue"/> </c:if> <%-- any content can be specified here e.g.: --%> <span style="color: ${color}"> <%= LocalDate.now() %> </span> 55 passage des paramètres… <%@ taglib prefix="perso" tagdir="/WEB-INF/tags/perso" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h1>Hello World!</h1> <perso:date color="yellow"/> </body> </html> 56 Déclaration des paramètres des tags • la balise attribute prend les attributs suivants • name: le nom de l’attribute • type: le type java de l’attribut (String par défaut) • required : l’attribut est-il obligatoire ? (si non, en cas d’absence, sa valeur sera null). 57 Tag implémentés en java • tags déclarés dans un fichier dld • • qui nomme le tag et l’associe à une classe … et implémentés par une classe java 58 Fichier TLD • lie les tags aux classes • déclare leurs attributs <?xml version="1.0" encoding="UTF-8"?> <taglib> <tlib-version>1.0</tlib-version> <short-name>p1</short-name> <uri>/WEB-INF/tlds/p1.tld</uri> <tag> <name>HideTag</name> <tag-class>demo.HideTag</tag-class> <body-content>tagdependent</body-content> <attribute> <name>show</name> <rtexprvalue>true</rtexprvalue> <type>boolean</type> </attribute> </tag> </taglib> 59 public class HideTag extends SimpleTagSupport { private boolean show; @Override public void doTag() throws JspException { JspWriter out = getJspContext().getOut(); try { if (show) { JspFragment f = getJspBody(); if (f != null) { f.invoke(out); } } } catch (java.io.IOException ex) { throw new JspException("Error in HideTag tag", ex); } } public void setShow(boolean show) { this.show = show; } } Implémentation java 60 Utilisation dans une JSP <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="perso" tagdir="/WEB-INF/tags/perso" %> <%@ taglib prefix="p1" uri="/WEB-INF/tlds/p1.tld" %> <!DOCTYPE html> <html> <body> <h1>Hello World!</h1> <p1:HideTag show="false"> ce texte sera caché par le tag… </p1:HideTag> </body> </html> 61