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>&lt ;SCRIPT language=&#034;Javascript&#034;&gt;
document.location.href=&#034;http://sitePirate.com&#034; ; &lt ;/SCRIPT&gt;</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