artigo servlets

15
Servlets, o coração do Java para web A internet tem sido a grande plataforma para muitos projetos de software da atualidade. Não é à toa que grande parte dos sistemas de hoje, independente de possuir suas interfaces desktop, mobile ou web (rodando no browser), faz uso do modelo cliente-servidor. Este modelo é caracterizado pelo fato da aplicação possuir módulos que executam em diferentes máquinas. Um módulo - servidor - geralmente é responsável pelas regras de negócio, persistência dos dados ou processamentos mais custosos, como, por exemplo, cálculos matemáticos complexos. Já o módulo cliente geralmente contém apenas a camada de apresentação da aplicação, a qual possui a interface com o usuário. A comunicação entre cliente e servidor, por sua vez, normalmente é feita através de uma rede utilizando-se de algum protocolo de comunicação, como o HTTP. Com base nisso, neste artigo veremos como construir esse módulo servidor utilizando Java, mais especificamente a Servlet API. Aqui iremos descobrir como os servlets estendem as possibilidades na construção de uma aplicação web. Veremos que, em adição às páginas HTML estáticas, por meio do uso da Servlet API é possível realizar processamento lógico no servidor, mantendo a simplicidade e portabilidade oferecidas pela linguagem de marcação de hipertexto no lado cliente. Também aprenderemos a trabalhar com dados compartilhados, gerenciar a sessão do usuário e delegar o tratamento de requisições. Tudo isso através da construção de exemplos práticos e um pequeno projeto. A Servlet API O Java tem sido amplamente utilizado no desenvolvimento de sistemas web devido a características como maturidade, segurança, robustez e confiabilidade. E é no coração do desenvolvimento web em Java, que encontramos a Servlet API. Atualmente em sua versão 3.0, esta API fornece diversos recursos que dão suporte e tornam possível a construção de aplicações web dinâmicas utilizando Java. A Servlet API surgiu da necessidade de se criar conteúdo dinâmico para as páginas web. Na época isto já era feito utilizando outras tecnologias, como o famoso CGI e até mesmo com Java, através de Applets. Mas ainda não era o ideal, devido às limitações que tais tecnologias carregam consigo. Para resolver esse problema no universo Java, foi criada então a Servlet API. Através dela é possível implementar aplicações web utilizando todos os recursos do Java, como APIs de acesso a banco de dados, sistemas de arquivos e outros recursos impossíveis de serem utilizados apenas com páginas HTML comuns. Tudo isso sem sobrecarregar a máquina do usuário, uma vez que todo esse processamento é realizado no lado servidor da aplicação, cabendo ao browser (cliente) apenas processar o HTML gerado pelo back-end, não sendo necessária a instalação de nenhum tipo de plugin, como o Flash Player, Silverlight ou mesmo o Java Plugin, este último utilizado para executar applets no browser.

Upload: ezequiel-oliveira

Post on 04-Aug-2015

107 views

Category:

Documents


27 download

TRANSCRIPT

Page 1: Artigo Servlets

Servlets, o coração do Java para web

A internet tem sido a grande plataforma para muitos projetos de software da atualidade. Não

é à toa que grande parte dos sistemas de hoje, independente de possuir suas interfaces

desktop, mobile ou web (rodando no browser), faz uso do modelo cliente-servidor. Este

modelo é caracterizado pelo fato da aplicação possuir módulos que executam em diferentes

máquinas. Um módulo - servidor - geralmente é responsável pelas regras de negócio,

persistência dos dados ou processamentos mais custosos, como, por exemplo, cálculos

matemáticos complexos. Já o módulo cliente geralmente contém apenas a camada de

apresentação da aplicação, a qual possui a interface com o usuário. A comunicação entre

cliente e servidor, por sua vez, normalmente é feita através de uma rede utilizando-se de

algum protocolo de comunicação, como o HTTP.

Com base nisso, neste artigo veremos como construir esse módulo servidor utilizando Java,

mais especificamente a Servlet API. Aqui iremos descobrir como os servlets estendem as

possibilidades na construção de uma aplicação web. Veremos que, em adição às páginas HTML

estáticas, por meio do uso da Servlet API é possível realizar processamento lógico no servidor,

mantendo a simplicidade e portabilidade oferecidas pela linguagem de marcação de

hipertexto no lado cliente.

