Esse artigo faz parte da revista Java Magazine edição 20. Clique aqui para ler todos os artigos desta edição

jm20_capa.jpg

Clique aqui para ler esse artigo em PDF.imagem_pdf.jpg

Servlets no Tomcat 5

Aplicações Web MVC em Java

Aprenda como a tecnologia original do Java na web pode somar ao JSP e ao JSTL para construir aplicações complexas

Esta é a terceira parte de uma série que apresenta os fundamentos do desenvolvimento de aplicações web em Java, utilizando como plataforma o Tomcat 5.0.x. Na primeira parte, vimos como instalar e administrar o Tomcat, e aprendemos os fundamentos do JSP 2.0. Na segunda, vimos como utilizar o JSTL para simplificar a codificação de páginas JSP e facilitar a interação entre programadores e web designers. Agora veremos como utilizar a tecnologia de Servlets, e como ela pode somar às tecnologias vistas nas duas primeiras partes, no que se tornou conhecido como Arquitetura Modelo 2 (Model 2) para desenvolvimento web em Java, ou Arquitetura MVC.

Ao contrário dos primeiros artigos desta série, em que as tecnologias apresentadas foram explicadas desde o básico, não serão mostrados os fundamentos de servlets. Isto porque, ao mesmo tempo em que foi iniciada esta série, na Edição 18, começou-se também uma seqüência de artigos de Felipe Leme (na coluna "Pente Fino"), que cobre desde os conceitos essenciais até recursos avançados dessa API. Assim, é recomendável consultar a primeira parte da série sobre servlets como complemento a este artigo.

Definindo servlets

HttpServlets (ou simplesmente "servlets") são classes Java criadas para funcionar dentro de um servidor/container web, assim como Applets são classes Java criadas para funcionar dentro de um navegador web. Portanto, servlets não são aplicações independentes; eles dependem do servidor web para funcionar. É o servidor quem decide em que momento criar uma nova instância de HttpServlet e quando executar seu código.

É comum que o iniciante tenha problemas para rodar seu primeiro servlet. Ou ele/ela encontra dificuldades na compilação da classe (que exige APIs não presentes no J2SE, sendo esta para muitos a primeira vez que se configura o classpath), ou se complica na execução e atualização da aplicação (muitos containers não recarregam aplicações web depois que suas classes são recompiladas). Por isso iniciamos com um exemplo básico, que ensina como realizar o ciclo de edição-compilação-deployment-execução no Tomcat 5, utilizando a linha de comando do sistema operacional e o JSDK.

Usuários de IDEs como o Eclipse e o NetBeans também podem ter dificuldades por causa do funcionamento do processo de deployment e configuração de recursos como conexões a bancos de dados. Não é o foco desta série tratar destas questões, mas o leitor poderá encontrar informações valiosas em outro artigo desta edição, “Cadastro em Passos com Struts”, que em um quadro apresenta particularidades da configuração de aplicações no Tomcat 5.

Primeiro servlet

Um servlet básico está na Listagem 1. Ele apenas retorna uma página HTML simples, contendo a data e a hora atuais. Foi escrito para responder a uma requisição HTTP GET, por isso implementa o método doGet(). Os argumentos deste método são justamente a requisição e a resposta. Qualquer informação que seja necessária para gerar a resposta deve ser obtida por meio da requisição, e qualquer que seja a resposta, ela deve ser entregue a métodos do objeto de resposta.

Para rodar o servlet é necessário que ele seja mapeado para uma URL, o que é feito no descritor web (o arquivo WEB-INF/web.xml). A Listagem 2 apresenta o descritor para a execução do servlet básico.

O descritor e o servlet devem ser colocados em um pacote WAR para execução pelo container web (no nosso caso o Tomcat 5.0.x – veja o quadro “Atualizar ou não para o Tomcat 5.5.x?”). Já vimos na primeira parte que os bytecodes de classes JavaBeans em um pacote WAR devem ser colocados sob a pasta WEB-INF/classes; servlets são tratados da mesma forma, assim como qualquer outro tipo de classe que você desenvolva como parte de sua aplicação web. Dessa maneira, nosso pacote WAR até o momento deve conter a estrutura apresentada na Figura 1.

A pasta javamagazine-servlets, que é a raiz da estrutura do pacote WAR apresentada na figura, deve ser criada dentro da pasta webapps do Tomcat 5, como foi feito nos artigos anteriores desta série.

 

