Por que eu devo ler este artigo:Serve para desenvolvedores que desejam iniciar a construção de aplicações web com Java utilizando JSP e Tag libraries, através dos seus conceitos principais e do desenvolvimento de uma aplicação de exemplo.

Este artigo trata os conceitos de JSP e Tag Libraries, visando apresentar as tecnologias aos desenvolvedores Java. Ele descreve os conceitos fundamentais de JSP e Tag Libraries e também exibe uma aplicação prática demonstrando todo o potencial de utilização desses conceitos.

Muitos desenvolvedores quando desejam iniciar na construção de aplicações web encontram, na maioria das vezes, frameworks de alto nível que facilitam o desenvolvimento, mas que possuem uma série de conceitos embutidos, que não são especificados. Entre eles, o conceito de JSP e Tag Libraries. Conhecer esses conceitos permite não somente entender melhor esses frameworks, como também fornece ao desenvolvedor uma capacidade maior de interação com eles.

O JSP (Java Server Pages) é uma especificação para camada web que serve de auxílio ao Servlet e é utilizado no desenvolvimento de interfaces web para aplicações corporativas. JSP é uma tecnologia que combina as linguagens de marcação HTML/XML e elementos da linguagem de programação Java, devolvendo um conteúdo dinâmico para o cliente web. Por esta razão, ele é comumente usado para representar a lógica de apresentação de uma aplicação web, embora as páginas JSP possam também conter lógicas de negócio.

A fim de facilitar a legibilidade, reusabilidade e manutenibilidade das páginas JSP, desenvolvedores podem incorporar, dentro do JSP, bibliotecas customizadas para diversos fins, tais como loops, comandos condicionais, etc. ou até mesmo implementar suas próprias bibliotecas para algo específico. Essas bibliotecas são denominadas Tag Libraries, e dentre as disponíveis no mercado temos o Standard Tag Libraries (JSTL).

Para exemplificar os conceitos de JSP e Tag Libraries, este artigo apresenta uma aplicação simples, uma loja virtual, que consiste basicamente no processo de compra de CDs (mesmo exemplo do artigo anterior). O exemplo ilustra os passos necessários para a construção da aplicação utilizando a arquitetura MVC, ou seja, o uso de JSP e Tag Libraries para a camada de apresentação e o Servlet atuando como controlador, melhorando assim o exemplo anterior, onde tudo era desenvolvido no próprio Servlet.

No segundo artigo desta série, continuamos com a apresentação sobre o desenvolvimento web na plataforma Java EE. Neste artigo abordaremos os conceitos de JSP e Tag Libraries, que são a base para o entendimento da camada de visão em uma arquitetura MVC. Vale ressaltar que todos os frameworks para web em Java utilizam de forma intrínseca essas tecnologias. Sendo assim, é de fundamental importância o conhecimento dessas, resultando em um conhecimento diferenciado para produção de aplicações web além do trivial, explorando ao máximo as vantagens dos frameworks disponíveis no mercado.

Definições sobre JSP

A JSP (JavaServer Pages) é uma especificação para camada web que facilita a programação de Servlets. A tecnologia JSP combina as linguagens de marcação HTML/XML e elementos da linguagem de programação Java, devolvendo um conteúdo dinâmico para o cliente web. Por esta razão, é comumente usado para representar a lógica de apresentação de uma aplicação web, embora as páginas JSP possam também conter lógica de negócio. JSP possui uma engine que trata a página JSP de forma a separar o que é código HTML e código Java para posterior tratamento. Estaremos detalhando mais suas funções no tópico referente ao ciclo de vida da JSP.

Como qualquer outra linguagem, a linguagem de script JSP tem uma gramática bem definida e inclui elementos de sintaxe para executar várias tarefas, tais como declarar variáveis e métodos, escrever expressões e fazer chamadas a outras páginas JSP. Em alto nível, estes elementos de sintaxe, também chamados de tags JSP, são classificados em seis categorias. A Tabela 1 apresenta resumidamente cada uma delas; em seguida explicamos cada uma resumidamente.

Tipo da Tag JSP Breve Descrição Sintaxe da Tag
Diretiva Especifica instruções em tempo de tradução para a engine JSP
Declaração Declara e define métodos e variáveis
Scriptlet Permite ao desenvolvedor escrever código Java de forma livre na página JSP.
Expressão Usado como um atalho para imprimir valores na saída HTML de uma página JSP.
Ação Provê uma instrução em tempo de requisição para a engine JSP <jsp:actionName />
Comentário Usado para documentação e para comentário
Tabela 1. Tipos de Elementos JSP.

Diretiva

Diretivas provem uma informação geral sobre a página JSP para a engine JSP. Existem três tipos de diretivas: page, include e taglib.

A diretiva page informa à engine uma propriedade da página JSP. Por exemplo, a seguinte diretiva informa à engine que nós utilizaremos Java como a linguagem de script da página JSP:


<%@ page language="java" %>