Também aprenderemos a trabalhar com dados compartilhados, gerenciar a sessão do usuário

e delegar o tratamento de requisições. Tudo isso através da construção de exemplos práticos e

um pequeno projeto.

A Servlet API

O Java tem sido amplamente utilizado no desenvolvimento de sistemas web devido a

características como maturidade, segurança, robustez e confiabilidade. E é no coração do

desenvolvimento web em Java, que encontramos a Servlet API. Atualmente em sua versão 3.0,

esta API fornece diversos recursos que dão suporte e tornam possível a construção de

aplicações web dinâmicas utilizando Java.

A Servlet API surgiu da necessidade de se criar conteúdo dinâmico para as páginas web. Na

época isto já era feito utilizando outras tecnologias, como o famoso CGI e até mesmo com

Java, através de Applets. Mas ainda não era o ideal, devido às limitações que tais tecnologias

carregam consigo. Para resolver esse problema no universo Java, foi criada então a Servlet API.

Através dela é possível implementar aplicações web utilizando todos os recursos do Java,

como APIs de acesso a banco de dados, sistemas de arquivos e outros recursos impossíveis de

serem utilizados apenas com páginas HTML comuns.

Tudo isso sem sobrecarregar a máquina do usuário, uma vez que todo esse processamento é

realizado no lado servidor da aplicação, cabendo ao browser (cliente) apenas processar o

HTML gerado pelo back-end, não sendo necessária a instalação de nenhum tipo de plugin,

como o Flash Player, Silverlight ou mesmo o Java Plugin, este último utilizado para executar

applets no browser.

Page 2: Artigo Servlets

Common Gateway Interface: Tecnologia onde scripts eram executados no servidor a fim de

gerar conteúdo dinâmico. Foi sendo substituída principalmente devido a sua baixa

escalabilidade e portabilidade.

Applets: Tecnologia Java que permite a criação de conteúdo dinâmico, porém do lado cliente -

no browser mais especificamente. Por rodar no cliente, possui diversas limitações, como a

necessidade de um plugin para poder ser executado, o “peso” do applet, que precisa ser

baixado com todas as dependências e carregado na página, restrições de segurança para

acesso ao sistema de arquivos, bancos de dados, entre outros pontos negativos.

Servlets

De modo resumido, um Servlet é uma classe Java que roda no servidor web e é capaz de

processar as requisições feitas pelos clientes (browsers) gerando uma resposta dinâmica,

geralmente no formato HTML. Para isso essa classe deve implementar a interface

javax.servlet.Servlet, a qual define os métodos do ciclo de vida desses objetos no servidor,

sendo o principal deles o método service(), no qual é efetuado o tratamento da requisição.

Além dessa interface básica, a API disponibiliza algumas classes que simplificam o

desenvolvimento, uma vez que estas já provêm implementações para boa parte dos métodos

da interface, além de oferecer pontos de extensão para que o desenvolvedor possa

implementar suas próprias regras.

No caso das aplicações web, onde basicamente é usado o protocolo HTTP nas requisições, a

API disponibiliza a classe HttpServlet para ser estendida. Esta já faz todo o tratamento das

regras do protocolo e deixa a cargo do desenvolvedor apenas a lógica do tratamento da

requisição. A classe HttpServlet define métodos no formato doXxxx() para cada método HTTP -

GET, POST, CONNECT, OPTIONS, HEAD, TRACE, PUT e DELETE - e ao desenvolvedor basta

sobrescrever os métodos que desejar.

Os métodos doGet() e doPost() são os mais comumente implementados, uma vez que seus

correspondentes, GET e POST, no HTTP são os mais utilizados.

Os passos para criar um servlet HTTP são bem simples, a saber:

1. Criar uma classe que estenda HttpServet;

2. Escolher os métodos HTTP que serão tratados, sobrescrevendo o método da classe

HttpServlet correspondente (Ex.: doPost() para tratar requisições do tipo POST);

3. Informar ao container quais URLs serão tratadas. Para isso basta anotar a classe com a

anotação @WebServlet, que recebe como parâmetro o padrão de URL a ser tratado

pelo servlet.

A Servlet API também oferece a classe GenericServlet, que pode ser estendida para se criar um

servlet genérico, independente de protocolo. Contudo, na prática, essa possibilidade

geralmente é barrada pelos servidores de aplicação, os quais só trabalham com o protocolo

