Configurer le descripteur de déploiement web.xml

Le fichier web.xml n'est utilisé que lors du déploiement d'une application Java dans un environnement d'exécution incluant le serveur Eclipse Jetty 9/servlet 3. Pour en savoir plus, consultez la page Environnement d'exécution Eclipse Jetty 9.3.

Les applications Web Java utilisent un fichier descripteur de déploiement pour définir la méthode de mappage des URL sur les servlets, déterminer les URL qui nécessitent une authentification ainsi que d'autres informations. Ce fichier s'appelle web.xml et se trouve dans le fichier d'archives WAR de l'application, sous le répertoire WEB-INF/. web.xml fait partie de la norme Servlet pour les applications Web.

Pour en savoir plus sur la norme web.xml, consultez le wiki de référence sur Metawerx web.xml et la spécification de servlet.

À propos des descripteurs de déploiement

Le descripteur de déploiement d'une application Web décrit les classes, les ressources et la configuration de l'application, ainsi que la manière dont le serveur Web les utilise pour diffuser des requêtes Web. Lorsque le serveur Web reçoit une requête pour une application, il se sert du descripteur de déploiement pour mapper l'URL de la requête sur le code destiné à traiter la requête.

Le descripteur de déploiement est un fichier appelé web.xml. Il se trouve dans le fichier d'archives WAR de l'application, sous le répertoire WEB-INF/. Il s'agit d'un fichier XML dont l'élément racine est <web-app>.

Voici un exemple simple de fichier web.xml qui mappe tous les chemins d'URL (/*) sur la classe de servlet mysite.server.ComingSoonServlet :

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <servlet>
        <servlet-name>comingsoon</servlet-name>
        <servlet-class>mysite.server.ComingSoonServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>comingsoon</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Servlets et chemins d'URL

Le fichier web.xml définit les mappages entre les chemins d'URL et les servlets qui traitent les requêtes avec ces chemins. Le serveur Web utilise cette configuration pour identifier le servlet devant traiter une requête donnée et pour appeler la méthode de classe qui correspond à la méthode de requête (par exemple, la méthode doGet() pour les requêtes HTTP GET).

Pour mapper une URL à un servlet, vous déclarez le servlet avec l'élément <servlet>, puis vous définissez un mappage à partir d'un chemin d'URL sur une déclaration de servlet avec l'élément <servlet-mapping>.

L'élément <servlet> déclare le servlet, y compris le nom utilisé pour faire référence au servlet via d'autres éléments du fichier, la classe utilisée avec le servlet et les paramètres d'initialisation. Il vous est possible de déclarer plusieurs servlets à l'aide de la même classe via des paramètres d'initialisation différents. Chaque nom de servlet doit être unique au sein du descripteur de déploiement.

    <servlet>
        <servlet-name>redteam</servlet-name>
        <servlet-class>mysite.server.TeamServlet</servlet-class>
        <init-param>
            <param-name>teamColor</param-name>
            <param-value>red</param-value>
        </init-param>
        <init-param>
            <param-name>bgColor</param-name>
            <param-value>#CC0000</param-value>
        </init-param>
    </servlet>

    <servlet>
        <servlet-name>blueteam</servlet-name>
        <servlet-class>mysite.server.TeamServlet</servlet-class>
        <init-param>
            <param-name>teamColor</param-name>
            <param-value>blue</param-value>
        </init-param>
        <init-param>
            <param-name>bgColor</param-name>
            <param-value>#0000CC</param-value>
        </init-param>
    </servlet>

