Programmation JEE/Servlets

Un livre de Wikilivres.

Un servlet est une classe JAVA côté serveur qui reçoit des données HTTP et qui opère un ou des traitements et devant respecter les contraintes de ce protocole HTTP.

Les servlets[modifier | modifier le wikicode]

Exemple de servlet[modifier | modifier le wikicode]

package servlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class Hello
 */
@WebServlet("/Hello")
public class Hello extends HttpServlet {

    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public Hello() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)              
                                               throws ServletException, IOException {
 
        // TODO Auto-generated method stub
       
        response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
        try {
            out.println("Hello World");
        } finally {
            out.close();
        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub

        doGet(request,response);
    }
}

Description[modifier | modifier le wikicode]

On remarque deux méthodes dans cette classe : doGet et doPost, la première répond par HTTP à l’envoi d'une requête GET, la seconde à l'envoi d'une requête POST. Comme l'on veut que dans les deux cas la servlet réponde, doPost renvoie à doGet.

Déployement sous TomCat[modifier | modifier le wikicode]

  • Placer la classe compilée avec son package dans le répertoire classes de WEB-INF du répertoire web de travail (ici : webTest)
  • Modifier le web.xml de WEB-INF en ajoutant :
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="true">  

  <!-- Début ici -->

    <servlet>
      <servlet-name>Hello</servlet-name><!-- Nom de la classe -->
      <servlet-class>servlet.Hello</servlet-class><!-- Arborescence de la classe : avec le package -->
    </servlet>
    <servlet-mapping>
        <servlet-name>Hello</servlet-name><!-- Nom de la classe -->
        <url-pattern>/Hello</url-pattern><!-- Pattern de la classe dans l'url -->
    </servlet-mapping>

   <!-- Fin ici -->

<web-app>

Le WEB-INF comprend donc :

   WEB-INF
     web.xml
     classes
       servlet
         Hello.class

Appel de la servlet[modifier | modifier le wikicode]

http://localhost:999/webTest/Hello

Résultat dans le navigateur :

Hello World

Anatomie de l'url[modifier | modifier le wikicode]

[Protocol://][DNS]:[PORT]/[RootEntryDirectory]/[ServletName]

Méthodes d'informations sur l'URL[modifier | modifier le wikicode]

          // Retourne le nom du serveur
        request.getServerName();

          // Retourne le port du serveur
        request.getServerPort();

          // Retourne le nom de l'application hébergeant la servlet
        request.getContextPath();

          // Retourne le chemin de la servlet
        request.getServletPath();

          // Retourne type de la requete http utillisee
        request.getMethod();

          // Retourne parametres passes dans URL
        request.getQueryString();

          // Retourne URL utilisee pour contacter la servlet
        request.getRequestURL();

          // Retourne l'adresse locale
        request.getLocalAddr();

        request.getLocalName();

        request.getLocalPort();

        request.getRemoteAddr();

        request.getRemoteHost();

Exemple dans la servlet :

package servlet;

import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class Hello
 */
@WebServlet("/Hello")
public class Hello extends HttpServlet {
private static final long serialVersionUID = 1L;
   
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Hello() {
        super();
        // TODO Auto-generated constructor stub
    }

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {
    out.println(request.getServerName());
    out.println("<br/>");
    out.println(request.getServerPort());
    out.println("<br/>");
    out.println(request.getContextPath());
    out.println("<br/>");
    out.println(request.getServletPath());
    out.println("<br/>");
    out.println(request.getMethod());
    out.println("<br/>");
    out.println(request.getQueryString());
    out.println("<br/>");
    out.println(request.getRequestURL());
    out.println("<br/>");
    out.println(request.getLocalAddr());
    out.println("<br/>");
    out.println(request.getLocalName());
    out.println("<br/>");
    out.println(request.getLocalPort());
    out.println("<br/>");
    out.println(request.getRemoteAddr());
    out.println("<br/>");
    out.println(request.getRemoteHost());
    } finally {
    out.close();
    }
    }
   
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
   
      processRequest(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
     throws ServletException, IOException {
    // TODO Auto-generated method stub

    processRequest(request, response);
    }
}

Cet appel : http://localhost:999/webTest/Hello

localhost
999
/webTest
/Hello
GET
null
http://localhost:999/webTest/Hello
127.0.0.1
localhost
999
127.0.0.1
127.0.0.1

Méthodes de lecture des paramètres[modifier | modifier le wikicode]

          // Récuperation du paramètre par le nomParametre
        request.getParameter(nomParametre);

 // Retourne une énumeration de tous les paramètres d'une requête
request.getParameterNames();

 // Retourne toutes les valeurs du paramètre de nomParametre
        request.getParameterValues(nomParametre);

          // Retourne une itération de nom de paramètres
        request.getParameterMap();

Méthodes de lecture des En-Têtes[modifier | modifier le wikicode]

          // Retourne les noms du header
        request.getHeaderNames();

 // Retourne les headers
request.getHeaders();

 // Retourne le nombre d'octets dans la requête
        request.getContentLength();

          // Retourne le type de contenu de la requête
        request.getContentType();

          // Retourne la langue privilégiée
        request.getLocale();

          // Retourne la liste des langues
        request.getLocales();

          // Retourne la date du header
        request.getDateHeader(String name);

          // Retourne le header spécifié par le "name"
        request.getHeader(String name);

          // Retourne les headers spécifiés par le "name"
        request.getHeaders(String name);

Méthodes d'ajout d'informations à la requête[modifier | modifier le wikicode]

          // Assure le stockage d'un objet dans l'objet HttpServletRequest
        request.setAttribute(String name, Object o);

          // Retourne l'objet stocké "name"
        request.getAttribute(String name);

          // Returne une enumeration des noms d'attributs
        request.getAttributeNames();

          // Supprime l'attribut "name" des attributs de la requête
        request.removeAttribute(String name);

Méthodes d'ajout des en-têtes[modifier | modifier le wikicode]

Les en-têtes HTTP sont utilisés pour ajouter à la réponse des informations supplémentaires.

          // Cette méthode permet d'indiquer la nature des informations présentes dans la réponse
        response.setContentType(String type);

          // Cette méthode indique la langue locale
        response.setLocale(Locale loc);

          // Cette méthode ajoute le header "name" avec sa valeur "value"
        response.addHeader(String name, String value);

Élaboration du corps de la réponse[modifier | modifier le wikicode]

  • (PrintWriter)getWriter() permet de transferer du texte dans le corps de la réponse HTTP
  • (ServletOutputStream)getOutputStream() permet de transférer du binaire dans le corps de la réponse HTTP

Ne jamais utiliser ces deux objets simultanément sous peine d'une exception IllegalStateException

Voici un exemple d'envoi binaire:

package servlet;

import java.io.*;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ReponseHttp2
 */
@WebServlet("/ReponseHttp2")
public class ReponseHttp2 extends HttpServlet {
private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ReponseHttp2() {
        super();
        // TODO Auto-generated constructor stub
    }
   
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    response.sendRedirect("images/toto.jpg");
    }
   
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request,response);
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request,response);
}

}
  • Dans cet exemple nous faisont appel à processRequest(request, response) pour obtenir invariablement le traitement en get et post

