Servlets et JSP - electricservices

Download Report

Transcript Servlets et JSP - electricservices

Servlets et JSP
Le Web en Java - 1

Le développement Web en Java se base sur plusieurs
frameworks standard






L’API Servlets (actuellement version 2.5)
JSP ou JavaServer Pages (actuellement version 2.1)
JSF ou JavaServer Faces (actuellement version 1.2)
Nous étudierons les deux premiers dans ce cours
Les servlets permettent de construire des pages Web
dynamiques en emboîtant la présentation HTML dans
le code.
Inversement, les pages JSP emboîtent le code dans
la présentation HTML
Le Web en Java - 2

Généralement on utilise les deux techniques simultanément
pour implémenter le pattern MVC2 (aussi appelé Modèle 2) :



Le browser de l’utilisateur, via une page html (ou jsp) appelle une
servlet en remplissant un formulaire précisant sa demande. La
servlet s’exécute sur le serveur, effectue le travail logique demandé,
stocke le ou les résultats dans la requête ou la session puis
forwarde vers une page jsp (les Views).
Celle-ci récupère les résultats stockés et se charge de leur
présentation en HTML/CSS. Cette page html est envoyée au
browser.
L’idéal est de n’écrire qu’une seule servlet qui fait le dispatching
(Contrôleur)
Le Web en Java - 3



Ces techniques ont évolué afin de permettre une séparation des
tâches entre le développeur Java et le Webmaster. Ce dernier
n’a pas (besoin d’avoir) de connaissances en Java;
Aussi, on va faire disparaître toute trace de code Java dans les
pages JSP. Ceci se fait grâce à des possibilités de scripting via
l’Expression Language (EL) et en utilisant des tags de contrôle
logique via JSTL (JSP Standard Tag Library).
JSF fournit un tel contrôleur et de nombreux tags qui
permettent d’améliorer la présentation, de valider les données
… Il ne peut être utilisé seul mais au dessus de JSP (par
exemple).
Serveur

Vous devez disposer d’un servlet container (Tomcat) ou d’un
serveur d’application (JBoss). Créez une configuration dans
Eclipse.
 dans Eclipse : ouvrez l'onglet Servers (Windows – Show
View – Other – Server – Servers)
 dans cet onglet cliquez à droite : New – Server choisissez
JBoss v 4.2, cliquez Next, entrez l'adresse où est installé
JBoss via le bouton Browse et cliquez sur Finish
 dans l'onglet Servers apparaît maintenant JBoss 4.2; double
cliquez dessus; dans la fenêtre qui s'ouvre, suivez le lien
"Open launch configuration"
 Ouvrez l'onglet Arguments; dans Program arguments vous
devez mettre
-c default –b 0.0.0.0
 Cliquez sur OK
Installation



Dans Eclipse, vous créez un Dynamic Web Project :
New – Project – Web – Dynamic Web Project.
Si votre projet utilise aussi des EJB 3.0, un serveur
d’application est obligatoire et dans ce cas dans
Eclipse, créez un Enterprise Application Project (New
– Project – J2EE – Enterprise Application Project,
donnez un nom, faites Next, puis Next, cochez
Generate deployment descriptor, cliquez sur New
Module et selectionnez EJB Module et Web Module)
Quelle que soit la technique utilisée, vérifiez que les
jar pour les servlets et JSP (servlet-api.jar et jspapi.jar) soient dans votre classpath.
Déploiement





Avant d’exécuter une servlet ou une page JSP, vous devez
déployer votre application.
Pour cela il vous faut créer un fichier war (web archive) si vous
travaillez avec un Dynamic Web Project seul.
Si vous développez un Enterprise Application Project, il faut
créer un fichier ear (entreprise archive, qui contient le fichier
war et le fichier jar où sont placés les EJB).
Pour déployer, il suffit de copier ce fichier war ou ce fichier ear
dans la directory webapps de Tomcat ou deploy de JBoss.
La création de l’archive à déployer et le déploiement peut se
faire en une seule étape dans Eclipse en exportant le projet
concerné sous forme de WAR ou EAR dans la directory voulue.
L’API Servlet
Les interfaces - 1

Implémentées par le container
 ServletConfig
 ServletContext
 ServletRequest
 ServletResponse
 RequestDispatcher
 FilterChain

FilterConfig
Les interfaces - 2

A implémenter par le développeur selon nécessité
 Servlet
 ServletContextListener
 ServletContextAttributeListener
 SingleThreadModel (deprecated)