Uma diretiva include pede à engine JSP para incluir o conteúdo de outro arquivo (HTML, JSP, etc.) na página corrente. Um exemplo:


<%@ include file="copyright.html" %>

Uma diretiva taglib é usada para associar um prefixo a uma biblioteca de tags (tag library ou simplesmente taglib). Exemplo:


<%@ taglib prefix="test" uri="taglib.tld" %>

Declarações

Declarações declaram e definem variáveis e métodos que podem ser usados em uma página JSP:


<%! int count = 0; %>

Este exemplo declara uma variável count e a inicializa com 0.

Scriptlet

Scriptlets são fragmentos de código Java que são embutidos em páginas JSP, como:


<% count++; %>

O scriptlet é executado cada vez que a página é acessada, e a variável count é incrementada a cada requisição. Devido aos scriptlets poderem conter código Java, eles são tipicamente usados para embutir lógica de negócio na página JSP. Entretanto, nós podemos usá-los para imprimir instruções HTML, também.

Expressões

Expressões atuam como uma forma direta e simples de imprimir o resultado de qualquer expressão Java em uma página JSP. Uma expressão Java pode ser uma variável, a soma de dois inteiros, etc. Um exemplo de uma expressão JSP:


<%= count %>

As expressões também são invocadas a cada vez que a página é acessada. Assim, o valor atualizado de count sempre será usado para cada requisição. A diferença entre uma scriptlet e uma expressão é que o valor resultante da expressão é automaticamente inserido no output; no caso, se tivermos count = 17 quando a página for solicitada, esta expressão irá gerar a string “17”.

Ações

Ações são comandos dados para a engine JSP. Eles a direcionam para executar certas tarefas durante a execução de uma página. Por exemplo, na seguinte linha de instrução, a engine inclui o conteúdo da outra página JSP, copyright.jsp, no conteúdo da página corrente:


<jsp:include page="copyright.jsp" />

Existem seis ações padrões para JSP: jsp:include, jsp:forward, jsp:useBean, jsp:setProperty, jsp:getProperty e jsp:plugin. As ações jsp:include e jsp:forward habilitam uma página JSP a reusar outros componentes web. A primeira inclui o conteúdo da página inclusa, já a segunda, jsp:forward, passa o controle para uma determinada página JSP.

As ações jsp:useBean, jsp:setProperty e jsp:getProperty são relacionadas ao uso de JavaBeans nas páginas JSP. A última ação (jsp:plugin) instrui ao JSP engine a geração do código HTML a fim de adicioná-lo nos componentes do lado do cliente, tal como applets.

Comentários

Comentários não afetam a saída de uma página JSP, independente de onde estejam escritos, mas são usados para o propósito de documentação. Um exemplo:


<%-- Aqui está o comentário --%>

Ciclo de vida do JSP

Uma página JSP possui sete fases em seu ciclo de vida. Porém, antes de falarmos mais sobre o ciclo de vida, precisamos entender dois pontos importantes com relação às páginas JSP, os quais explicaremos abaixo.

Páginas JSP são Servlets

Embora, estruturalmente, uma página JSP possa ser vista como uma página HTML, ela na prática executa como um Servlet. A engine JSP analisa o arquivo JSP e cria um arquivo Java correspondente. Este arquivo declara uma classe Servlet e mapeia seus membros diretamente para os elementos do arquivo JSP. A engine JSP então compila a classe, a carrega em memória e a executa como qualquer outro Servlet. A saída deste Servlet é então enviada para o cliente.

Entendendo o mecanismo de tradução

Como uma página HTML pode incluir o conteúdo de outras páginas HTML, uma página JSP pode incluir conteúdos de outras páginas JSP e HTML. Isso é feito com auxílio da diretiva include. Assim, quando a engine JSP gera o código Java para uma página JSP, ele também insere o conteúdo da página incluída no Servlet que foi gerado. Ao ato de traduzir um grupo de páginas em uma única classe Servlet, chamamos de unidade de tradução. Algumas das tags JSP afetam toda a unidade de tradução e não somente a página onde eles estão declarados. Alguns pontos importantes referentes a uma unidade de tradução:

  • As diretivas de página afetam toda a unidade de tradução;
  • Uma declaração de variável não pode ocorrer mais de uma vez em uma unidade de tradução. Por exemplo, nós não podemos declarar uma variável em uma página incluída usando a diretiva include se esta já estiver sido declarada na página incluinte, porque as duas compõe uma única unidade de tradução;
  • A ação <jsp:useBean> não pode declarar o mesmo bean duas vezes em uma única unidade de tradução, pois acarretará em erro de duplicação de instâncias.

Fases do Ciclo de Vida do JSP

Quando uma página JSP é acessada pela primeira vez, o servidor responde de forma mais lenta que na segunda, terceira e nos acessos subsequentes. Isto é porque, como mencionamos acima, toda página JSP deve ser convertida em uma Servlet e, logo após, a Servlet deve ser compilada. Para cada requisição, a engine JSP compara o timestamp do código-fonte da JSP ao da classe Servlet para determinar se a JSP é nova ou mais atual que a Servlet.