Atualizar ou não para o Tomcat 5.5.x?

Enquanto este artigo estava sendo escrito, foi anunciada a primeira versão estável do Tomcat 5.5.x, a versão 5.5.4. Entretanto, não recomendo aos leitores um upgrade imediato para esta versão; sugiro que permaneçam com a série 5.0.x (5.0.28), que é a recomendada pela própria Apache Software Foundation para desenvolvimento voltado para Servlets 2.4 e JSP 2.0. O motivo são mudanças profundas no código do Tomcat 5.5 em relação a versões anteriores, utilizando (e exigindo) o Java 5. Mesmo com uma versão estável, ainda irá levar algum tempo até que o novo Tomcat e a nova VM amadureçam para uso em missão crítica, e para que IDEs e bibliotecas de terceiros sejam atualizados para o novo padrão.

Compilando o servlet

Para compilar o servlet, é necessário acrescentar as classes da API de Servlets ao classpath do sistema operacional (aqui estamos supondo que todas as operações são realizadas no prompt do sistema, e não em um IDE). Essas classes não são parte do JSDK, mas podem ser encontradas na pasta common/lib/servlet-api.jar na sua instalação do Tomcat 5. Então, supondo que seu ambiente já esteja preparado para execução do javac na linha de comando, bastará executar algo como:

 

export CLASSPATH=$CLASSPATH:$TOMCAT_HOME/common/lib/servlet-api.jar

 

O comando anterior funcionará no Linux. No Windows, o comando seria:

 

set CLASSPATH=%CLASSPATH%:%TOMCAT_HOME%\common\lib\servlet-api.jar

 

Substitua a variável de ambiente TOMCAT_HOME pelo diretório onde o Tomcat 5 foi instalado em seu computador (ou então defina a variável com o valor correspondente). Para compilar o servlet tenha certeza de que o diretório corrente seja a pasta WEB-INF/classes da nossa aplicação, e execute o comando (no Linux):

 

javac javamagazine/ServletBasico.java

 

Ou então, no Windows:

 

javac javamagazine\ServletBasico.java

 

Agora podemos iniciar o Tomcat 5 utilizando o script startup.sh (ou startup.bat), da mesma forma que fizemos nos artigos anteriores.

Para executar a aplicação, peça pela URL http://127.0.0.1:8080/javamagazine/servletbasico. O resultado deverá ser como o mostrado na Figura 2.

Se algo sair errado

Caso você não consiga ver a página apresentada na Figura 2, verifique se o erro ocorreu no processamento do descritor web.xml (durante o deployment da aplicação); ou se ele aconteceu na  compilação do servlet. No primeiro caso, o erro só será percebido quando o Tomcat for iniciado (aparecerão mensagens de erro no arquivo logs/catalina.out do servidor). No segundo, o erro será reportado imediatamente pela execução do comando javac.

Em ambas as situações deve-se verificar, por meio da aplicação Manager do Tomcat, se o contexto foi ativado ou não. A Figura 3 apresenta um exemplo de como deve ser a saída da aplicação com o contexto ativado. Observe a coluna “Running” exibindo o valor “True”.

Caso o valor não seja “True”, a aplicação não teve o seu deployment realizado com sucesso. Corrija o arquivo web.xml e clique no link Start para refazer o deployment da aplicação. Depois carregue novamente a URL para executar o servlet.

E se segundo o Manager a aplicação estiver rodando, mas mesmo assim o servlet não funcionar corretamente? Neste caso, você pode ter cometido um erro no mapeamento do servlet (verifique o elemento url-pattern no web.xml); ou um erro de compilação no servlet pode ter passado desapercebido. Corrija o servlet (e o recompile), ou corrija o descritor web.xml e então clique no link Reload no Manager para que as mudanças se tornem visíveis. Então recarregue o contexto usando o Manager.

Separando lógica e formatação

Embora seja possível desenvolver aplicações complexas utilizando apenas classes que estendem HttpServlet, esta não é a forma mais eficiente de se construir uma aplicação web para o J2EE 1.4 (ou mesmo para a versão 1.3 dessa especificação). Apenas com essa técnica, será bem difícil interagir com um web designer, pois ele provavelmente não sabe como escrever e compilar classes Java. E não será nada eficiente ter um programador sempre copiando o código HTML que o designer alterou com um editor especializado para dentro do código do servlet.

 O que se costuma fazer hoje é processar os dados da requisição no servlet e depois repassar a requisição para que uma página JSP providencie a formatação dos resultados. Os resultados são inseridos na requisição como atributos, o que é equivalente a utilizar numa página JSP o tag com scope="request", como visto na primeira parte desta série (Edição 18). Para fazer o repasse, utiliza-se o método getRequestDispatcher() do objeto request.