HTTP.

Page 3: Artigo Servlets

Hello Servlet World

Agora que já vimos um pouco sobre servlets, vamos verificar como tudo isso funciona na

prática.

Para tal, criaremos um pequeno servlet que simplesmente imprime uma mensagem de boas-

vindas no browser, seguindo a linha dos famosos Hello, Worlds! Nosso servlet terá ainda a

possibilidade de receber um parâmetro com o nome do usuário na requisição, para assim

exibir uma saudação nominal.

Ambiente

Para dar início aos nossos exemplos, vamos montar nosso ambiente de desenvolvimento, que

consistirá basicamente de um IDE e um servidor de aplicação. Para os exemplos deste artigo,

utilizaremos Eclipse e Tomcat, respectivamente.

No caso do Eclipse, vamos utilizar a distribuição Java EE, que já vem pré-configurada com

plugins para o desenvolvimento web (veja a seção Links). Para isso, baixe o arquivo e

descompacte-o num diretório de sua preferência.

O Apache Tomcat será o servidor de aplicação que adotaremos nos exemplos. Para fazer uso

da Servlet API 3.0, é preciso utilizar a versão 7 deste servidor (veja Links). Portanto, baixe o

Tomcat 7 e siga os passos abaixo para adicioná-lo ao Eclipse:

1. No menu, acesse File > New > Other... > Server;

2. Escolha a opção Apache > Apache Tomcat v7.0 e clique em Next;

3. Informe a localização do diretório de instalação do Tomcat e clique em Finish.

Projeto

Com o ambiente devidamente configurado, vamos criar um projeto para desenvolver os

exemplos. Portanto, crie um novo projeto web no Eclipse acessando o menu File > New >

Project... > Dynamic Web Project.

Em seguida, dê um nome ao projeto, selecione o servidor no qual o projeto será executado

(Target runtime) e a versão da Servlet API (Dynamic web module version) que será utilizada, de

acordo com a Figura 1.

Page 4: Artigo Servlets

O primeiro servlet

Criaremos agora nosso primeiro servlet. A Listagem 1 mostra o código de HelloServlet. Como

podemos observar, esta classe estende HttpServlet e implementa o método doGet(). Deste

modo, sempre que o servlet receber uma requisição do tipo HTTP GET, o método doGet() será

invocado pelo servidor de aplicação.

Através da anotação @WebServlet, informamos ao servidor que a classe em questão é um

servlet. A String “/serv/hello” indica que o servlet tratará as requisições para este path.

Também é possível utilizar padrões ao invés de um path específico, caso queiramos que um