Assim, se nós modificarmos uma JSP, seu processo de conversão para Servlet é executado novamente. Este processo consiste de sete fases. A Tabela 2 lista as fases na ordem em que devem ocorrer.

Nome da Fase Descrição
Tradução da Página A página é analisada e um arquivo Java contendo o Servlet correspondente é criado.
Compilação da Página O arquivo Java é compilado.
Carregar a classe A classe compilada é carregada pelo container na memória.
Criar a instância Uma instância do Servlet é criado.
jspInit() Este método é chamado antes de qualquer outro método para permitir a inicialização.
jspService() Este método é chamado para cada requisição.
jspDestroy() Este método é chamado quando o container decide colocar o Servlet fora do ar.
Tabela 2. Seqüência de fases do ciclo de vida do JSP.

Inclusão Estática e Dinâmica

A especificação JSP define mecanismos que nos permite reusar os componentes web (páginas HTML, JSP, arquivos estáticos em geral, etc.). Reutilizar componentes é uma prática importante, pois aumenta a produtividade e a manutenibilidade da aplicação. Entenderemos, mais adiante, como componentes podem ser reutilizados em JSP.

No mundo JSP, reusar componentes web, essencialmente, significa incluir o conteúdo ou a saída de outro componente web em uma página JSP. Isto pode ser feito de duas formas: estática ou dinâmica. Inclusão estática envolve incluir o conteúdo dos componentes web em um arquivo JSP no momento em que o arquivo JSP é traduzido. Na inclusão dinâmica a saída de outro componente é incluída na saída da página JSP quando a página JSP é invocada.

Inclusão Estática

Na inclusão estática, os conteúdos de outros arquivos são incluídos no arquivo JSP atual em tempo de tradução para produzir um único Servlet. Nós usamos a diretiva JSP include para executar esta tarefa. Vamos ver algumas sintaxes para tal operação de inclusão:


<%@ include file="relativeURL" %>

<jsp:directive.include file="relativeURL" />

O atributo file é o único atributo da diretiva include, sendo obrigatório. Ele faz referência para o arquivo que contém o texto estático ou o código que será inserido dentro da página JSP. Ele pode referenciar qualquer arquivo baseado em texto – HTML, JSP, XML, ou um simples arquivo .txt – usando uma URL relativa (relativeURL). Uma URL relativa não pode ter um protocolo, um hostname ou um número de porta. Pode ou ser um caminho relativo para o arquivo JSP corrente, ou um caminho relativo para a raiz do documento da aplicação web. Um exemplo correto de utilização seria:


<%@ include file="cabecalho.html" %>

Inclusão Dinâmica

Na inclusão dinâmica, quando uma página JSP é chamada, ela envia uma requisição para outro objeto, e a saída deste é incluída na página JSP chamada. Para essa tarefa são utilizadas as ações JSP:


<jsp:include page="relativeURL"  flush=“true”>

<jsp:forward page="relativeURL ">

O atributo page é obrigatório. Ele deve ser uma URL relativa e pode referenciar um componente web estático ou dinâmico, incluindo um Servlet. Por exemplo:


<jsp:forward page="/pages/welcome.jsp ">

Quando usamos a ação <jsp:include>, esta delega o controle do processamento da requisição temporariamente para o componente incluído. Uma vez que o componente incluído tenha terminado seu processamento, o controle é transferido novamente para página que o incluiu.

Já quando usamos a ação <jsp:forward>, ela delega o processamento da requisição para o componente definido no atributo page. Este componente passa a ser o responsável por finalizar o processamento da requisição e enviá-la de volta ao cliente.

Podemos também passar parâmetros aos componentes incluídos dinamicamente utilizando a tag <jsp:param />. Por exemplo:


<jsp:include page="somePage.jsp">

  <jsp:param name="name1" value="value1" />

  <jsp:param name="name2" value="value2" />

</jsp:include>

Escopos em JSP

Conforme exposto no primeiro artigo (publicado na Edição 66), o modelo de Servlet permite o compartilhamento dos dados através de diferentes objetos do container: ServletContext, HttpSession e ServletRequest. Os escopos associados a esses três objetos do container são respectivamente, escopo de aplicação, escopo de sessão e escopo de requisição. Desde que a tecnologia JSP é baseada na tecnologia de Servlets, também utiliza os três escopos, que são referenciados nas páginas JSP pelas varáveis implícitas application, session e request.

Além desses escopos, as páginas JSP têm o quarto escopo, o escopo de página, referenciado pela variável implícita pageContext e mantido pelo objeto PageContext. Esse escopo é limitado a uma única unidade de tradução, ou seja, caso se queira compartilhar objetos através de páginas diferentes, mas pertencentes a uma mesma unidade de tradução, esse objeto pode ser utilizado.

Tag Libraries

