My favorites | Português | Sign in

O descritor de implementação: web.xml

Os aplicativos da web em Java usam um arquivo de descritor de implementação para determinar como os URLs mapeiam para os servlets, quais URLs precisam de autenticação e outras informações. Esse arquivo é chamado web.xml e reside no WAR do aplicativo no diretório WEB-INF/. web.xml é parte do padrão de servlet para aplicativos da web.

Para obter mais informações sobre o padrão web.xml, consulte a referência wiki do Metawerx sobre o web.xml, a referência ao elemento web.xml do WebLogic e a especificação do Servlet.

Sobre os descritores de implementação

O descritor de implementação de um aplicativo da web descreve as classes, os recursos e a configuração do aplicativo e como eles são utilizados pelo servidor da web para servir às solicitações da web. Quando o servidor da web recebe uma solicitação do aplicativo, ele usa o descritor de implementação para mapear o URL da solicitação para o código que irá manipulá-la.

O descritor de implementação é um arquivo chamado web.xml. Ele fica no WAR do aplicativo no diretório WEB-INF/. Ele é um arquivo XML cujo elemento raiz é <web-app>.

Veja abaixo um exemplo simples de web.xml que mapeia todos os caminhos de URL (/*) para a classe 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>

Servlets e caminhos de URL

web.xml define os mapeamentos entre os caminhos de URL e os servlets usam esses caminhos para manipular as solicitações. O servidor da web usa essa configuração para identificar o servlet que irá manipular uma determinada solicitação e chamar o método da classe que corresponde ao método de solicitação (por exemplo, o método doGet() para solicitações HTTP GET).

Para mapear um URL para um servlet, declare o servlet com o elemento <servlet> e, em seguida, defina o mapeamento de um caminho de URL para uma declaração de servlet com o elemento <servlet-mapping>.

O elemento <servlet> declara o servlet, incluindo um nome usado para se referir ao servlet por outros elementos no arquivo, a classe a ser usada para o servlet e os parâmetros de inicialização. É possível declarar vários servlets usando a mesma classe com parâmetros de inicialização diferentes. O nome de cada servlet deve ser exclusivo no descritor de implementação.

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

O elemento <servlet-mapping> especifica um padrão de URL e o nome de um servlet declarado a ser usado para solicitações cujo URL corresponde ao padrão. O padrão de URL pode ter um asterisco (*) no começo ou no final do padrão para indicar zero ou mais de um caractere (o padrão não suporta curingas no meio de uma string e não permite vários curingas em um padrão). O padrão corresponde ao caminho completo do URL, começando com e incluindo a barra / seguida do nome do domínio.

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

Nesse exemplo, uma solicitação de um URL http://www.example.com/blue/teamProfile é manipulada pela classe TeamServlet, com o parâmetro teamColor igual a blue e o parâmetro bgColor igual a #0000CC. O servlet pode obter a parte do caminho de URL correspondente ao curinga usando o método getPathInfo() do objeto ServletRequest.

Observação: Arquivos estáticos, arquivos que são servidos aos usuários sem modificações, como imagens, CSS ou JavaScript, são manipulados separadamente a partir dos caminhos mencionados no descritor de implementação. Uma solicitação de um caminho de URL que corresponde ao caminho para um arquivo no WAR que é considerado estático servirá o arquivo, independentemente dos mapeamentos do servlet e do filtro no descritor de implementação. Você pode excluir os arquivos daqueles tratados como arquivos estáticos usando o arquivo appengine-web.xml.

O servlet pode acessar os seus parâmetros de inicialização ao obter as configurações do servlet por meio do seu próprio método getServletConfig(), chamando em seguida o método getInitParameter() no objeto de configuração usando o nome do parâmetro como um argumento.

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

JSPs

Um aplicativo pode usar as JSPs (JavaServer Pages) para implementar páginas web. As JSPs são servlets definidas usando uma mistura de conteúdo estático (como HTML) e código Java.

O Google App Engine suporta a compilação automática e o mapeamento de URL para as JSPs. Um arquivo JSP no WAR do aplicativo (fora do WEB-INF/) cujo nome de arquivo termina em .jsp é compilado automaticamente em uma classe de servlet e mapeado para o caminho de URL equivalente ao caminho para o arquivo JSP da raiz do WAR. Por exemplo, se um aplicativo tem um arquivo JSP chamado start.jsp em um subdiretório register/ do WAR, o Google App Engine o compila e o mapeia para o caminho de URL /register/start.jsp.

Se você quiser mais controle sobre o mapeamento da JSP para um URL, é possível especificar o mapeamento explicitamente ao declará-lo com um elemento <servlet> no descritor de implementação. Em vez de um elemento <servlet-class>, especifique um elemento <jsp-file> com o caminho para o arquivo JSP a partir da raiz do WAR. O elemento <servlet> da JSP pode conter parâmetros de inicialização.

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

É possível instalar as bibliotecas de tags da JSP com o elemento <taglib>. A biblioteca de tags possui um caminho para o arquivo <taglib-location> da TLD (Descritor da biblioteca de tags) da JSP e um URI que as JSPs usam para selecionar a biblioteca a ser carregada (<taglib-uri>). Observe que o Google App Engine oferece a JSTL (Biblioteca padrão de tags JavaServer Pages) e não é necessário instalá-la.

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

Segurança e autenticação

Um aplicativo do Google App Engine pode usar as Contas do Google para autenticar o usuário. Ele pode usar a API das Contas do Google para detectar se o usuário fez login, para obter o endereço de e-mail do usuário conectado no momento e para gerar URLs de entrada e saída. Um aplicativo também pode especificar as restrições de acesso para caminhos de URL com base nas Contas do Google usando o descritor de implementação.

O elemento <security-constraint> define uma restrição de segurança para URLs que correspondem a um padrão. Se o usuário não fez login e tentar acessar um URL cujo caminho tem uma restrição de segurança, o Google App Engine redireciona o usuário para a página de login das Contas do Google. As Contas do Google redirecionam o usuário para o URL do aplicativo depois de ele ter feito login ou se inscrito em uma conta nova. O aplicativo não precisa fazer mais nada para garantir que apenas os usuários que fizeram login acessem o URL.

Uma restrição de segurança inclui uma restrição de autorização que especifica quais usuários das Contas do Google podem acessar o caminho. Se a restrição de autorização especificar ao usuário um papel de *, todos os usuários que fizeram login nas Contas do Google poderão acessar o URL. Se a restrição especificar ao usuário um papel de admin, somente os desenvolvedores registrados (administradores) do aplicativo poderão acessar o URL. O papel admin facilita a criação de seções do seu site exclusivas para os administradores.

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

O Google App Engine não suporta papéis de segurança personalizados (<security-role>) ou mecanismos de autenticação alternativos (<login-config>) no descritor de implementação.

As restrições de segurança se aplicam aos arquivos estáticos e aos servlets.

URLs seguros

O Google App Engine suporta conexões seguras por meio do HTTPS para URLs com o domínio *.appspot.com. Quando uma solicitação acessa um URL usando HTTPS, os dados da solicitação e os dados da resposta são criptografados pelo remetente antes da transmissão, e são descriptografados pelo destinatário após o recebimento. As conexões seguras são úteis para proteger os dados do cliente, como informações de contato, senhas e mensagens particulares.

Observação: Os domínios do Google Apps não suportam HTTPS no momento. O suporte ao HTTPS está limitado aos aplicativos acessados por meio dos domínios *.appspot.com. Acessar um URL HTTPS em um domínio do Google Apps retornará o erro "host não encontrado". Acessar um URL cujo manipulador aceita apenas HTTPS (veja abaixo) usando HTTP retornará o erro 403 de HTTP "Forbidden" (Proibido). Você pode vincular um URL HTTPS ao domínio *.appspot.com para recursos de segurança e usar o domínio do Google Apps e o HTTP para o restante do site.

Antes de usar os URLs seguros de um aplicativo, ative os URLs seguros no arquivo appengine-web.xml do aplicativo usando o elemento <ssl-enabeld>true</ssl-enabled>. Consulte Configuração do aplicativo: como ativar URLs seguros para obter mais informações sobre esse arquivo.

Para declarar que o HTTPS deve ser usado para um URL, configure uma restrição de segurança no descritor de implementação (como descrito em Segurança e autenticação com um <user-data-constraint> cujo <transport-guarantee> seja CONFIDENTIAL, conforme mostrado a seguir:

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

As solicitações que usam HTTP (não seguras) para URLs cuja garantia de transporte seja CONFIDENTIAL são redirecionadas automaticamente para o mesmo URL usando HTTPS.

As conexões seguras usam mais CPU e largura de banda do que as conexões não seguras e são, portanto, mais caras. As conexões seguras também são mais lentas do que as não seguras.

Qualquer URL pode usar a garantia de transporte CONFIDENTIAL, incluindo JSPs e arquivos estáticos.

O servidor da web para desenvolvimento não suporta conexões HTTPS. Ele ignora a garantia de transporte e, portanto, os caminhos voltados para o uso com HTTPS podem ser testados usando conexões HTTP normais para o servidor da web para desenvolvimento.

Quando você testar os manipuladores HTTPS do seu aplicativo usando o URL do appspot.com da versão, como https://1.latest.app-id.appspot.com/, o seu navegador avisará que o certificado HTTPS não foi assinado para o caminho de domínio especificado. Se você aceitar o certificado para aquele domínio, as paginas carregarão corretamente. Os usuários não verão o aviso do certificado quando acessarem https://app-id.appspot.com/.

A entrada e saída das Contas do Google são sempre feitas usando uma conexão segura, sem relação com a maneira pela qual os URLs do aplicativo são configurados.

Como mencionado acima, as restrições de segurança se aplicam aos arquivos estáticos e aos servlets. Isso inclui a garantia de transporte.

A lista do arquivo de boas-vindas

Quando os URLs do seu site representam caminhos para arquivos estáticos ou JSPs no seu WAR, é sempre bom que os caminhos para os diretórios também façam algo útil. Um usuário que visita o caminho de URL /help/accounts/password.jsp para obter informações sobre as senhas da conta pode experimentar visitar /help/accounts/ para encontrar uma página com a documentação do sistema de contas. O descritor de implementação pode especificar uma lista de nomes de arquivos que o servidor deve experimentar quando o usuário acessar um caminho que representa um subdiretório WAR (que ainda não está mapeado explicitamente para um servlet). O padrão do servlet chama isso de "lista do arquivo de boas-vindas".

Por exemplo, se o usuário acessar o caminho de URL /help/accounts/, o seguinte elemento <welcome-file-list> no descritor de implementação fala para o servidor verificar help/accounts/index.jsp e help/accounts/index.html antes de informar que o URL não existe:

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

Filtros

Um filtro é uma classe que atua em uma solicitação como um servlet, mas que pode permitir que a manipulação da solicitação continue com outros filtros ou servlets. Um filtro pode realizar uma tarefa auxiliar como registrar, realizar verificações de autenticação especializadas ou anotar os objetos da solicitação ou da resposta antes de chamar o servlet. Os filtros permitem compor tarefas de processamento de solicitação a partir do descritor de implementação.

Uma classe de filtro implementa a interface javax.servlet.Filter, incluindo o método doFilter(). Veja abaixo uma implementação de filtro simples que registra uma mensagem e passa o controle para a cadeia, que pode incluir outros filtros ou um servlet, como descrito pelo descritor de implementação:

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

Como acontece com os servlets, você pode configurar um filtro no descritor de implementação ao declará-lo com o elemento <filter> e mapeá-lo para um padrão de URL com o elemento <filter-mapping>. Os filtros também podem ser mapeados diretamente para outros servlets.

O elemento <filter> contém um <filter-name>, um <filter-class> e elementos <init-param> opcionais.

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

O elemento <filter-mapping> contém um <filter-name>, que corresponde ao nome de um filtro declarado, um elemento <url-pattern>, para aplicar o filtro aos URLs, ou um elemento <servlet-name>, que corresponde ao nome de um servlet declarado para aplicar o filtro sempre que o servlet for chamado.

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

Manipuladores de erro

É possível personalizar o que o servidor envia para o usuário quando ocorre um erro, usando o descritor de implementação. O servidor pode exibir um local alternativo para a página quando for enviar um código de status HTTP particular ou quando um servlet emite uma exceção Java particular.

O elemento <error-page> contém um elemento <error-code> com um valor do código de erro HTTP (como 500) ou um elemento <exception-type> com o nome da classe da exceção esperada (como java.io.IOException). Ele também contém um elemento <location> com o caminho de URL do recurso para mostrar quando o erro ocorre.

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

Observação: Até o momento da redação deste artigo, não é possível configurar manipuladores de erro personalizados para algumas condições de erro. Especificamente, não é possível personalizar o código de resposta 404 quando não houver um mapeamento de servlet definido para um URL e, em seguida, a página de erro de cota 403 ou um erro de servidor 500 causado por um erro interno do Google App Engine.

Recursos do web.xml não suportados

O Google App Engine suporta o elemento <load-on-startup> para declarações do servlet. No entanto, o carregamento ocorre de fato durante a primeira solicitação manipulada pela instância do servidor da web, e não antes dela.

O Google App Engine suporta os elementos <mime-mapping> para especificar o tipo MIME a ser usado para recursos cujos nomes de arquivo terminem com determinadas extensões. No entanto, os mapeamentos MIME se aplicam apenas aos servlets, e não aos arquivos estáticos. Os arquivos estáticos usam uma lista fixa de mapeamentos de extensões de nome de arquivo para tipos MIME.

Alguns elementos do descritor de implementação podem levar um nome, uma descrição e ícones de exibição legíveis para uso nas IDEs. O Google App Engine não as utiliza e as ignora.

O Google App Engine não suporta variáveis de ambiente JNDI (<env-entry>).

O Google App Engine não suporta recursos EJB (<resource-ref>).

O elemento <distributable> é ignorado.

A programação do servlet com <run-at> não é suportada.