Élaborer une réponse HTTP[modifier | modifier le wikicode]

Les codes de status sont répartis en 5 catégories :

1XX : informatif
2XX : succès
3XX : redirection
4XX : erreur client
5XX : erreur serveur

Le détail des codes est disponible chez http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

  • setStatus(int rc)
  • sendError(int sc, String message)

... permettent de changer le status d'erreur de la page. Pour exemple nous allons générer une erreur serveur.

package servlet;

import java.io.*;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ReponseHTTP
 */
@WebServlet("/ReponseHTTP")
public class ReponseHTTP extends HttpServlet {
private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ReponseHTTP() {
        super();
        // TODO Auto-generated constructor stub
    }

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {
    response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "le serveur est surchargé. Veuillez réessayer plus tard");
    } finally {
    out.close();
    }
    }
   
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}

}

Autres ressources[modifier | modifier le wikicode]

RequestDispatcher[modifier | modifier le wikicode]

include[modifier | modifier le wikicode]

Inclusion d'une ressource externe.

RequestDispatcher rd = null;
rd = getServletContext().getRequestDispatcher("/header.html");
rd.include(request, response);

forward[modifier | modifier le wikicode]

Transfert du resultat d'une servlet vers une autre ressource.

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.HttpServlet;
import javax.servlet.HttpServletRequest;
import javax.servlet.HttpServletResponse;

public class Result extends HttpServlet {
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
     throws ServletException, IOException {
       
       response.setContentType("text/html;charset=UTF-8");
       PrintWriter out = response.getWriter();
       try {
         int result = 10;
         RequestDispatcher rd = null;
         rd = getServletContext().getRequestDispatcher("/result.jsp");
         request.setAttribute("resultat", result);
         rd.forward(request, response);
       } finally {
         out.close();
       }
   }
}

La ressource de destination : result.jsp

<%@page contentType="text/html" pageEncoding="UTF-8">
<%@page import="java.text.*" %>
<html>
  <body>
    <%
    resultat=(double) request.getAttribute("resultat");
    %>

    Resultat : <%= resultat %>
  </body>
</html>

Redirection[modifier | modifier le wikicode]

Le serveur informe le navigateur de faire une requête HTTP vers l'url indiquée.

location[modifier | modifier le wikicode]

response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // Pour une réponse HTTP 301
response.setHeader("location", "http://www.google.be"); // Pour une réponse HTTP 302

redirect[modifier | modifier le wikicode]

response.sendRedirect("http://www.google.be");

Filtres[modifier | modifier le wikicode]

Les filtres ajoutent un traitement sur une requête HTTP avant qu'elle soit reçue par une servlet ou sur la réponse HTTP avant qu'elles soient transmises.

Leurs roles sont :

  • Contrôle des accès
  • Journalisation des accès
  • Décompression des données
  • Décryptage
  • Conversion des données

Plusieurs réponses peuvent être exécutées successivement. La classe filtre doit implémenter javax.servlet.Filter.

Évènements[modifier | modifier le wikicode]

Les évènements nous informent des opérations de l'application comme l'instanciation et la destruction des objets.

  • Évènements liés à l'application : Ceux déclenchés par servlet context.
  • Évènements liés aux sessions : Les classes de ce type doivent implémenter HttpSessionListener, HttpSessionAttributeListener.

Synchronisation des servlets[modifier | modifier le wikicode]

Cette synchronisation permet d'éviter au serveur d'utiliser deux threads en même temps, par exemple, lorsque deux instances de la même classe appellent une même méthode par deux clients différents. synchronized(this){} doit être appliquées aux traitements critiques comme les compteurs.

public class ... {
  public void method() {
    out = response.getWriter();
    synchronized(this) {
      compteur++;
    }
    out.println("La valeur du compteur est " + compteur);
  }
}