Além das JSP actions pré-definidas, desenvolvedores podem adicionar suas próprias actions customizadas através do uso da JSP Tag Extension API. A idéia da criação de tag libraries surgiu no intuito de facilitar a legibilidade e manutenibilidade das páginas JSP. A criação destas é bastante simples, sendo necessário para isso escrever uma classe Java, Tag Handler, que implementa uma das interfaces Tag oferecidas pela API (Tag, IterationTag, BodyTag, SimpleTag). A interface Tag deve ser usada para escrever tags simples que não requerem iterações ou processamento do corpo da tag. Para escrever esses tipos de tags devem ser usadas as classes IterationTag e BodyTag.

A interface SimpleTag apareceu na especificação 2.0 do JSP com o objetivo de simplificar o desenvolvimento de tag handlers, reduzindo assim a quantidade de código nessas classes. Além da Tag Handler, deve ser configurado um arquivo XML, o Tag Library descriptor (TLD), para indicar ao engine JSP todas as informações necessárias para que este possa executar uma tag dentro de uma página JSP, como qual é o Tag Handler associado, onde ele se encontra e como deve ser usado.

A proposta desse artigo, a princípio, não é ensinar a fazer uma taglib e sim oferecer uma visão geral do seu funcionamento e especificar o seu uso. Dessa forma, iremos abordar a utilização de tag libraries já existentes no mercado. Dentre elas, temos a JSP Standard Tag Libraries (JSTL), um componente da plataforma Java EE que estende a especificação JSP, adicionando tags para tarefas comuns como processamento de dados em XML, comandos condicionais, loops e internacionalização. A JSTL consiste de vários grupos de tags para funções específicas:

  • core – tags de propósito geral: condicional, loop, seleção etc;
  • xml – tags para tratamento, seleção e transformação de dados XML;
  • fmt – tags para formatação de datas e uso de internacionalização;
  • sql – tags para acesso a banco de dados relacionais;
  • functions – tags para manipulação de Strings e coleções.

Para usar as tags da JSTL você precisará das bibliotecas da especificação e de uma implementação da especificação. Existe a implementação do grupo Apache Jakarta, a Jakarta Standard Tag library (ver Links). De posse dessas bibliotecas, adicione-as na pasta WEB-INF/lib do seu projeto web. Após isso, você precisa referenciar a taglib no seu arquivo JSP, utilizando para isso a diretiva taglib, por exemplo:


<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>

Essa diretiva informa ao engine JSP que você irá utilizar o grupo de funções core com o prefixo c, ou seja, você poderá invocar suas funções dentro da página JSP através do alias c, por exemplo, a tag abaixo imprime uma tabela com o nome e o endereço dos usuários de uma determinada lista:


<table>

  <c:forEach var=”usuario” items=”${usuarios}”>

    <tr>

      <td><c:out value="${usuario.nome}"/></td>

      <td><c:out value="${usuario.endereco}"/></td>

    </tr>

  </c: forEach>

</table>

O atributo uri informado não indica que essa tag está sendo baixada do site da Sun, é apenas um alias que está mapeado em um arquivo .tld dentro da biblioteca de implementação da taglib. Após referenciá-la você poderá utilizar umas das possíveis tags definidas no corpo da sua página JSP. A Tabela 3 ilustra as tags disponíveis que podem ser usadas dentro da página JSP.

Categoria Tags Descrição
Propósito geral <c:catch> Captura exceções
<c:out> Imprime conteúdo dentro da página
Suporte a variáveis <c:set> Seta o valor de uma variável
<c:remove> Remove uma variável
Controle de fluxo <c:if> Corresponde ao condicional if
<c:choose> Corresponde ao comando switch
<c:forEach> Percorre uma determinada coleção
<c:forTokens> Percorre uma determinada String formada por delimitadores
Tratamento de URLs <c:url> Reescreve URLs e codifica seus parâmetros
<c:import> Acessa conteúdo fora da aplicação web
<c:redirect> Redireciona a resposta do browser cliente para uma determinada url
Tabela 3. Lista de tags da JSTL.

Para o efetivo uso de tag libraries, é de extrema importância entender seus tipos. Existem basicamente quatro tipos distintos:

  • Tags vazias: Tags que não possuem atributos ou conteúdo em seu corpo. Pode ser escrita como <prefix:tagName> </prefix:tagName> ou <prefix:tagName/>. Um exemplo seria uma tag que imprimisse um * para os campos obrigatórios de um formulário, podendo ser usado numa página JSP da seguinte forma: <t:required>, admitindo que t tenha sido definido previamente como prefixo na diretiva taglib;
  • Tags com atributos: Possuem um ou mais atributos que servem como parâmetros para a taglib. Por exemplo, imagine uma tag que dá uma mensagem de boas vindas para um usuário recebido como parâmetro. Pode ser usada da seguinte forma: <t:greet name=”Java Magazine”/>;
  • Tags com corpo JSP: Podem receber código JSP como conteúdo. Por exemplo:
  • 
      <c:if test=”${usuarioValidado}”>
    
      Usuário <%=request.getParameter(“nomeUsuario”)%> logado com sucesso.
      
  • Tags contendo outras tags: Possuem outras tags em seu corpo. Por exemplo:
  • 
    <c:choose>
    
      <c:when test=”${operacao == ‘soma’}”
    
        Valor: ${a + b}
    
      </c:when>
    
      <c:when test=”${operacao == ‘sub’}”
    
        Valor: ${a - b}
    
      </c:when>
    
      <c:when test=”${operacao == ‘mult’}”
    
        Valor: ${a * b}
    
      </c:when>
    
      <c:when test=”${operacao == ‘div’}”
    
        Valor: ${a / b}
    
      </c:when>
    
      <c:otherwise>
    
        Operação inválida!
    
      </c:otherwise>
    
    </c:choose>
    