L'élément <servlet-mapping> indique un format d'URL et le nom d'un servlet déclaré à utiliser avec les requêtes dont l'URL correspond au format. Un astérisque (*) peut être utilisé en début ou en fin de format d'URL pour remplacer un zéro ou plusieurs caractères. (La norme n'autorise pas les caractères génériques au milieu d'une chaîne, ni l'utilisation de plusieurs caractères génériques dans un même modèle.) Le format correspond au chemin complet de l'URL, commençant par la barre oblique (/) suivie du nom de domaine.

    <servlet-mapping>
        <servlet-name>redteam</servlet-name>
        <url-pattern>/red/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>blueteam</servlet-name>
        <url-pattern>/blue/*</url-pattern>
    </servlet-mapping>

Dans cet exemple, une requête pour l'URL http://www.example.com/blue/teamProfile est traitée par la classe TeamServlet, avec le paramètre teamColor égal à blue et le paramètre bgColor égal à #0000CC. Le servlet peut faire correspondre la portion du chemin de l'URL au caractère générique à l'aide de la méthode getPathInfo() de l'objet ServletRequest.

Le servlet peut accéder à ses paramètres d'initialisation en obtenant la configuration du servlet via sa propre méthode getServletConfig(), puis en appelant la méthode getInitParameter() sur l'objet de configuration via le nom du paramètre en tant qu'argument.

        String teamColor = getServletConfig().getInitParameter("teamColor");

Pages JSP

Une application peut utiliser des pages JSP pour implémenter des pages Web. Les JSP sont des servlets définis à l'aide de contenu statique (tel que HTML), combiné à du code Java.

App Engine est compatible avec la compilation automatique, ainsi que le mappage d'URL pour les JSP. Tout fichier JSP contenu dans le fichier d'archives WAR de l'application (en dehors de WEB-INF/) dont le nom de fichier se termine par .jsp est compilé automatiquement dans une classe de servlet et est mappé sur le chemin de l'URL qui correspond au chemin d'accès au fichier JSP dans la racine WAR. Par exemple, si une application possède un fichier JSP nommé start.jsp dans un sous-répertoire appelé register/ de son fichier d'archives WAR, App Engine le compile et le mappe au chemin de l'URL /register/start.jsp.

Si vous souhaitez exercer un contrôle plus rigoureux sur la manière dont la page JSP est mappée à l'URL, vous pouvez spécifier explicitement le mappage en le déclarant avec un élément <servlet> dans le descripteur de déploiement. Au lieu d'indiquer un élément <servlet-class>, vous spécifiez un élément <jsp-file> avec le chemin d'accès au fichier JSP à partir de la racine du fichier d'archives WAR. L'élément <servlet> du fichier JSP peut comporter des paramètres d'initialisation.

    <servlet>
        <servlet-name>register</servlet-name>
        <jsp-file>/register/start.jsp</jsp-file>
    </servlet>

    <servlet-mapping>
        <servlet-name>register</servlet-name>
        <url-pattern>/register/*</url-pattern>
    </servlet-mapping>

Remarque : L'élément <jsp-file> doit commencer par une barre oblique (/) si le fichier JSP se trouve dans le répertoire racine de l'application.

Vous pouvez installer des bibliothèques de balises JSP à l'aide de l'élément <taglib>. Une bibliothèque de balises comporte un chemin d'accès au fichier TLD (<taglib-location>) et un URI que les JSP utilisent pour sélectionner la bibliothèque à charger (<taglib-uri>). Notez qu'App Engine fournit la bibliothèque de balises standards des pages JavaServer (JSTL) et que vous n'avez pas besoin de l'installer.

    <taglib>
        <taglib-uri>/escape</taglib-uri>
        <taglib-location>/WEB-INF/escape-tags.tld</taglib-location>
    </taglib>

Liste des fichiers de bienvenue

Lorsque les URL de votre site représentent des chemins d'accès à des fichiers statiques ou à des JSP dans votre fichier d'archives WAR, il peut être judicieux que les chemins d'accès aux répertoires représentent également quelque chose. Par exemple, si un utilisateur accède au chemin de l'URL /help/accounts/password.jsp pour obtenir des informations sur les mots de passe du compte, il peut également accéder au chemin /help/accounts/ pour afficher une page présentant la documentation système sur les comptes. Le descripteur de déploiement permet de spécifier une liste de noms de fichiers que le serveur doit consulter lorsque l'utilisateur accède à un chemin qui correspond à un sous-répertoire du fichier d'archives WAR (qui n'est pas explicitement mappé sur un servlet). La norme de servlet l'appelle "liste des fichiers de bienvenue".

Par exemple, si l'utilisateur accède au chemin de l'URL /help/accounts/, l'élément <welcome-file-list> suivant du descripteur de déploiement demande au serveur de vérifier les fichiers help/accounts/index.jsp et help/accounts/index.html avant de signaler que l'URL n'existe pas :

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

Filtres

Un filtre est une classe qui agit sur une requête comme un servlet, mais qui permet de poursuivre le traitement de la requête avec d'autres filtres ou servlets. Un filtre peut exécuter une tâche secondaire telle que la connexion, en effectuant des vérifications d'authentification spéciales ou en annotant les objets de demande ou de réponse avant d'appeler le servlet. Les filtres vous permettent d'élaborer des tâches de traitement des réponses à partir du descripteur de déploiement.

Une classe de filtre met en œuvre l'interface javax.servlet.Filter, y compris la méthode doFilter(). Voici une simple mise en œuvre de filtre qui enregistre un message, puis transmet le contrôle à la chaîne qui peut inclure d'autres filtres ou un servlet, comme décrit dans le descripteur de déploiement :

package mysite.server;

import java.io.IOException;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class LogFilterImpl implements Filter {

    private FilterConfig filterConfig;
    private static final Logger log = Logger.getLogger(LogFilterImpl.class.getName());

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws IOException, ServletException {
        log.warning("Log filter processed a " + getFilterConfig().getInitParameter("logType")
            + " request");

        filterChain.doFilter(request, response);
    }

    public FilterConfig getFilterConfig() {
        return filterConfig;
    }

    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }

    public void destroy() {}

}

De la même manière que pour les servlets, vous configurez un filtre dans le descripteur de déploiement en déclarant le filtre avec l'élément <filter>, puis en le mappant à un format d'URL avec l'élément <filter-mapping>. Vous avez également la possibilité de mapper les filtres directement sur d'autres servlets.

L'élément <filter> comporte un élément <filter-name> et <filter-class>, ainsi que des éléments <init-param> facultatifs.

    <filter>
        <filter-name>logSpecial</filter-name>
        <filter-class>mysite.server.LogFilterImpl</filter-class>
        <init-param>
            <param-name>logType</param-name>
            <param-value>special</param-value>
        </init-param>
    </filter>

L'élément <filter-mapping> comporte un élément <filter-name> qui correspond au nom d'un filtre déclaré, et soit un élément <url-pattern> permettant d'appliquer le filtre aux URL, soit un élément <servlet-name> qui correspond au nom d'un servlet déclaré afin d'appliquer le filtre chaque fois que le servlet est appelé.

    <!-- Log for all URLs ending in ".special" -->
    <filter-mapping>
        <filter-name>logSpecial</filter-name>
        <url-pattern>*.special</url-pattern>
    </filter-mapping>

    <!-- Log for all URLs that use the "comingsoon" servlet -->
    <filter-mapping>
        <filter-name>logSpecial</filter-name>
        <servlet-name>comingsoon</servlet-name>
    </filter-mapping>

Remarque : Les filtres ne sont pas appelés sur les éléments statiques, même si le chemin correspond à un modèle filter-mapping. Les fichiers statiques sont diffusés directement dans le navigateur.

Gestionnaire d'erreurs

Grâce au descripteur de déploiement, vous pouvez personnaliser les données que le serveur envoie à l'utilisateur en cas d'erreur. Le serveur peut afficher une page de remplacement lorsqu'il est sur le point d'envoyer un code d'état HTTP particulier, ou lorsqu'un servlet génère une exception Java particulière.

L'élément <error-page> contient soit un élément <error-code> avec une valeur de code d'erreur HTTP (par exemple, 500), soit un élément <exception-type> avec le nom de classe de l'exception attendue (par exemple, java.io.IOException). Il contient également l'élément <location> contenant le chemin de l'URL de la ressource à afficher lorsque l'erreur se produit.

    <error-page>
        <error-code>500</error-code>
        <location>/errors/servererror.jsp</location>
    </error-page>

Remarque : Pour l'instant, il n'est pas possible de configurer des gestionnaires d'erreurs personnalisés pour certaines conditions d'erreur. En particulier, vous ne pouvez pas personnaliser la page de réponse 404 lorsqu'aucun mappage de servlet n'est défini pour une URL, ni la page d'erreur de quotas 403, ni la page d'erreur de serveur 500 qui apparaît suite à une erreur interne App Engine.

Fonctionnalités web.xml non compatibles

Les caractéristiques web.xml suivantes ne sont pas compatibles avec App Engine :

  • App Engine prend en charge l'élément <load-on-startup> pour les déclarations de servlet. Toutefois, la charge se produit lors de la première requête traitée par l'instance de serveur Web, et non avant.
  • Certains éléments de descripteur de déploiement peuvent avoir un nom d'affichage, une description et une icône interprétables par l'utilisateur sous des environnements de développement intégrés. App Engine ne tient pas compte de ces éléments.
  • App Engine n'accepte pas les variables d'environnement JNDI (<env-entry>).
  • App Engine n'accepte pas les ressources EJB (<resource-ref>).
  • La notification de la destruction de servlets, de contexte de servlet, ou de filtres n'est pas acceptée.
  • L'élément <distributable> n'est pas pris en compte.
  • La planification de servlet avec <run-at> n'est pas acceptée.
  • Les contraintes de sécurité ne sont pas acceptées. Pour des fonctionnalités équivalentes, consultez le tutoriel consacré à Bookshelf.
  • L'élément "CONFIDENTIAL" n'est pas accepté dans web.xml.