La technologie des Servlets

Présentation du protocole HTTP

Caractéristiques du protocole HTTP (Hyper Text Transmission Protocol) :

figures/jsp/http.png

Les requêtes HTTP

Forme générale d'une requête :

méthode URI protocole
attribut1: valeur1
attribut2: valeur2
....
<ligne vide>

Un exemple (notez la ligne vide à la fin) :

GET /index.html HTTP/1.0
accept: */*
connection: keep-alive
cache-control: no-cache
    

Les requêtes de lecture

♦  Méthode GET : récupération de données identifiées par l'URI.

♦  Méthode HEAD : demande d'informations sur les données identifiées par l'URI (pas de transmission de données).

♦  Méthode POST : identique à GET, mais le client ajoute à la requête un ensemble de paires :

nom1=valeur1
nom1=valeur2
nom2=valeur3
...

Vous pouvez noter qu'il est possible d'associer plusieurs valeurs au même nom.

Les requêtes de modification

♦  Méthode PUT : dépose d'un fichier.

♦  Méthode OPTIONS : interroge le serveur sur les méthodes disponibles sur une URI donnée.

♦  Méthode DELETE : ...

♦  Méthode TRACE : ...

Les réponses HTTP

Forme générale d'une réponse :

protocole CODE description
attribut1: valeur1
attribut2: valeur2
....
<ligne vide>
<les données>

Un exemple (notez la ligne vide) :

HTTP/1.0 200 OK
server: Apache...
date: ...
content-Type: text/html
              
<html>
   ....
</html>

Les codes de réponse HTTP

Les principaux codes de réponse :

200 requête exécutée avec succès
301 ressource déplacée définitivement
302 ressource déplacée temporairement
403 requête non autorisée
404 ressource non disponible
500 erreur interne du serveur
... ...

Retrouvez les principaux codes sur http://www.codeshttp.com/ ou directement dans la RFC2616.

Applications WEB

Principes des applications WEB :

figures/jsp/appweb.png

Solutions propriétaires et CGI

♦ CGI (Common Gateway Interface) une solution simple mais coûteuse :

figures/jsp/cgi.png

Chaque requête donne lieu à la création d'un processus qui traite la requête et produit la réponse. La charge du système est donc très importante. Des langages de scripts (bash, perl, python, etc.) sont souvent choisis pour leur facilité de mise en oeuvre.

♦ API propriétaires non portables (ISAPI de Microsoft ou NSAPI de NetApp) :

figures/jsp/apipro.png

Dans cette approche, chaque application WEB est une librairie ajoutée au serveur WEB. Nous suivrons la même idée dans le monde Java.

ASP, PHP et JSP

♦ ASP (Active Server Page) de Microsoft. Les pages ASP sont un mélange de VBscript et de HTML.

♦ PHP (PHP : Hypertext Preprocessor) même solution avec un langage de script conçu à cet effet.

♦ Servlet, JSP (Java Server Page) même solution avec un mélange de Java et HTML.

La technologie des Servlets

♦  Version 3.0 (JEE 6)

♦  C'est une spécification

♦  Produits qui implantent cette norme :

♦  Historique :

Application WEB Java

Une application WEB Java est constituée

Une application WEB a la structure suivante :

mon-application.war
  | ressources statiques (html, jpg, css, ...)
  + WEB-INF/
      | web.xml
      + classes/       contient les .class
      + lib/           contient les .jar

Ces fichiers peuvent être rangés dans une WAR (Web Application aRchive) en fait une archive jar (qui est un ZIP).

Conteneur WEB

♦ Les applications sont déployées dans un conteneur WEB :

figures/jsp/servlet.png

♦ Le conteneur WEB assure :

Configuration (web.xml)

♦ le fichier web.xml :

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">

    <display-name>Application de test</display-name>
    <description>Ma première application</description>

   <!-- déclarations des servlets -->
   <servlet> ... </servlet>

   <!-- correspondance servlets / URL -->
   <servlet-mapping> ... </servlet-mapping>

</web-app>

♦ Déclaration des servlets :

<servlet>
    <servlet-name>UneServletSimple</servlet-name>
    <servlet-class>mypackage.SimpleServlet</servlet-class>
    <init-param>
        <param-name>jdbc.url</param-name>
        <param-value>jdbc:mysql://machine/nomdebase</param-value>
    </init-param>
    ...
    <load-on-startup>2</load-on-startup>
</servlet>

La clause load-on-startup permet d'indiquer un ordre dans le chargement et l'initialisation des servlets.

♦ Mise en correspondance servlet versus URL :

<servlet-mapping>
    <servlet-name>UneServletSimple</servlet-name>
    <url-pattern>/simple*</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>UneServletSimple</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

URL traitées par la servlet :

http://serveur-name/application-name/simple
http://serveur-name/application-name/simple/hello.html
http://serveur-name/application-name/simple/documents/7419.html

http://serveur-name/application-name/simple/hello.do
http://serveur-name/application-name/logout.do

Des méthodes s'appliquant sur la requête permettent de découper l'URL.

Ma première servlet

package mypackage;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

import mybusiness.Business;

public final class SimpleServlet extends HttpServlet {
    Business bs = null;

    // initialisation de la servlet
    public void init(ServletConfig c) throws ServletException {
        String jdbc = c.getInitParameter("jdbc.url");
        bs = new Business(jdbc);
    }

    // destruction la servlet
    public void destroy() {
        bs.close();
    }

    public void doGet( ... )    { ... }
    public void doPost( ... )   { ... }
    public void service( ... )  { ... }
}

♦  Détail de la méthode doGet :

public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws IOException, ServletException {
  
    // récupération d'un paramètre de la requête
    String data = request.getParameter("data");

    // appel de la couche métier
    String result = bs.action(data);

    // calcul du résultat
    response.setContentType("text/html");
    PrintWriter writer = response.getWriter();

    writer.println("<html><body>");
    writer.println("<h1>Hello</h1>");
    writer.printf("<p> %s </p>", result);
    writer.println("</body></html>");
    }

Il existe autant de méthodes à surcharger dans la classe HttpServlet que de méthodes HTTP.

Le cycle de vie d'une servlet

♦ Un exemple :

figures/jsp/cycles.png

♦ C'est la même instance (éventuellement exécutée en parallèle dans plusieurs threads) qui traite les requêtes de tous les clients.

♦ Les Servlets peuvent être préchargées au lancement du serveur ou lancées à la demande.

Les interfaces de requête et de réponse

♦  javax.servlet.http.HttpServletRequest

public HttpSession getSession()
public String getParameter(String name)
public String[] getParameterValues(String name)
...

♦  javax.servlet.http.HttpServletResponse

public void setContentType(String type)
public java.io.PrintWriter getWriter() throws ...
public ServletOutputStream getOutputStream() throws ...
public void addHeader(String name, String value)
public void addCookie(Cookie cookie)
...

Servlet et formulaires HTML

♦ Un formulaire HTML :

<html><body>
<form action="test" method="POST">
  <label>Nom : </label>
    <input type="text" name="nom" size="15"/><br/>
  <label>Prénom : </label>
    <input type="text" name="prenom" size="15"/><br/>
  <label>Statut : </label>
    <select name="statut" size="1">
      <option value="Etudiant">Etudiant</option>
      <option value="Prof">Enseignant</option>
    </select><br/>
  <input type="submit" name="boutonOK" value="Valider"/>
</form>
</body></html>

♦ La servlet test :

public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws IOException, ServletException
{
   String nom = request.getParameter("nom");
   String prenom = request.getParameter("prenom");
   
   response.setContentType("text/html");
   response.getWriter().printf(
      "<html><body><p>Bonjour %s %s</p></body></html>",
      prenom, nom
   );
}

La gestion des sessions

♦ Principe : pour identifier le client, le serveur renvoi, dans la réponse à la première requête, un cookie (JESSIONID) :

figures/jsp/client-serveur-1.png

♦ Les cookies sont tirés au hasard.

♦ Lors des requêtes suivantes, le client est repéré et le serveur peut lui associer une session :

figures/jsp/client-serveur-2.png

Codage des sessions

♦ Rappel : dans l'interface HttpServletRequest nous trouvons la méthode

public HttpSession getSession()

♦ L'interface javax.servlet.http.HttpSession :

public Object getAttribute(String name)
public void setAttribute(String name, Object value)
public void invalidate()
...

Ces méthodes permettent de récupérer un objet depuis une session, de placer un objet dans une session et finalement, de vider une session.

La durée de vie des sessions

♦ Réglage de la durée de vie des sessions :

<web-app ... >

    ... premières déclarations ...
    ... déclaration des servlets ...

    <!-- durée de vie des sessions en minutes -->
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

    ...

Suivre les modifications de session

♦ Si un object référencé en session implante HttpSessionBindingListener (interface du package javax.servlet.http), alors les évènements

void valueBound(HttpSessionBindingEvent event) ;
void valueUnbound(HttpSessionBindingEvent event) ;

lui indiquent sont attachement ou son détachement d'une session.

♦ On peut également écouter les évènements :

Durée de vie des objets

Il existe plusieurs visibilité et durée de vie pour les objets Java :

Instances de porté requête :

// ranger un objet dans une requête
request.setAttribute("myObject", myObject);
...
// le récupérer
myObject = (MyObject) request.getAttribute("myObject");

♦  Utilité : faire passer des données d'une servlet à une autre servlet (chaînage) ou d'une servlet à une page JSP.

♦  fin de vie : fin du traitement de la requête.

Instances de porté session :

// ranger un objet dans une session
HttpSession session = request.getSession();
session.setAttribute("myObject", myObject);
...
// le récupérer
myObject = (MyObject) session.getAttribute("myObject");

♦  Utilité : faire passer des données d'une requête à une autre requête émise par le même client. A titre d'exemples :

♦  fin de vie : fin de la session (timeout ou invalidation).

Instances de porté application :

// ranger un objet dans la zone application
HttpSession session = request.getSession();
ServletContext context = session.getServletContext();
context.setAttribute("myObject", myObject);
...
// le récupérer
myObject = (MyObject) context.getAttribute("myObject");

♦  Utilité : rendre des données ou des services accessibles à tous les clients. A titre d'exemples :

♦  fin de vie : fin de l'application (durée de vie très longue).

La porté des instances Java :

figures/jsp/scope.png