Desenvolvendo uma aplicação web utilizando Servlets, JSP e Tag libraries

Para ilustrar os conceitos explorados no artigo, vamos apresentar o mesmo exemplo ilustrado no artigo sobre Servlets, uma loja de CDs virtual. Entretanto, a proposta agora é melhorá-lo através de utilização de JSP e Tag libraries, utilizando o Modelo 2 de arquitetura JSP. Este modelo segue a arquitetura MVC através da utilização de Servlets como controladores, JSPs como visão e JavaBeans como modelo. Para relembrar o exemplo, ele consiste basicamente no processo de compra de CDs dividida em quatro etapas:

  • O cliente solicita visualizar o catálogo de CDs disponíveis para compra;
  • O cliente seleciona os CDs que deseja comprar;
  • O cliente informa os dados de compra: nome, endereço de entrega e número de cartão;
  • O cliente confirma os dados.

Na explicação do exemplo que daremos em seguida, iremos focar exclusivamente nas alterações realizadas através da adoção da nova arquitetura. Dessa forma, caso você tenha dificuldades referente ao uso ou configuração de Servlets, sugerimos a leitura do primeiro artigo, publicado na Edição 66.

Configurações adicionais no projeto

Assim como no exemplo do primeiro artigo sobre Servlets, iremos utilizar a IDE Eclipse, versão Ganymede (3.4; ver Links), para auxiliar no desenvolvimento da aplicação de exemplo. Também utilizaremos o container web Tomcat 6 para rodar a aplicação. Caso você encontre dificuldades em criar um projeto web no Eclipse, veja artigo anterior que descreve os passos necessários para criação e configuração.

Nesse exemplo, especificamente devido ao uso de Tag Libraries (JSTL), precisaremos incluir as bibliotecas jstl.jar e standard.jar ao projeto (ver Links). A primeira define um padrão para taglibs e a segunda consiste na implementação Jakarta do padrão. Essas bibliotecas devem ser postas no diretório WEB-INF/lib, conforme a estrutura padrão de aplicações web.

Estrutura do projeto

O Eclipse gera o projeto web seguindo a estrutura de diretórios de uma aplicação web Java EE (ver Figura 6). Segue uma descrição do conteúdo dos diretórios mais relevantes:

  • LojaVirtual: diretório raiz da aplicação. Irá representar o contexto da aplicação no servidor web;
  • src: contém os arquivos fontes da aplicação, as classes de negócio, os servlets, etc. Esse diretório não precisa estar presente no servidor web;
  • WebContent: Contém os arquivos HTML e JSP da aplicação;
  • WEB-INF: contém as classes compiladas e as bibliotecas externas utilizadas pela aplicação, inclusive as bibliotecas de tag libraries. Contém também o descritor web.xml.
Estrutura de pastas da aplicação web
Figura 6. Estrutura de pastas da aplicação web.

Exibindo o catálogo de CDs

A página inicial da aplicação não sofreu alterações, contendo apenas um link para exibir o catálogo de CDs (Figura 7 e Listagem 1). Ao clicar no link o sistema irá chamar um Servlet (ListaCDsServlet) para exibir o catálogo de CDs (Listagem 2). No artigo anterior, o Servlet fazia toda a geração da saída html, o que gerava uma mistura de código html dentro de código Java, dificultando a legibilidade e manutenção da aplicação, pois não havia separação da lógica de negócio com a apresentação.

Agora o Servlet irá servir apenas como um controlador, ou seja, irá utilizar as classes de modelo para executar a lógica de negócio e toda a construção da página de saída será repassada para a página JSP catalogoCds.jsp (Listagem 3). A página define o formulário e a lista de CDs com os checkboxes para seleção. Esta lista é construída através do mecanismo de inclusão dinâmica da página catalogoCdsInclude.jsp (Listagem 4).

A página catalogoCds.jsp recupera o catálogo de CDs da variável implícita application, que compartilha objetos no escopo de aplicação. Esse catálogo foi criado no método init() de ListaCDsServlet. Então na página catalogoCds.jsp são setados os atributos listaCds e listaEditavel no request através da utilização de scriptlets (veja as linhas 13-18 da Listagem 3). Os valores desses atributos serão lidos por catalogoCdsInclude.jsp, responsável em montar uma tabela contendo os dados de cds a partir de uma lista, oferecendo um checkbox de seleção caso a tabela seja editável, ou seja, o atributo listaEditavel seja true.