Filter
Les classes







GenericServlet
ServletContextEvent
ServletContextAttributeEvent
ServletInputStream
ServletOutputStream
ServletRequestWrapper
ServletResponseWrapper
L’interface Servlet

Il déclare les méthodes





public void init(ServletConfig config)
throws ServletException
public void service(ServletRequest req,
ServletResponse res) throws
ServletException, IOException
public void destroy()
public ServletConfig getServletConfig()
Les trois premières méthodes font partie du cycle de
vie de la servlet
Cycle de vie d’une servlet
1.
2.
3.
4.
Le container charge et instancie la servlet. Ne faites rien dans
le constructeur. N'en écrivez même pas !
Le container appelle sa méthode init(…) en lui passant son
ServletConfig. La méthode init doit stocker ce
ServletConfig et effectuer toute autre initialisation
nécessaire (connexion à une DB, …). Si on étend
GenericServlet, on le fait en redéfinissant init() sans
paramètre.
La servlet est prête à recevoir des requêtes et à les traiter via
sa méthode service().
Quand le container n’a plus besoin de cette servlet, il appelle
sa méthode destroy() avant de la mettre à disposition du
garbage collector. C’est dans cette méthode qu’on libèrera les
ressources initialisées dans init.
Servlet et concurrence




Les servlets sont appelées par plusieurs utilisateurs
simultanément.
L’accès à leurs champs modifiables doit donc être
synchronisé
Sauf si la servlet implémente SingleThreadModel,
mais c’est déconseillé.
Exemple : la servlet Compteur




Ecrire la classe Compteur.java
Déclarer la servlet dans web.xml
Archiver et déployer (regarder la structure de l’archive)
Appeler http://localhost:8080/MyWeb/Compteur
L’interface ServletConfig


On peut obtenir sa ServletConfig via la méthode
getServletConfig (que le développeur écrit ou
dont il hérite)
Elle déclare les méthodes

String getInitParameter(String name)
Enumeration getInitParameterNames()
ServletContext getServletContext()

String getServletName()



Comme GenericServlet implémente aussi
ServletConfig, elle fournit ces méthodes.
L’interface ServletRequest - 1


Emballe la requête du client et permet d’avoir accès
aux informations qui y sont contenues
Récupérer les paramètres : envoyés par le clients (via
un formulaire ou dans l’url)




public Enumeration getParameterNames()
public String getParameter(String name)
public String[] getParameterValues(String
name)
public Map getParameterMap() // renvoie une
Map<String, String[]> !
L’interface ServletRequest - 2

Récupérer les headers de la requête




public int getContentLength()
public String getContentType()
public String getProtocol()
Gérer les attributs placés dans la requête par le
container ou une autre servlet