As facilidades fornecidas pela tecnologia JSP nos permitem criar aplicações web mais agradáveis. Não é uma boa prática de usabilidade criar uma aplicação com muitas pequenas páginas; boas aplicações web reduzem a quantidade de páginas diferentes pelas quais o usuário tem que navegar, inserindo mais informações nas mesmas páginas e links diretos para páginas relacionadas.

Embora seja possível endereçar tanto servlets quanto páginas JSP por meio de URLs, é conveniente centralizar todas as requisições em URLs mapeadas para servlets, e deixar as páginas JSP apenas como formatadores que serão executados por algum servlet. Ou seja, o fluxo de uma requisição será sempre o apresentado na Figura 4: navegador-servlet-JSP-navegador.

 Portanto todas as URLs especificadas como links nas páginas HTML resultantes, ou em atributos action de formulários, devem indicar URLs mapeadas para servlets – nunca páginas JSP.

 

Atenção: A estrutura de uma boa aplicação web é “plana”, enquanto que aplicações gráficas para desktop (como as escritas para o Windows com VisualBasic ou Delphi – ou em Java utilizando o Swing) são em geral bastante hierarquizadas, via menus, janelas e caixas de diálogo. Não caia na armadilha de projetar uma aplicação web como se fosse uma aplicação de interface gráfica!

Segundo exemplo: capitais

Juntando as duas práticas apresentadas – utilizar servlets apenas para lógica e páginas JSP para formatação dos resultados, e reduzir a quantidade de páginas pelas quais o usuário tem que navegar – apresentamos um exemplo onde é informada a sigla de um estado e a aplicação responde com sua capital. Já aprendemos nas duas partes anteriores desta série como criar páginas JSP contendo dados variáveis, e como exibir condicionalmente partes da página, de modo que temos todos os conhecimentos necessários para entender o exemplo.

A Listagem 3 apresenta a página JSP que permite a seleção de um estado e a exibição do nome da sua capital, e a Listagem 4 apresenta o servlet correspondente. Esperamos que o leitor seja capaz de configurar o mapeamento do servlet para a URL /capital no descritor web.xml, tomando por base o primeiro exemplo do artigo.

Para que seja possível rodar o novo servlet, é necessário que seja feita uma recarga do contexto por meio da aplicação Manager do Tomcat. Veja na Figura 5 um exemplo de navegação pelo novo servlet. Note que a divisão de tarefas entre o servlet e a página JSP é natural, e que a página JSP deste exemplo é mais simples do que as de exemplos similares apresentados nos artigos anteriores desta série.

O processamento de parâmetros da requisição é completamente transparente ao seu tipo, por isso freqüentemente os desenvolvedores fazem com que ambos os métodos doGet() e doPost() de seus servlets chamem um mesmo método, como o processRequest() em nosso exemplo.

 Uma vantagem desta prática é que, na maior parte dos casos, a requisição POST é mais elegante, pois não exibe no navegador uma URL cheia de símbolos “?”, “&”, “=” e “%”; mas é fácil especificar os parâmetros de uma requisição GET, sem necessidade de um formulário HTML para gerar a requisição POST. Então, o GET é útil para depuração, mas o POST é melhor para a produção.

O ServletCapital utiliza um Map para relacionar siglas dos estados às suas capitais. Como estes dados não são modificados por meio da aplicação (isto é, ela não permite cadastrar um novo estado ou modificar a capital de um estado conhecido), é seguro utilizar uma variável de classe para armazenar o mapa, e inicializá-lo no método init().

 

Atenção: Cuidado para não confundir o termo “atributo”, quando utilizado para indicar variáveis de instância de um objeto Java, com o uso do termo para valores que são salvos na requisição ou na sessão HTTP e recuperados pelo método getAttribute().

 

Note que este exemplo utiliza tags do JSTL na página JSP. Assim sendo, os pacotes JAR do Jakarta Taglib Standard devem ser copiados para a pasta WEB-INF/lib da nossa aplicação (veja o artigo na Edição 19 para mais detalhes sobre o uso e instalação do JSTL). A ...

Quer ler esse conteúdo completo? Tenha acesso completo