A construção da lista é feita utilizando as tag libraries <c:if>. e <c:forEach> (linhas 9-19 da Listagem 4). Note que a utilização de taglibs deixa o código bastante limpo, facilitando a legibilidade e a manutenibilidade.

Página inicial da Loja Virtual
Figura 7. Página inicial da Loja Virtual.
Listagem 1. Código HTML da página principal da aplicação.

<html>

   <head>

     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

     <title>Loja virtual</title>

   </head>

   <body>

     <h2>Loja Virtual</h2>

     <a href="/LojaVirtual/listacds">Ver catálogo de cds</a>

   </body>

 </html>
Listagem 2. Servlet que exibe o catálogo de Cds.

package lojavirtual;

 …

 public class ListaCdsServlet extends HttpServlet {



   @Override

   public void init() throws ServletException {

     super.init();

                

     //inicializa o map com o catálogo de cds

     CD cd1 = new CD(1L, "Novelas", "DJavan", 25.0);

     CD cd2 = new CD(2L, "Ao Vivo (vol. 1)", "DJavan", 30.0);

     CD cd3 = new CD(3L, "Ao Vivo (vol. 2)", "DJavan", 30.0);

     CD cd4 = new CD(4L, "Lilás", "DJavan", 20.0);

     CD cd5 = new CD(5L, "Acústico MTV", "Capital Inicial", 23.0);

     CD cd6 = new CD(6L, "Acústico MTV", "Kid Abelha", 21.0);

     CD cd7 = new CD(7L, "Infinito Particular", "Marisa Monte", 35.0);

     CD cd8 = new CD(8L, "Universo ao meu redor", "Marisa Monte", 40.0);

     CD cd9 = new CD(9L, "Greatest hits", "Queen", 20.0);

     CD cd10 = new CD(10L, "Queen Collection", "Queen", 45.0);

               
     HashMap<Long, CD> mapCds = new HashMap<Long, CD>();

     mapCds.put(cd1.getCodigo(), cd1);

     mapCds.put(cd2.getCodigo(), cd2);

     mapCds.put(cd3.getCodigo(), cd3);

     mapCds.put(cd4.getCodigo(), cd4);

     mapCds.put(cd5.getCodigo(), cd5);

     mapCds.put(cd6.getCodigo(), cd6);

     mapCds.put(cd7.getCodigo(), cd7);

     mapCds.put(cd8.getCodigo(), cd8);

     mapCds.put(cd9.getCodigo(), cd9);

     mapCds.put(cd10.getCodigo(), cd10);

               

     getServletContext().setAttribute("catalogoCds", mapCds);

   }



   @Override

   protected void doGet(HttpServletRequest req, HttpServletResponse resp)

     throws ServletException, IOException {



     //chama o servlet que monta a tabela de cds

     req.getRequestDispatcher("/catalogoCds.jsp").forward(req, resp);

   }

 }
 
Listagem 3. Página JSP de exibição do catálogo de Cds.

 <%@ page language="java" contentType="text/html; charset=ISO-8859-1"

    pageEncoding="ISO-8859-1"

    import="java.util.HashMap, lojavirtual.CD"

    %>

 <!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=ISO-8859-1">

   </head>

   <body>

     <h2>Lista de CDs</h2>

     <form name=formLista action='/LojaVirtualJSP/dadosCompra' method=POST>

       <%

         //adiciona os parâmetros no request para a criação da tabela com os cds

         HashMap<Long, CD> mapCds = (HashMap<Long, CD>) application.getAttribute("catalogoCds");

         request.setAttribute("listaCds", mapCds.values());

         request.setAttribute("listaEditavel", true);

       %>

       <jsp:include page="catalogoCdsInclude.jsp"></jsp:include>

       <input type="submit" value="Adicionar ao carrinho">

     </form>

   </body>

 </html>
 
Listagem 4. Página JSP que constrói a lista de Cds.


 <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>

 <table border="1">

   <tr>

     <c:if test="${requestScope.listaEditavel}">

       <td> </td>

     </c:if>

     <td>Código</td><td>Título</td><td>Artista</td><td>Preço</td>

   </tr>

   <c:forEach var="cd" items="${requestScope.listaCds}">

     <tr>

       <c:if test="${requestScope.listaEditavel}">

         <td><input type="checkbox" name="chkCodigosCds" value="${cd.codigo}"></td>

       </c:if>

       <td>${cd.codigo}</td>

       <td>${cd.titulo}</td>

       <td>${cd.artista}</td>

       <td>${cd.preco}</td>

     </tr>

   </c:forEach>

 </table>

Desenvolvendo a página com o formulário de requisição dos dados de compra

