Mis favoritos | Español | Acceder

El descriptor de implementación: web.xml

Las aplicaciones web Java utilizan un archivo de descriptor de implementación para determinar la forma en que las URL realizan asignaciones para los servlets, qué URL necesita autenticación, entre otra información. Este archivo se llama web.xml y se ubica en el WAR de la aplicación en el directorio WEB-INF/. web.xml forma parte del estándar de servlet para aplicaciones web.

Para obtener más información sobre el estándar web.xml, consulta la wiki de referencia de web.xml de Metawerx, la referencia del elemento web.xml de WebLogic y la especificación del servlet.

Acerca de los descriptores de implementación

Un descriptor de implementación de aplicación web describe las clases, los recursos y la configuración de la aplicación y cómo los utiliza el servidor web para suministrar las solicitudes web. Cuando el servidor web recibe una solicitud para la aplicación, utiliza el descriptor de implementación para asignar la URL de la solicitud al código que debe controlarla.

El descriptor de implementación es un archivo denominado web.xml. Se ubica en el WAR de la aplicación en el directorio WEB-INF/. Se trata de un archivo XML cuyo elemento raíz es <web-app>.

A continuación se indica un sencillo ejemplo de web.xml que asigna todas las rutas de las URL (/*) a la clase de servlet mysite.server.ComingSoonServlet:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <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>

Rutas de URL y servlets

web.xml define las asignaciones entre las rutas de URL y los servlets que controlan las solicitudes con estas rutas. El servidor web utiliza esta configuración para identificar el servlet que controla una solicitud concreta y ejecuta el método de clase que corresponde al método de solicitud (por ejemplo, el método doGet() para solicitudes GET HTTP).

Para asignar una URL a un servlet, declara el servlet con el elemento <servlet>, a continuación, define una asignación desde una ruta de URL hasta una declaración de servlet con el elemento <servlet-mapping>.

El elemento <servlet> declara el servlet, incluido un nombre utilizado para hacer referencia al servlet por parte de otros elementos del archivo, la clase que se va a utilizar para el servlet y los parámetros de inicialización. Puedes declarar varios servlets con la misma clase y diferentes parámetros de inicialización. El nombre de cada servlet debe ser único en todo el descriptor de implementación.

    <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>

El elemento <servlet-mapping> especifica un patrón URL y el nombre de un servlet declarado que se va a utilizar para las solicitudes cuya URL corresponde al patrón. El patrón URL puede utilizar un asterisco (*) al principio o al final del patrón para indicar cero o más caracteres. (El estándar no admite comodines en mitad de una cadena y no permite varios comodines en un patrón). El patrón corresponde a la ruta completa de la URL, empezando con e incluyendo la barra inclinada (/), seguida del nombre de dominio.

    <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>

Según este ejemplo, una solicitud de la URL http://www.example.com/blue/teamProfile se controla a través de la clase TeamServlet, con el parámetro teamColor igual a blue y el parámetro bgColor igual a #0000CC. El servlet puede obtener la parte de la ruta de la URL que corresponde al comodín a través del método getPathInfo() del objeto ServletRequest.

Nota: los archivos estáticos, los archivos que se suministran textualmente a los usuarios como, por ejemplo, imágenes, CSS o JavaScript, se controlan de forma independiente desde las rutas mencionadas en el descriptor de implementación. Una solicitud para una ruta de URL que se corresponda con una ruta de un archivo del WAR que se considere un archivo estático suministrará el archivo, independientemente de las asignaciones del servlet y del filtro en el descriptor de implementación. Puedes excluir archivos de entre los tratados como archivos estáticos con el archivo appengine-web.xml.

El servlet puede acceder a sus parámetros de inicialización si obtiene su configuración de servlet a través de su propio método getServletConfig() y, si ejecuta a continuación el método getInitParameter() en el objeto de configuración utilizando el nombre del parámetro como un argumento.

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

Páginas JSP

Una aplicación puede utilizar JavaServer Pages (JSP) para implementar páginas web. Las páginas JSP son servlets definidos a través de contenido estático (por ejemplo, HTML) mezclado con código Java.

App Engine admite la compilación automática y la asignación de URL a páginas JSP. Un archivo JSP del WAR de la aplicación (independiente de WEB-INF/), cuyo nombre de archivo termina en .jsp se compila automáticamente en una clase de servlet y se asigna a la ruta de URL equivalente a la ruta del archivo JSP desde la raíz del WAR. Por ejemplo, si una aplicación tiene un archivo JSP llamado start.jsp en un subdirectorio llamado register/ de su WAR, App Engine lo compilará y lo asignará a la ruta de URL /register/start.jsp.

Si deseas ejercer mayor control sobre la forma en que la página JSP se asigna a una URL, puedes especificar la asignación de forma específica si la declaras con un elemento <servlet> en el descriptor de implementación. En lugar de un elemento <servlet-class>, especifica un elemento <jsp-file> con la ruta del archivo JSP desde la raíz del WAR. El elemento <servlet> del JSP puede contener parámetros de inicialización.

    <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>

Puedes instalar bibliotecas de etiquetas JSP con el elemento <taglib>. Una biblioteca de etiquetas tiene una ruta al archivo TLD (descriptor de biblioteca de etiquetas) JSP (<taglib-location>) y un URI que las páginas JSP utilizan para seleccionar la biblioteca para cargar (<taglib-uri>). Ten en cuenta que App Engine suministra la biblioteca JavaServer Pages Standard Tag Library (JSTL) y no necesitas instalarla.

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

Autenticación y seguridad

Una aplicación App Engine puede utilizar Cuentas de Google para la autenticación de usuario. La aplicación puede utilizar el API de Cuentas de Google para detectar el usuario actual, obtener la dirección de correo electrónico del usuario actual y generar una URL de acceso y de salida. Una aplicación también puede especificar restricciones en el acceso para rutas de URL según el servicio Cuentas de Google, a través del descriptor de implementación.

El elemento <security-constraint> define una restricción de seguridad para las URL que se corresponden con un patrón. Si un usuario accede a una URL cuya ruta tiene una restricción de seguridad y el usuario no ha accedido, App Engine redirigirá al usuario a la página de acceso del servicio de Cuentas de Google. El servicio de Cuentas de Google redirige al usuario de vuelta la URL de la aplicación tras haber accedido correctamente o haber registrado una cuenta nueva. La aplicación únicamente tiene que garantizar que sólo los usuarios actualmente registrados puedan acceder a la URL.

Una restricción de seguridad incluye una restricción de autorización que especifica los usuarios del servicio de Cuentas de Google que pueden acceder a la ruta. Si la restricción de autorización especifica una función de usuario *, en ese caso, todos los usuarios que accedan al servicio de Cuentas de Google podrán acceder a la URL. Si la restricción especifica una función de usuario admin, en ese caso, sólo los desarrolladores registrados (administradores) de la aplicación podrán acceder a la URL. La función admin facilita la creación de secciones exclusivas del administrador en tu sitio.

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/profile/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>*</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

App Engine no admite funciones de seguridad personalizadas (<security-role>) ni cambios en los mecanismos de autenticación (<login-config>) en el descriptor de implementación.

Las restricciones de seguridad se aplican tanto a los archivos estáticos como a los servlets.

URL seguras

Google App Engine admite conexiones seguras a través de HTTPS para las URL que utilizan el dominio *.appspot.com. Cuando una solicitud accede a una URL a través de HTTPS, el remitente encripta tanto los datos solicitados como los datos de respuesta antes de transmitirlos y el destinatario los desencripta tras recibirlos. Las conexiones seguras resultan útiles para proteger los datos del cliente como, por ejemplo, la información de contacto, las contraseñas y los mensajes privados.

Nota: los dominios de Google Apps actualmente no admiten HTTPS. La compatibilidad de HTTPS se limita a las aplicaciones a las que se accede a través de dominios *.appspot.com. El acceso a una URL HTTPS de un dominio de Google Apps devuelve un mensaje de error que indica que no se ha encontrado el host y el acceso a una URL cuyo controlador sólo acepta HTTPS (consulta la información que aparece a continuación) a través de HTTP devuelve un mensaje de error HTTP 403 que indica acceso prohibido. Puedes crear un enlace a una URL HTTPS con el dominio *.appspot.com para funciones seguras y utilizar el dominio de Apps y HTTP para el resto del sitio.

Antes de que puedas utilizar URL seguras para una aplicación, debes habilitar las URL seguras en el archivo appengine-web.xml de la aplicación a través del elemento <ssl-enabeld>true</ssl-enabled>. Consulta Configuración de aplicaciones: habilitación de URL seguras para obtener más información sobre este archivo.

Para declarar que se debe utilizar HTTPS para una URL, establece una restricción de seguridad en el descriptor de implementación (tal como se describe en la sección Seguridad y autenticación) con un elemento <user-data-constraint> donde <transport-guarantee> sea CONFIDENTIAL, del modo que se indica a continuación:

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/profile/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

Las solicitudes que utilizan HTTP (no seguras) para direcciones URL cuya garantía de transporte sea CONFIDENTIAL se redirigirán de forma automática a la misma URL a través de HTTPS.

Las conexiones seguras emplean más CPU y banda ancha que las conexiones no seguras y son, por tanto, más caras. Las conexiones seguras son también más lentas que las conexiones no seguras.

Cualquier URL puede utilizar la garantía de transporte CONFIDENTIAL, incluidos los archivos estáticos y JSP.

El servidor web de desarrollo no admite conexiones HTTPS. Por tanto ignora la garantía de transporte, de modo que las rutas que deberían utilizar HTTPS se pueden comprobar a través de conexiones HTTP regulares al servidor web de desarrollo.

Cuando compruebes los controladores HTTPS de tu aplicación a través de la versión de la URL appspot.com como, por ejemplo, https://1.latest.app-id.appspot.com/, tu navegador te advertirá de que el certificado HTTPS no se ha establecido para esta ruta de dominio específica. Si aceptas el certificado para este dominio, las páginas se cargarán correctamente. Los usuarios no verán la advertencia del certificado cuando accedan a https://app-id.appspot.com/.

El servicio de acceso y salida de Cuentas de Google utiliza siempre una conexión segura, sin relación con la forma en que se configuran las URL de la aplicación.

Como se ha indicado anteriormente, las restricciones de seguridad se aplican tanto a los archivos estáticos como a los servlets. Esto incluye la garantía de transporte.

La lista de archivos bienvenidos

Cuando las URL de tu sitio representan rutas para archivos estáticos o JSP de tu WAR, a menudo es buena idea hacer algo útil también con las rutas de los directorios. Un usuario que visita la ruta de URL /help/accounts/password.jsp para obtener información sobre las contraseñas de las cuentas, puede intentar visitar /help/accounts/ para buscar una página que proporcione una introducción a la documentación del sistema de cuentas. El descriptor de implementación puede especificar una lista de nombres de archivo que el servidor debe probar cuando el usuario acceda a una ruta que represente un subdirectorio del WAR (que aún no se ha asignado a un servlet de forma explícita). El estándar de servlet denomina esto la "lista de archivos de bienvenida".

Por ejemplo, si el usuario accede a la ruta de URL /help/accounts/, el siguiente elemento <welcome-file-list> del descriptor de implementación indicará al servidor que compruebe help/accounts/index.jsp y help/accounts/index.html antes de informar de que la URL no existe:

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

Filtros

Un filtro es una clase que actúa con una solicitud como lo hace un servlet, pero debe permitir la gestión de la solicitud para continuar con otros filtros o servlets. Un filtro puede realizar una tarea auxiliar como, por ejemplo el inicio de sesión, la realización de comprobaciones de autenticación especializadas o la anotación de la solicitud o de los objetos de respuesta antes de ejecutar el servlet. Los filtros te permiten redactar tareas de procesamiento de solicitud desde el descriptor de implementación.

Una clase de filtro implementa la interfaz javax.servlet.Filter, incluido el método doFilter(). A continuación se indica una sencilla implementación de filtro que registra un mensaje y transmite el control a la cadena, que puede incluir otros filtros o un servlet, tal como describe el descriptor de implementación:

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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

    public void doFilter(HttpServletRequest request,
                         HttpServletResponse response,
                         FilterChain filterChain)
            throws IOException, ServletException {
        log.info("Log filter processed a " +
                 getServletConfig().getInitParameter("logType") +
                 " request");

        filterConfig.doFilter(request, response);
    }

    public FilterConfig getFilterConfig() {
        return filterConfig;
    }
    public void setFilterConfig(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }
}

Al igual que los servlets, un filtro se configura en el descriptor de implementación mediante la declaración del filtro con el elemento <filter> y, a continuación, a través de su asignación a un patrón de URL con el elemento <filter-mapping>. También puedes asignar los filtros a otros servlets de forma directa.

El elemento <filter> contiene un elemento <filter-name>, un elemento <filter-class> y el elemento opcional <init-param>.

    <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>

El elemento <filter-mapping> contiene un elemento <filter-name> que se corresponde con el nombre de un filtro declarado y también un elemento <url-pattern> para aplicar el filtro a las URL o un elemento <servlet-name> que se corresponde con el nombre de un servlet declarado y que permite aplicar el filtro siempre que se ejecute el servlet.

    <!-- 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>

Controladores de error

Puedes personalizar lo que el servidor envía al usuario cuando se produce un error, por medio del descriptor de implementación. El servidor puede mostrar una ubicación de página alternativa cuando se trata de enviar un código de estado HTTP concreto o cuando un servlet genera una excepción Java concreta.

El elemento <error-page> contiene tanto un elemento <error-code> con un valor de código de error HTTP (como por ejemplo 500) o un elemento <exception-type> con el nombre de clase de la excepción prevista (como por ejemplo java.io.IOException). También contiene un elemento <location> que contiene a su vez la ruta de URL del recurso que se va a mostrar cuando se produzca el error.

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

Nota: por el momento, no puedes configurar controladores de error personalizados para algunos estados de error. En concreto, no puedes personalizar el código de respuesta 404 si no se ha establecido una asignación del servlet para una URL, la página de error de cuota 403 ni un error del servidor 500 causado por un error interno de App Engine.

Funciones de web.xml no admitidas

App Engine admite el elemento <load-on-startup> para declaraciones de servlet. No obstante, la carga se produce actualmente durante la primera solicitud controlada por la instancia del servidor web, no antes.

App Engine admite elementos <mime-mapping> para especificar el tipo MIME que se va a utilizar para los recursos cuyos nombres de archivo terminen en determinadas extensiones. No obstante, las asignaciones MIME sólo se aplican a los servlets y no a los archivos estáticos. Los archivos estáticos utilizan una lista de asignaciones de extensiones de nombre de archivo para los tipos MIME.

Algunos elementos del descriptor de implementación pueden disponer de un nombre de visualización, una descripción y un icono interpretables por humanos para su uso en entornos de desarrollo integrados (IDE). App Engine no los usa y, por tanto, los ignora.

App Engine no admite las variables de entorno JNDI (<env-entry>).

App Engine no admite los recursos EJB (<resource-ref>).

El elemento <distributable> se ignora.

No se admite el servlet programado con <run-at>.