public
public
public
value)
public
Enumeration getAttributeNames()
Object getAttribute(String name)
void setAttribute(String name, Object
void removeAttribute(String name)
L’interface ServletRequest - 3

Divers








public
public
public
public
public
public
public
public
String getScheme() // http, ftp…
String getServerName()
int getServerPort()
boolean isSecure() // https
Locale getLocale()
Enumeration getLocales()
String getCharacterEncoding()
void setCharacterEncoding(String enc)
//défaut ISO-8859-1 (Latin 1)
L’interface ServletRequest - 4

Lire des données (fichier, objet sérialisé,…) placées
dans la requête



public ServletInputStream getInputStream()
public BufferedReader getReader()
Forwarder la requête à une autre servlet/page JSP…

public RequestDispatcher
getRequestDispatcher(String path)
ex: RequestDispatcher rd = req.
getRequestDispatcher(/resultat.jsp);
rd.forward(req, resp);
L’interface ServletResponse - 1


On peut placer des données et configurer la réponse
Indiquer la longueur, le type MIME, l’encodage …






public
public
public
public
void
void
void
void
setContentLenght(int len)
setContentType(String mime)
setCharacterEncoding(String enc)
setLocale(Locale l)
Les getters correspondant aux méthodes ci-dessus
Récupérer un stream ou writer pour écrire la réponse


public ServletOutputStream getOutputStream()
public PrintWriter getWriter()

n’appeler qu’une de ces deux méthodes !
L’interface ServletResponse - 2

Gérer le buffer de sortie






public
public
public
public
public
public
envoyé
void setBufferSize(int size)
int getBufferSize()
int flushBuffer()
void resetBuffer()
void reset() // aussi les headers
boolean isCommitted() // dès qu’on a
un buffer
Le ServletContext - 1



C’est un objet propre à la servlet, accessible à tous
les utilisateurs de celui-ci, de portée « application »
On l’obtient via la méthode getServletContext()
de la ServletConfig ou héritée de
GenericServlet
On peut y placer des attributs accessibles à tous les
utilisateurs




public
public
public
value)
public
Enumeration getAttributeNames()
Object getAttribute(String name)
void setAttribute(String name, Object
void removeAttribute(String name)
Le ServletContext - 2

Obtenir des informations générales






public java.util.Enumeration
getInitParameterNames()
public String getInitParameter(String name)
public String getServletContextName() // le
nom de l’application
public String getServerInfo() // le nom du
container
public int getMajorVersion() // de
l’implémentation de l’API Servlet
public int getMinorVersion()
Le ServletContext - 3

Obtenir des informations sur l’environnement








public ServletContext getContext(String uri)
public String getRealPath(String path)
public String getContextPath() // /MyWeb
public String getMimeType(String file)
public RequestDispatcher
getNamedDispatcher(String name) // nom de la
servlet où on va
public RequestDispatcher
getRequestDispatcher(String path)
public URL getResource(String path) // path
dans l’application
public InputStream
getResourceAsStream(String path)
Le protocole HTTP - Méthodes





GET : ne change pas les données sur le serveur
POST : pour les changer ou envoyer une grande
quantité de données
HEAD : demande seulement l’entête
DELETE : demande de supprimer une ressource sur
le serveur
PUT : upload une ressource sur le serveur
Le protocole HTTP – statut - 1


Le statuscode envoyé dans la réponse indique
comment s’est passé la requête :
Catégories de StatusCode





• 100-199: informatif; le client doit répondre par une autre
action.
• 200-299: succès.
• 300-399: le fichier à été déplacé. En général un header
Location indique la nouvelle adresse.
• 400-499: erreur due au client.
• 500-599: erreur coté serveur.
Le protocole HTTP – statut - 2

Quelques codes usuels en HTTP 1.1





• 200 (OK): Tout s’est bien passé le document est ci-après.
C’est la valeur par défaut pour les servlets.
• 204 (No Content): Le browser continue à afficher
l’ancienne page.
• 301 (Moved Permanently): Le document demandé a
été déplacé ailleurs définitivement (l’endroit est indiqué dans
le header Location). Les browsers y vont automatiquement.
• 302 (Found): Le document demandé a été déplacé
ailleurs temporairement (l’endroit est indiqué dans le header
Location). Les browsers y vont automatiquement.
Les servlets doivent utiliser sendRedirect et non
setStatus pour renvoyer ce code et mettre une valeur
dans le header Location.
Le protocole HTTP – statut - 3




401 (Unauthorized): Le browser essaye d’accéder à une
page protégée par mot de passe et il n’y a pas de header
Authorization dans la requête. Le Serveur Web ouvre une
fenêtre de login dans le browser et réitère la demande avec
le Header Authorization mis aux valeurs entrées
403 (Forbidden): Le browser essaie d’accéder à une
directory et le serveur a été configuré pour le refuser
404 (Not Found): Cette page n’existe pas. Les servlets
doivent utiliser sendError et non setStatus pour renvoyer ce
code.
408 (Request timeout): La page n’a pu être obtenue
avant le timeout
L’API
HTTPServlet
HTTPServlet - 1

La classe abstraite HTTPServlet hérite de
GenericServlet.


Il est toujours possible de redéfinir init() (sans
paramètre) et destroy() en cas de besoin.
Elle possède deux méthodes service() : la première
héritée est redéfinie pour appeler la seconde en castant ses
paramètres :



void service(ServletRequest rq, ServletResponse
rp) appelle
void service(HTTPServletRequest req,
HTTPServletResponse resp)
Il n’y a aucune raison de redéfinir ces méthodes
HTTPServlet - 2

Cette deuxième méthode service() se contente de dispatcher à des
méthodes spécialisées pour chaque méthode du protocole HTTP :
 protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws
ServletException, IOException
 protected void doPost(HttpServletRequest req,
HttpServletResponse resp) throws
ServletException, IOException
 protected void doHead(HttpServletRequest req,
HttpServletResponse resp) throws
ServletException, IOException
 protected void doPut(HttpServletRequest req,
HttpServletResponse resp) throws
ServletException, IOException
HTTPServlet - 3



Normalement on se contente de redéfinir les
méthodes dont on a l’usage : doGet et doPost et
bien souvent, dans doPost, on se contente d’appeler
doGet.
Il est inutile de redéfinir doHead : la méthode héritée
fait déjà tout ce qu’il y a à faire.
Si on est certain que le protocole est HTTP1.1, on
peut aussi utiliser les méthodes doTrace et
doOptions. Il est inutile de les redéfinir.
HTTPServletRequest - 1


Cette interface étends ServletRequest
Elle ajoute des méthodes pour traiter les headers
HTTP






public
public
public
public
public
public
String getMethod() // GET, POST
Enumeration getHeaderNames()
String getHeader(String name)
Enumeration getHeaders(String name)
long getDateHeader(String name)
int getIntHeader(String name)
HTTPServletRequest - 2

Headers HTTP









Accept : les types MIME supportés par le browser.
Accept-Encoding : les encodages supportés.
Authorization : à envoyer pour une page protégée HTTP.
Connection : en HTTP 1.0 doit valoir keep-alive pour une connexion
persistante. En HTTP1.1 les connexions sont persistantes par défaut. Pour
qu’une connexion soit persistante, il faut de plus que le header ContentLength soit placé sur la réponse, ce qui se fait à l’aide de
setContentLength.
Cookie : les cookies envoyés, utiliser getCookies plutôt que
getHeaders.
Host : le host demandé, obligatoire en HTTP1.1.
If-Modified-Since : le client ne veut la page que si modifiée depuis une
certaine date. utiliser la méthode getLastModified de HTTPServlet et
non getHeader.
Referer : l’URL de la page qui vous a référencé
User-Agent : le browser
HTTPServletRequest - 3

Méthodes spécialisées à utiliser au lieu de getHeader
public int getContentLength()

public String getContentType()
Ces deux méthodes sont héritées de ServletRequest

public Cookie[] getCookies()


Méthodes relatives à l’authentification :




public String getAuthType() : renvoie BASIC_AUTH,
DIGEST_AUTH, CLIENT_CERT_AUTH ou FORM_AUTH
public String getUserName()
public Principal getUserPrincipal() à utiliser
avec le package java.security
public boolean isUserInRole()
HTTPServletRequest - 4

Méthodes d’information du chemin
http://localhost:8080/MyWeb/request/HTTPRequestServlet/intox.htm?Nom=Mic
hel+Debacker&Employeur=IPL

public String getQueryString()
Nom=Michel+Debacker&Employeur=IPL





public String getContextPath() /MyWeb
public String getServletPath()/request/HTTPRequestServlet
public String getPathInfo() /intox.htm (voir web.xml)
public String getPathTranslated()
public String getRequestURI()
/MyWeb/request/HTTPRequestServlet/intox.htm

public StringBuffer getRequestURL() ce qui précède le ?
Réponse HTTP

Format d’une réponse HTTP
HTTP/1.1 200 OK
Content-Type text/html
<html><head><title>Le titre</title></head>
<body>Ici on met le texte de la page</body>
</html>

La ligne vide qui sépare les headers de la page est
fondamentale.
HTTPServletResponse - 1

Gestion des Headers de réponse HTTP


on utilise les méthodes set pour installer la seule valeur ou
la première valeur d’un header. Elles réinitialisent le header.
on utilise les méthodes add pour ajouter une seconde, …
valeur à un header


public void setHeader(String name, String
value)
public void addHeader(String name, String
value)
HTTPServletResponse - 2

Méthodes de convenances







public
value)
public
value)
public
date)
public
date)
public
public
public
void setIntHeader(String name, int
void addIntHeader(String name, int
void setDateHeader(String name, long
void addDateHeader(String name, long
boolean containsHeader(String name)
void setContentType(String type)
void setContentLength(int length)
HTTPServletResponse - 3

Headers de réponse HTTP












Allow: méthodes HTTP supportées par le serveur
Cache-Control: s’il vaut no-cache, la page ne sera pas mise en cache. Voir
Pragma pour les browsers qui ne supportent qu’HTTP 1.0
Content-Encoding: l’encodage (supporté par le browser d’après la requête)
Content-Length: longueur (calculée par programme) de la page
Content-Type: type MIME de la page
Expires: la date à laquelle la page ne doit plus être gardée en cache
Last-Modified: dernière modification
Location: l’url où rediriger la requête
Pragma: comme Cache-Control, mais pour HTTP 1.0
Refresh: nombre de secondes avant de rafraîchir la page automatiquement
Set-Cookie: donne une valeur à une clé à mettre en cookie (addCookie)
WWW-Authenticate: le type d’autorisation à fournir lors de la prochaine
requête
HTTPServletResponse - 4

Gestion des codes de statut



public void setStatus(int statusCode)
public void sendError(int statusCode)
public void sendError(int stCode, String msg)
Les deux dernières effacent aussi le buffer et envoient la réponse
(d’erreur). La servlet n’a donc plus le droit d’écrire sur sa sortie.
Pour le paramètre statusCode, on utilise les constantes définies
dans HTTPServletResponse.
HTTPServletResponse - 5

Rediriger la requête

public void sendRedirect(String url)



La réponse ne peut pas avoir été envoyée au client
(committed)
Si le serveur doit (ou peut) garder la session par URL rewriting,
il faut d’abord appliquer
String encodeRedirectURL(String url) à l’url de
destination.
La redirection est différente du forwarding : en redirection, la
requête est perdue, la page est envoyée au client et le browser
réitère la requête avec la nouvelle location. En forwarding, tout
se passe coté serveur, on peut avoir commencer à écrire la
réponse et la requête est transmise à la nouvelle location.
Après le forward, la réponse est committed.
Gestion des cookies - 1

Envoyer un cookie dans la réponse :
Cookie cookie = new Cookie("nom", "valeur");
response.addCookie(cookie);

Lire les cookies envoyés avec la requête :
Cookie[] cookies = request.getCookies();
for (Cookie c: cookies)
if (c.getName().equals("nom")) {
traiterLeCookie(c);
break;
}
Gestion des cookies - 2

La classe Cookie possède des getters getProp et des setters
setProp pour les propriétés prop suivantes :








comment : commentaire, guère supporté
domain : le domaine d’application du cookie. Le host actuel doit en
faire partie.
maxAge : durée de vie en secondes
name : nom du cookie. Pas de setter (propriété read-only)
path : le chemin d’application du cookie. Par défaut l’arbre de la
page actuelle.
secure : si true, n’est envoyé qu’en SSL, HTTPS
value : la valeur du cookie
version : la version du protocole de cookie supporté : 0 =
Netscape, 1 = RFC 2109
Gestion de la session - 1

Il y a trois manières de gérer la session


par cookie : méthode préférée quand le browser accepte les
cookies
par URL rewriting : utiliser String encodeURL(String
url) s’il est possible que le serveur doivent employer cette
technique (c’est le deuxième choix)
url : http:/www.ipl.be/index.html
url encodée :
http:/www.ipl.be/index.html;jsessionid=A03E…

en utilisant des champs HIDDEN dans un formulaire stocké
dans la réponse et renvoyé dans les requêtes suivantes
Gestion de la session - 2

Par URL rewriting :




refusez les cookies et entrez
http://localhost:8080/MyWeb/HTTPRequestServlet/intox.htm?Nom
=Michel+Debacker&Employeur=IPL
récupérez la session et testez :
http://localhost:8080/MyWeb/HTTPRequestServlet/intox.htm;jsessi
onid=44475A059F1E7865AD55098ECC20289D?Nom=Michel+Deba
cker&Employeur=IPL où vous replacez
44475A059F1E7865AD55098ECC20289D par le numéro de session
récupéré : le numéro de session ne change pas. Sans le jsessionid
ou avec un mauvais numéro de session, on a une session différente
à chaque requête.
Gestion de la session - 3

Java EE utilise 3 manières de gérer la session :




URL Rewriting
Cookies
Session SSL en HTTPS
Obtenir sa session : la demander à la requête


Si une session existe :
HTTPSession session = request.getSession();
Si aucune session n’existe : la créer (create = true)
HTTPSession getSession(boolean create)
Si, dans ce cas (pas de session existante), on passe false
aucune session n’est créée et la méthode renvoie null.
Gestion de la session - 4

L’interface HTTPSession : usage

Y stocker des attributs de portée session :





public
public
public
value)
public
Enumeration getAttributeNames()
Object getAttribute(String name)
void setAttribute(String name, Object
void removeAttribute(String name)
Obtenir le Servlet Context

public void getServletContext()
Gestion de la session - 5

Gérer la session elle-même







public
public
public
public
public
public
public
void getId()
long getCreationTime()
boolean isNew()
long getLastAccessedTime()
int getMaxInactiveInterval()
void setMaxInactiveInterval(int intrvl)
void invalidate() // libère aussi les attributs