Não houve qualquer alteração para a criação dessa página, já que toda a apresentação já estava separada em um arquivo HTML. Após o cliente ter selecionado os CDs da lista apresentada e clicar no botão Adicionar ao carrinho (Figura 8), o formulário então é submetido na forma de método POST (linha 48, Listagem 2).

Dessa forma, o Servlet DadosCompraServlet (Listagem 5) executa o método doPost() implementado, recuperando os CDs do catálogo a partir dos identificadores selecionados pelo usuário e cria uma lista de objetos de CDs selecionados pelo usuário, colocando-os na sessão do usuário (linha 21). Finalmente, redireciona a requisição para o arquivo HTML que contém o formulário (Listagem 6).

Página que exibe o catálogo dos CDs
Figura 8. Página que exibe o catálogo dos CDs.
Listagem 5. Servlet que exibe o formulário para o preenchimento dos dados de compra.

 package lojavirtual;

 ...

 @SuppressWarnings("serial")

 public class DadosCompraServlet extends HttpServlet {



   @Override

   protected void doPost(HttpServletRequest req, HttpServletResponse resp)

     throws ServletException, IOException {



     //recupera os codigos dos cds selecionados

     String[] codigosCds = req.getParameterValues("chkCodigosCds");

               

     //recupera os cds do catalogo e adiciona os selecionados nas sessao

     HashMap<Long, CD> mapCds = (HashMap<Long, CD>) getServletContext().getAttribute("catalogoCds");

     List<CD> cdsSelecionados = new ArrayList<CD>();

     for (String codigo : codigosCds) {

       CD cd = mapCds.get(new Long(codigo));

       cdsSelecionados.add(cd);

     }

     HttpSession session = req.getSession();

     session.setAttribute("cdsSelecionados", cdsSelecionados);

               

     //chama a página para o preenchimento dos dados de compra

     req.getRequestDispatcher("dadosCompra.html").forward(req, resp);

   }

 }
Listagem 6. Página HTML contendo o formulário dos dados de compra.

<html>

  <head>

    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

    <title>Loja virtual</title>

  </head>

  <body>

    <h2>Dados de compra:</h2>

    <form name="formDados" action="/LojaVirtual/confirmaDados" method="POST">

      <table>

        <tr>

          <td>Nome:</td>

          <td><input type="text" name="nome"></td>

        </tr>

        <tr>

          <td>Endereço de entrega:</td>

          <td><input type="text" name="endereco"></td>

        </tr>

        <tr>

          <td>Número do cartão:</td>

          <td><input type="text" name="cartao"></td>

        </tr>

      </table>

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

    </form>

  </body>

</html>

Desenvolvendo a página de confirmação dos dados da compra

Ao preencher e enviar os dados de compra (Figura 9) o Servlet ConfirmaDadosServlet é invocado e então o método doPost() é executado (Listagem 7). A implementação dessa parte da aplicação foi modificada, ficando o Servlet atuando como controlador, recuperando os dados de compra da requisição, construindo o JavaBean Usuario, calculando o total e enviando a requisição para a página confirmaDados.jsp (Listagem 8), passando o usuário e o total da compra como atributos do objeto request. A classe Usuario foi criada na intenção de agrupar os dados do usuário da compra e também para ilustrar o uso da tag javabean.

A página confirmaDados.jsp então monta a página com os dados de confirmação (Figura 10). Para a montagem dos dados do usuário, a página confirmaDados.jsp utiliza o JavaBean Usuario construído pelo Servlet através das tags <jsp:useBean> e <jsp:getProperty>. Para a construção da tabela com os CDs selecionados na compra a página catalogoCdsInclude.jsp é incluída. Os atributos listaCds e listaEditavel no request são preenchidos respectivamente com a lista de cds recuperada da sessão do usuário e false. Por fim, o valor do total da compra é impresso simplesmente através da recuperação do valor no objeto request.

Página que exibe o formulário dos dados de compra
Figura 9. Página que exibe o formulário dos dados de compra.
Página de confirmação da compra
Figura 10. Página de confirmação da compra.
Listagem 7. Servlet que exibe a tela de confirmação de dados.

 package lojavirtual;

 …

 public class ConfirmaDadosServlet extends HttpServlet {


   @Override

   protected void doPost(HttpServletRequest req, HttpServletResponse resp)

     throws ServletException, IOException {



     //recupera os dados de compra

     String nome = req.getParameter("nome");

     String endereco = req.getParameter("endereco");

     String cartao = req.getParameter("cartao");

               

     //cria o objeto usuario

     Usuario usuario = new Usuario();

     usuario.setNome(nome);

     usuario.setEndereco(endereco);

     usuario.setNumeroCartao(cartao);

               

     //calcula o total

     List<CD> cdsSelecionados = (List<CD>) req.getSession().getAttribute("cdsSelecionados");

     double total = 0;

     for (CD cd : cdsSelecionados) {

       total += cd.getPreco();

     }



     req.setAttribute("usuario", usuario);

     req.setAttribute("total", total);

               

     req.getRequestDispatcher("confirmaDados.jsp").forward(req, resp);

   }

 }