mesmo servlet trate mais de uma URL. Exemplos de padrões são: /app/servlets/*, *.jpg, *.jsf,

*.action, etc.

Path: O caminho ou path é a parte da URL que indica que recurso específico está sendo

acessado. Uma URL em geral tem o formato: <Protocolo>://<Domínio>[:<Porta>]/<Path>. Para

a URL http://google.com/maps, por exemplo, http é o protocolo, google.com é o domínio e

/maps é o path. Quando a porta não é informada, é utilizada a porta padrão do protocolo, 80

no caso do HTTP.

Nas versões anteriores da Servlet API não existia a possibilidade de configurar os servlets

utilizando annotations.

Para tal propósito era preciso declarar o servlet e os mapeamentos para o mesmo no arquivo

web.xml, localizado na pasta WEB-INF do projeto. Era necessária a criação de uma tag

Page 5: Artigo Servlets

<servlet>, onde era informado o nome e a classe do servlet, e tags <servlet-mapping>, onde

eram informados os padrões de URL que cada servlet iria tratar. Este tipo de configuração

ainda é suportado na nova versão da API.

No método doGet() utilizamos o objeto PrintWriter, responsável por escrever os dados na

saída a ser retornada ao browser. Obtemos esse objeto através do método

response.getWriter() e o utilizamos para escrever a mensagem de boas vindas ao usuário.

Nesse momento estamos de fato gerando o conteúdo dinâmico, que será visualizado pelo

cliente. No nosso exemplo, é possível perceber que estamos montando um texto no formato

HTML, o qual será renderizado no browser que efetuou a requisição.

Na prática, dificilmente encontraremos um servlet que gere o código HTML diretamente,

como no nosso exemplo, por questões de clareza e manutenibilidade do código de

apresentação. Para tal propósito, foram criados o JavaServer Pages (JSP) e afins. Entretanto,

para não nos desviarmos do tema do artigo, não utilizaremos o JSP e deixaremos o código de

layout no próprio servlet.

Note que utilizamos o método request.getParameter() para recuperar um parâmetro da

requisição. Verificamos então se o parâmetro name, com o nome do usuário, foi passado. Se

positivo, montamos uma mensagem nominal de boas vindas. Caso contrário, montamos uma

mensagem genérica.

Listagem 1. Código da classe HelloServlet.

package br.com.exemplo.servlets;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

@WebServlet("/serv/hello")

public class HelloServlet extends HttpServlet {

protected void doGet(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

String userName = request.getParameter("name");

StringBuilder greeting = new StringBuilder("Hello, ");

greeting.append((userName != null) ? userName : "Guest");

greeting.append("!");

StringBuilder html = new StringBuilder();

html.append("<html>");

html.append(" <head>");

html.append(" <title>Hello Servlets</title>");

html.append(" </head>");

html.append(" <body>");

html.append(" <h1>" + greeting + "</h1>");

html.append(" </body>");

html.append("</html>");

response.getWriter().print(html.toString());

}

}

Page 6: Artigo Servlets

Vamos então testar nosso servlet. Para isso, inicialize o servidor a partir do Eclipse, o que pode

ser feito na aba Servers, selecionando o servidor e clicando no botão Start, como mostra a

Figura 2.

Caso a aba Servers não esteja sendo exibida, acesse Window > Show View > Other... e

selecione Servers.

Agora abra o browser de sua preferência e acesse o endereço do servlet que acabamos de

criar: http://localhost:8080/HelloServlets/serv/hello, onde http://localhost:8080 é o endereço

do servidor, HelloServlets é o contexto da nossa aplicação (por padrão, o mesmo nome do

projeto no Eclipse) e serv/hello é o caminho que mapeamos para o servlet HelloServlet.

O resultado deve ser semelhante ao mostrado na Figura 3. Para testar a saudação nominal é

preciso informar na URL o valor do parâmetro name. Sendo assim, altere a URL para algo como

http://localhost:8080/HelloServlets/serv/hello?name=Jorge%20Amado e verifique o resultado.

Modularizando o tratamento da requisição

A Servlet API permite que um servlet delegue, total ou parcialmente, o tratamento de uma

requisição.

Assim, é possível encaminhar a requisição recebida, com ou sem alteração, para ser tratada

por outro componente, que pode ser outro servlet ou uma página JSP ou JSF, por exemplo.

Para demonstrar tal caso, criaremos a seguir uma versão mais rebuscada do nosso exemplo,

deixando a aplicação mais modularizada, separando as regras de negócio da montagem do

HTML resultante.

Page 7: Artigo Servlets

A classe HelloBusinessServlet (exibida na Listagem 2), que representa um servlet mapeado

para tratar requisições à URL /serv/hello2, executa apenas a lógica de negócio da aplicação,

que compreende montar uma saudação baseada na hora do dia e na presença de um

parâmetro com o nome do usuário na requisição. Note que, no método doGet(), após montar

o texto da saudação, criamos um atributo na requisição através do método

request.setAttribute(). Dessa forma é possível inserir informações na requisição que podem

ser utilizadas pelos componentes que vierem a tratá-la na sequência. No nosso caso,

montamos o texto e encaminhamos a requisição para ser tratada por outro servlet, associado

à URL serv/msg, que será responsável por construir o layout da página de resposta. Para

encaminharmos uma requisição utilizamos o método forward() da interface

RequestDispatcher, cuja instância é obtida através do método request.getRequestDispatcher(),

como podemos observar no exemplo.

Na Listagem 3 é mostrado o código da classe MessageServlet, no qual simplesmente

montamos o HTML da resposta que será exibida ao usuário.

Observe que utilizamos o método request.getAttribute() para recuperar a mensagem de

saudação, criada no servlet anterior.

Listagem 2. Código da classe HelloBusinessServlet - responsável por executar as

regras de negócio da aplicação.

package br.com.exemplo.servlets;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

@WebServlet("/serv/hello2")

public class HelloBusinessServlet extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

String userName = request.getParameter("name");

StringBuilder greeting = new StringBuilder("Hello, ");

greeting.append((userName != null) ? UserName : "Guest");

greeting.append("!");

Calendar cal = Calendar.getInstance();

int hour = cal.get(Calendar.HOUR_OF_DAY);

greeting.append(" Good ");

if (hour > 4 && hour < 12) {

greeting.append("Morning");

} else if (hour < 18) {

greeting.append("Afternoon");

} else {

greeting.append("Evening");

}

greeting.append("!");

request.setAttribute("text", greeting.toString());

request.getRequestDispatcher("/serv/msg").forward(request, response);

}

}

Page 8: Artigo Servlets

Listagem 3. Código da classe MessageServlet - responsável por exibir uma

mensagem na tela.

package br.com.exemplo.servlets;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

@WebServlet("/serv/msg")

public class MessageServlet extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

String messageText = (String) request.getAttribute("text");

StringBuilder html = new StringBuilder();

html.append("<html>");

html.append(" <head>");

html.append(" <title>Hello Servlets - Message</title>");

html.append(" </head>");

html.append(" <body>");

html.append(" <h1>" + messageText + "</h1>");

html.append(" </body>");

html.append("</html>");

response.getWriter().print(html.toString());

}

Com essa pequena alteração, vimos que é possível criar aplicações modularizadas utilizando

servlets. Numa aplicação real, geralmente iremos encontrar servlets sendo utilizados em

conjunto com outras tecnologias, como HTML, JSP, JSF, AJAX, etc. Dessa forma as

responsabilidades podem ser mais bem distribuídas, possibilitando a criação de aplicações

poderosas, com todos os recursos do Java, e bem estruturadas, sem misturar regras de

negócio com a lógica de apresentação.

Compartilhando dados além das requisições

No nosso último exemplo, vimos como compartilhar dados entre diferentes servlets, tratando

uma mesma requisição através dos métodos getAttribute() e setAttribute() da classe

HttpRequest. Com o auxílio destes métodos foi possível ler e escrever atributos no escopo da

requisição. Entretanto, do ponto de vista do servidor, cada requisição é única e não tem

nenhum tipo de ligação com as demais, uma vez que este atende a requisições de diferentes

clientes vindas de diferentes locais em diferentes momentos. Dessa forma não é possível a

troca de dados entre requisições distintas utilizando esses métodos.

Para viabilizar tal nível de compartilhamento, são oferecidos dois outros escopos, que vão

além da requisição: os escopos de sessão e de aplicação; ambos acessíveis através de classes

da Servlet API.

Escopo de Sessão

Para melhor entendermos o conceito de “escopo de sessão” ou “sessão do usuário”, vamos

imaginar um exemplo bastante comum do nosso dia a dia: um carrinho de compras. Neste

caso, o servidor tem que manter o estado dos dados enviados em cada requisição que adiciona

Page 9: Artigo Servlets

um item ao carrinho. Além disso, é preciso manter várias instâncias do carrinho, pois vários

usuários podem estar comprando ao mesmo tempo, fazendo com que o servidor tenha que

saber qual carrinho é de qual usuário.

Quando falamos em sessão do usuário é justamente desse tipo de situação que estamos nos

referindo. A sessão nada mais é do que um conjunto de informações de um determinado

usuário que fica armazenado no servidor. Essas informações continuam acessíveis, por um

determinado período, aos servlets entre as diversas requisições subsequentes que o usuário

venha a fazer.

A sessão possui um tempo máximo de inatividade, ou seja, quando o servidor percebe que não

está mais recebendo requisições de um determinado usuário por um tempo x, configurado no

servidor ou aplicação, esse elimina os dados daquela sessão.

Para manipular os dados da sessão de um usuário, a Servlet API fornece a interface

HttpSession, a qual também possui os métodos getAttribute() e setAttribute().

Um uso bastante comum do escopo de sessão é para o controle de acesso.

Neste caso, geralmente é criado um atributo com os dados do usuário autenticado na sessão,

e a cada requisição é possível verificar se este atributo está presente, ou seja, se existe um

usuário autenticado e se o mesmo tem permissão para executar a ação solicitada.

A sessão pode ser eliminada através do método HttpSession.invalidate(), ou quando o tempo

máximo de inatividade é atingido.

Na realidade, a sessão é associada ao browser que está efetuando as requisições, e não ao

usuário em si, IP ou coisa parecida. Isto pode ser verificado facilmente acessando um site de

compras qualquer, colocando alguns itens no carrinho e em seguida acessando o mesmo site a

partir de um browser diferente. O carrinho no segundo browser provavelmente estará vazio.

O que acontece é que o servidor gera uma chave de sessão e a envia ao cliente no cabeçalho

da resposta de uma determinada requisição, geralmente após a aplicação solicitar que seja

criada a sessão para o usuário. O cliente (browser), por sua vez, passa a enviar essa chave nas

requisições subsequentes e dessa forma o servidor consegue saber quais novas requisições

partiram desse mesmo cliente. Tudo isso é feito de forma transparente ao usuário.

Escopo de aplicação

Há, ainda, algumas situações onde a aplicação tem a necessidade de compartilhar dados num

escopo mais abrangente, de forma global, para que estes possam ser manipulados por

qualquer servlet presente na mesma.

Nestes casos podemos utilizar a interface ServletContext, a qual também possui os métodos

getAttribute() e setAttribute(). É possível obter a instância de ServletContext através do

método request.getServletContext().

Projeto Exemplo

Page 10: Artigo Servlets

Para que possamos ver na prática como tudo isso funciona, vamos aplicar os conceitos em

um pequeno projeto. A aplicação que desenvolveremos será um livro de visitas bastante

simples. Nela é exibido um mural de mensagens e é dada ao usuário a opção de escrever novas

mensagens. A Figura 4 mostra a tela principal da aplicação em funcionamento.

Para começar, crie um novo projeto web no Eclipse e dê o nome de “Guestbook”. Assim

como no projeto anterior, escolha o servidor Tomcat 7 que configuramos e a versão 3.0 da

Servlet API.

As Listagens 4 e 5 mostram o código das classes Message e MessagesManager, que são as

classes de negócio da nossa aplicação. A classe Message é um POJO simples que representa

uma mensagem no nosso livro de visitas. A mensagem é composta pelo nome e e-mail do

autor, conteúdo e data. A classe MessagesManager possui apenas dois métodos de negócio:

add(), que adiciona uma nova mensagem na lista de mensagens; e getMessages(), que

simplesmente retorna a lista com as mensagens.

Note que nossa aplicação, por se tratar de um exemplo didático, mantém a lista de mensagens

em memória. Em um sistema real as mensagens provavelmente seriam armazenadas e

recuperadas de uma base de dados.

Listagem 4. Código da classe Message - representa uma mensagem do usuário.

package br.com.exemplo.guestbook.bean;

import java.util.Date;

Page 11: Artigo Servlets

public class Message {

private String authorName;

private String authorEmail;

private String text;

private Date date;

public Message(String authorName, String authorEmail, String text, Date date) {

this.authorName = authorName;

this.authorEmail = authorEmail;

this.text = text;

this.date = date;

}

// gets e sets omitidos.

}

Listagem 5. Código da classe MessagesManager - cuida das regras de negócio

relacionadas às mensagens do usuário.

package br.com.exemplo.guestbook;

import java.util.ArrayList;

import java.util.List;

import br.com.exemplo.guestbook.bean.Message;

public class MessagesManager {

private List<Message> messages = new ArrayList<Message>();

public void add(Message message) {

messages.add(message);

}

public List<Message> getMessages() {

return messages;

}

}

Com as classes de negócio prontas, vamos criar o servlet responsável por gerar o código HTML

da página inicial da nossa aplicação (ver Figura 4), a qual irá exibir a lista das mensagens

postadas pelos usuários, além de algumas informações estatísticas da aplicação.

A Listagem 6 mostra a classe ListMessagesServlet. Primeiro marcamos a classe como um

servlet, através da anotação @WebServlet, na qual informamos também a URL que será

tratada por esse servlet. No método doGet(), primeiramente recuperamos a sessão do usuário

através do método request.getSession(), e desta recuperamos o atributo messageCount, que

contém o número de mensagens postadas pelo usuário. Caso o valor do atributo seja nulo,

assumimos o valor 0. Da mesma forma, recuperamos o ServletContext, a partir do qual

recuperamos o atributo manager, que é uma instância da classe MessagesManager, vista

anteriormente. Caso este não esteja com valor nulo, recuperamos do mesmo a lista de

mensagens e a atribuímos à variável messages. Na variável totalMessageCount armazenamos

o tamanho da lista, que corresponde ao número total de mensagens da aplicação.

Criamos então a URL de acesso ao formulário de inclusão de novas mensagens para que

possamos montar o hiperlink para esse formulário corretamente no código HTML.

Para isso, invocamos o método request.getContextPath() para recuperar o path da aplicação

e o concatenarmos com o caminho do arquivo form.html.

Page 12: Artigo Servlets

O restante do código simplesmente monta o código HTML que será exibido como resposta ao

cliente e em seguida o escreve na saída (no objeto response). Note que temos um loop para

iterar sobre as mensagens e para cada uma é chamado o método formatMessage(). É neste

método que montamos um texto HTML formatado contendo as informações da mensagem

recebida por parâmetro.

Listagem 6. Código da classe ListMessagesServlet - Monta a página inicial da aplicação, com a

lista de mensagens.

Nosso próximo passo será criar o formulário para que o usuário possa cadastrar uma nova

mensagem (ver Figura 5). A Listagem 7 mostra o código do arquivo form.html. Este arquivo

deve ser criado na pasta WebContent do projeto. Nele, criamos um formulário HTML com os

campos correspondentes às propriedades da mensagem que desejamos cadastrar, dos quais

extrairemos os valores dessas propriedades. Atente para os valores dos atributos name dos

elementos input e textarea, pois serão utilizados no servlet que efetuará o cadastro da

mensagem.

No elemento <form>, o atributo action informa a URL para a qual os dados do formulário

devem ser submetidos, e o atributo method indica o método HTTP a ser utilizado. No nosso

caso, será utilizado o método POST.

Listagem 7. Código da página form.html - formulário para inclusão de nova

mensagem.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Livro de visitas - Nova Mensagem</title>

</head>

<body>

<h1>Deixe sua mensagem</h1>

<form action="serv/messages/new" method="post">

<fieldset>

<legend>Nova mensagem:</legend>

Page 13: Artigo Servlets

<label for="txtName">Nome:</label>

<input name="txtName" />

<br />

<label for="txtEmail">E-mail:</label>

<input name="txtEmail" />

<br />

<label for="txaMessage">Mensagem:</label>

<textarea rows="5" cols="50" name="txaMessage"></textarea>

<br />

</fieldset>

<input type="submit" value="Enviar" />

</form>

</body>

</html>

A classe NewMessageServlet, mostrada na Listagem 8, será responsável por receber os dados

do formulário HTML, criar um objeto Message utilizando esses dados e salvar esta nova

mensagem na “base de dados”. Dessa vez implementamos o método doPost(), pois já que

utilizamos o valor post no atributo method do formulário HTML, o browser irá enviar uma

requisição do tipo HTTP POST.

No método doPost(), inicialmente recuperamos os valores dos parâmetros da requisição

através do método request.getParameter(). Perceba que os nomes dos parâmetros são os

mesmos nomes dos campos no formulário HTML. Em seguida, criamos uma nova mensagem

com os valores recuperados acrescidos da data corrente.

Na sequência, recuperamos, assim como na classe ListMessagesServlet, o contexto da

aplicação e, a partir deste, a instância da classe MessagesManager. Caso a instância ainda não

tenha sido criada, nós a criamos e a salvamos no contexto recuperado. Repare que utilizamos

um bloco sincronizado (synchronized) para garantir que essa sequência de operações sempre

aconteça de forma atômica, evitando assim problemas relacionados à concorrência.

Por padrão, sempre que recebe uma requisição, o servidor cria uma thread para tratá-la.

No entanto, este só cria uma instância do servlet caso ainda não exista uma, fazendo assim

com que a mesma instância trate várias requisições. Dessa forma, o desenvolvedor deve ter

cautela ao manipular, em seu servlet, dados compartilhados.

Na sequência, adicionamos a nova mensagem à nossa “base de dados”, utilizando o método

add() do objeto MessagesManager que acabamos de recuperar.

Após isso, recuperamos a sessão HTTP e o atributo messageCount contendo a quantidade de

mensagens criadas pelo usuário. Entretanto, dessa vez utilizamos o método setAttribute() para

configurar um novo valor, incrementando o valor anterior.

Finalmente invocamos o método layout(), que será responsável por montar o HTML de

resposta a ser exibido ao usuário. Nesse método, primeiro montamos a URL para voltar à

página de listagem, utilizando o path da aplicação, recuperado pelo método

request.getContextPath(), concatenado ao path mapeado pelo servlet ListMessagesServlet. Em

seguida montamos o código HTML e invocamos o método response.getWriter().print() para

escrevê-lo na resposta que será enviada ao usuário.

Page 14: Artigo Servlets

Listagem 8. Código da classe NewMessageServlet - cuida das regras de negócio relacionadas às

mensagens do usuário.

package br.com.exemplo.guestbook.servlet;

import java.io.IOException;

import java.util.Calendar;

import javax.servlet.ServletContext;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import br.com.exemplo.guestbook.MessagesManager;

import br.com.exemplo.guestbook.bean.Message;

@WebServlet("/serv/messages/new")

public class NewMessageServlet extends HttpServlet {

protected void doPost(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

String authorName = request.getParameter("txtName");

String authorEmail = request.getParameter("txtEmail");

String text = request.getParameter("txaMessage");

Message message = new Message(authorName, authorEmail, text, Calendar.getInstance().getTime());

ServletContext context = request.getServletContext();

MessagesManager manager = null;

synchronized (this) {

manager = (MessagesManager) context.getAttribute("manager");

if (manager == null) {

manager = new MessagesManager();

context.setAttribute("manager", manager);

}

}

manager.add(message);

HttpSession session = request.getSession();

Object value = session.getAttribute("messageCount");

int userMessageCount = value != null ? (Integer) value : 0;

session.setAttribute("messageCount", ++userMessageCount);

layout(request, response);

}

private void layout(HttpServletRequest request, HttpServletResponse response)

throws IOException {

String destination = request.getContextPath() + "/serv/messages/list";

StringBuilder html = new StringBuilder();

html.append("<html>");

html.append(" <head>");

html.append(" <title>Guestbook</title>");

html.append(" </head>");

html.append(" <body>");

html.append(" <h1>Mensagem adicionada com sucesso!</h1>");

html.append(" <a href='" + destination + "'>Continuar</a>");

html.append(" </body>");

Page 15: Artigo Servlets

html.append("</html>");

response.getWriter().print(html.toString());

}

}

Por fim, vamos criar o arquivo index.html na pasta WebContent com o conteúdo mostrado na

Listagem 9. Aqui utilizamos a tag HTML <meta> com o atributo http-equiv=“Refresh” para

redirecionar o usuário para a página de listagem das mensagens. Por padrão, o servidor

carrega a página index.html automaticamente quando o endereço da aplicação é digitado.

Dessa forma, quando o usuário acessar o endereço http://localhost:8080/Guestbook, o

servidor carregará automaticamente a página index.html, que por sua vez irá redirecionar o

usuário para a página com a lista de mensagens, não sendo necessário a este escrever o

caminho completo da página (http://localhost:8080/Guestbook/serv/messages/list).

Com isso concluímos o desenvolvimento do nosso projeto exemplo. Para testá-lo, execute a

aplicação, crie novas mensagens e as visualize na tela de listagem. Para simular diferentes

usuários, podemos utilizar vários browsers, ou mesmo acessar a aplicação de outras máquinas,

simulando assim um ambiente mais real.

Listagem 9. Código do arquivo index.html - página inicial da aplicação.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Guestbook</title>

<meta http-equiv="Refresh" content="0;url=serv/messages/list" />

</head>

<body></body>

</html>

Conclusões

Este artigo mostrou como criar aplicações web em Java utilizando a Servlet API, em sua

versão 3.0. Aqui o leitor aprendeu a criar servlets HTTP, tratar parâmetros da requisição,

escrever a resposta em HTML para o usuário, delegar requisições para outros servlets e

compartilhar dados entre servlets nos escopos de requisição, sessão e aplicação. Esse

conhecimento serve de base para todo o universo de desenvolvimento web em Java; desde as

páginas JSP até os diversos frameworks presentes no mercado, como Struts, Spring MVC e JSF.

Autor

Paulo César Coutinho

Analista de Sistemas no SERPRO. Tem experiência no desenvolvimento e projeto de aplicações

Java, C/C++ e Flex, PL/SQL e Oracle Forms. Possui as certificações SCJP 5 e SCWCD 1.4