Listagem 8. Página JSP que constrói a tela de confirmação dos dados de compra.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"

    pageEncoding="ISO-8859-1"

    import="java.util.List, lojavirtual.CD"

    %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

  <jsp:useBean id="usuario" class="lojavirtual.Usuario" scope="request"></jsp:useBean>

  <head>

    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

  </head>

  <body>

    <h2>Confirmação dos dados</h2>

        

    <table>

      <tr>

        <td>Nome:</td>

        <td><jsp:getProperty name="usuario" property="nome"/></td>

      </tr>

      <tr>

        <td>Endereço:</td>

        <td><jsp:getProperty name="usuario" property="endereco"/></td>

      </tr>

      <tr>

        <td>Número do cartão:</td>

        <td><jsp:getProperty name="usuario" property="numeroCartao"/></td>

      </tr>

    </table>

    <br><b>Lista de Cds</b>

    <%

      List<CD> cdsSelecionados = (List<CD>) request.getSession().getAttribute("cdsSelecionados");

      request.setAttribute("listaCds", cdsSelecionados);

      request.setAttribute("listaEditavel", false);

    %>

    <jsp:include page="catalogoCdsInclude.jsp"></jsp:include>

      Total da compra: <%=request.getAttribute("total") %>

    <br><br><input type="submit" value="Confirmar dados">                       

  </body>

</html>

Executando a aplicação

Para executar a aplicação devemos primeiramente iniciar o servidor, bastando para isso acessar a aba Servers e iniciar o servidor Tomcat (Figura 11). Uma vez o servidor iniciado, digite a URL http://localhost:8080/LojaVirtualJSP/ em um browser. A página inicial será exibida (index.html). O Eclipse também oferece a possibilidade de iniciar o servidor em modo debug, de forma a depurar a aplicação.

Em todo o processo de desenvolvimento, é necessário muitas vezes parar o servidor para efetuar as alterações. De uma forma geral, o container detecta automaticamente alterações em páginas estáticas (HTMLs, javascripts, estilos, imagens, etc.) e JSPs. Entretanto, para alterações em classes (Servlets, classes de negócio) e bibliotecas externas é desejável restartar o servidor (parar e iniciar novamente) para refletir na aplicação.

Iniciando o servidor Tomcat
Figura 11. Iniciando o servidor Tomcat.
Conclusões

Para desenvolver uma aplicação web de forma sustentável, é desejável seguir uma arquitetura MVC, que separa bem as responsabilidades de visão, modelo e controle, facilitando assim o entendimento, reuso e a manutenção dessas aplicações. Os conceitos de JSP e Tag Libraries são fundamentais para a construção da camada de visão, deixando para os servlets e classes de negócio as responsabilidades de controle e regras de negócio.

Esse artigo apresentou a estrutura de arquivos JSP, sua sintaxe e ciclo de vida, e o conceito da inclusão de Tag Libraries, enfatizando a especificação JSTL, a fim de incrementar a reusabilidade e manutenibilidade de aplicações. O funcionamento desses conceitos é ilustrado através de um exemplo, onde a aplicação desenvolvida utilizando apenas servlets no artigo anterior é melhorada através do uso do Modelo 2 de arquitetura JSP. Essa arquitetura aprimora a estrutura da aplicação, deixando o servlet atuando como controlador, JSP/Tag libraries na parte de apresentação e os javabeans na parte de modelo.

Notas

Timestamp: É uma sequência de caracteres, denotando a data e/ou hora (tempo) no qual certo evento ocorreu. Esta data é frequentemente apresentada em um formato consistente, permitindo uma fácil comparação de dois registros diferentes, e possibilitando seguir de perto a ocorrência dos eventos a medida que o tempo avança. A prática de armazenar timestamps de uma maneira consistente junto com os dados atuais é chamado de timestamping.

Timestamps são tipicamente usados para registrar eventos. Assim, cada evento armazenado em um log é marcado com um timestamp. Em sistemas de arquivos, timestamps podem significar o armazenamento da data/hora de criação ou modificação de um arquivo.

Links

Saiu na DevMedia!

  • eXtreme Programming na prática:
    Vamos bater um papo sobre a eXtreme Programming (XP) para responder algumas das dúvidas mais comuns que surgem quando se está buscando uma metodologia ágil para usar em seus projetos.
  • Primeiros passos no Python:
    Abordaremos como o Python é utilizado no mundo real e quais são as áreas de desenvolvimento nas quais essa linguagem mais se destaca, tais como desenvolvimento web, Big Data e inteligência artificial/aprendizado de máquina (machine learning).

Saiba mais sobre Java ;)

  • Programador Java:
    Aprender Java não é uma tarefa simples, mas seguindo a ordem proposta nesse Guia, você evitará muitas confusões e perdas de tempo no seu aprendizado. Vem aprender java de verdade, vem!
  • Revista Java Magazine Edição 67