Skip to content

3. Noções básicas de desenvolvimento web em Java

Abordaremos agora o desenvolvimento de aplicativos web dinâmicos, c.a.d. São aplicativos nos quais as páginas HTML enviadas ao usuário são geradas por programas.

3.1. Criação de um projeto web no Eclipse

Vamos desenvolver uma primeira aplicação web com o Eclipse/Tomcat. Seguiremos uma abordagem semelhante à utilizada para criar uma aplicação web sem o Eclipse. Com o Eclipse aberto, criamos um novo projeto:

Image

que definimos como um projeto web dinâmico:

Image

Na primeira página do assistente de criação, especificamos o nome do projeto [1] e seu local [2]:

Image

Na segunda página do assistente, aceitamos os valores padrão:

Image

A última página do assistente solicita que definamos o contexto [3] do aplicativo:

Image

Assim que o assistente for validado por [Finish], o Eclipse se conecta ao site [http://java.sun.com] para recuperar alguns documentos que deseja armazenar em cache, a fim de evitar acessos desnecessários à rede. Em seguida, é solicitada uma autorização de licença:

Image

Aceita-se a solicitação. O Eclipse cria o projeto web. Para exibi-lo, ele utiliza um ambiente, chamado de perspectiva, diferente daquele usado para um projeto Java clássico:

Image

A perspectiva associada a um projeto web é a perspectiva J2EE. Aceitamos para ver... O resultado obtido é o seguinte:

Image

A perspectiva J2EE é, na verdade, desnecessariamente complexa para projetos web simples. Nesse caso, a perspectiva Java é suficiente. Para obtê-la, usamos a opção [Window -> Open perspective -> Java]:

Image

src: conterá o código Java das classes do aplicativo, bem como os arquivos que devem estar no Classpath do aplicativo.

build/classes (não representado): conterá os arquivos .class das classes compiladas, bem como uma cópia de todos os arquivos que não sejam .java localizados em src. Uma aplicação web frequentemente utiliza arquivos chamados de “recursos”, que devem estar no Classpath da aplicação, o c.a.d. O conjunto de pastas que são exploradas pelo JVM quando a aplicação faz referência a uma classe, seja durante a compilação, seja durante a execução. O Eclipse garante que a pasta build/classes faça parte do c web. Os arquivos “recursos” são colocados na pasta src, sabendo-se que o Eclipse os copiará automaticamente para build/classes.

WebContent: conterá os recursos da aplicação web que não precisam estar no Classpath da aplicação.

WEB-INF/lib: conterá os arquivos .jar necessários para a aplicação web.

Vamos examinar o conteúdo do arquivo [WEB-INF/web.xml], que configura a aplicação [personne]:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>    personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Já nos deparamos com esse tipo de configuração quando estudamos a criação de páginas iniciais no parágrafo 2.3.4. Esse arquivo nada mais faz do que definir uma série de páginas iniciais. Manteremos apenas a primeira. O arquivo [web.xml] fica da seguinte forma:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

O conteúdo do arquivo XML acima deve obedecer às regras de sintaxe definidas no arquivo indicado pelo atributo [xsi:schemaLocation] da tag de abertura <web-app>. Esse arquivo é, neste caso, o [http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd]. Trata-se de um arquivo XML que pode ser acessado diretamente por meio de um navegador. Se o navegador for suficientemente recente, ele exibirá um arquivo XML:

Image

O Eclipse tentará verificar a validade do documento XML usando o arquivo .xsd especificado no atributo [xsi:schemaLocation] da tag de abertura <web-app>. Para isso, ele fará um acesso à rede. Se o seu computador estiver em uma rede privada, será necessário indicar ao Eclipse o servidor a ser utilizado para sair da rede privada, chamado de proxy HTTP. Isso é feito com a opção [Window -> Preferences -> Internet]:

Image

Marque a opção (1) se estiver em uma rede privada. Em (2), indique o nome do servidor que hospeda o proxy HTTP e, em (3), a porta de escuta desse proxy. Por fim, em (4), indique os computadores para os quais não é necessário passar pelo proxy, ou seja, aqueles que estão na mesma rede privada que o computador com o qual você está trabalhando.

Vamos agora criar o arquivo [index.html] da página inicial.

3.2. Criação de uma página inicial

Clicamos com o botão direito do mouse na pasta [WebContent] e selecionamos a opção [New -> Other]:

Image

Escolhemos o tipo [HTML] e transformamos [Next] em ->

Image

Acima, selecionamos a pasta pai [WebContent] em (1) ou em (2) e, em seguida, especificamos em (3) o nome do arquivo a ser criado. Feito isso, passamos para a próxima página do assistente:

Image

Com (1), podemos gerar um arquivo HTML pré-preenchido com (2). Se desmarcarmos (1), geramos um arquivo HTML vazio. Mantemos a opção (1) marcada para obter um esboço de código. Concluímos o assistente com [Finish]. O arquivo [index.html] é então criado:

Image

com o seguinte conteúdo:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

Modificamos esse arquivo da seguinte maneira:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Application personne</title>
</head>
<body>
Application personne active...
<br>
<br>
Vous êtes sur la page d'accueil
</body>
</html>

3.3. Teste da página inicial

Se ela não estiver presente, vamos exibir a visualização [Servers] com a opção [Window - > Show View -> Other -> Servers] e, em seguida, clicar com o botão direito do mouse no servidor Tomcat 5.5:

Image

A opção [Add and Remove Objects] acima permite adicionar ou remover aplicativos web do servidor Tomcat:

Image

Os projetos web reconhecidos pelo Eclipse são exibidos em (1). É possível registrá-los no servidor Tomcat por meio de (2). As aplicações web registradas no servidor Tomcat aparecem em (4). É possível cancelar o registro delas com (3). Vamos registrar o projeto [personne]:

Image

e, em seguida, conclua o assistente de registro com [Finish]. A visualização [Servers] mostra que o projeto [personne] foi registrado no Tomcat:

Image

Agora, vamos iniciar o servidor Tomcat:

Vamos abrir o navegador da web:

Image

e, em seguida, acessemos a URL [http://localhost:8080/personne]. Essa URL corresponde à raiz do aplicativo web. Nenhum documento é solicitado. Nesse caso, é exibida a página inicial do aplicativo. Se ela não existir, será exibida uma mensagem de erro. Aqui, a página inicial existe. Trata-se do arquivo [index.html] que criamos anteriormente. O resultado obtido é o seguinte:

Image

Está de acordo com o esperado. Agora, vamos usar um navegador externo ao Eclipse e acessar a mesma URL:

Image

A aplicação web [personne] é, portanto, reconhecida também fora do Eclipse.

3.4. Criação de um formulário HTML

Agora, criamos um documento estático HTML [formulaire.html] na pasta [personne]:

Image

Para criá-lo, seguiremos o procedimento descrito no parágrafo 3.2, página 33. Seu conteúdo será o seguinte:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Personne - formulaire</title>
</head>
<body>
  <center>
    <h2>Personne - formulaire</h2>
    <hr>
    <form action="" method="post">
    <table>
      <tr>
        <td>Nom</td>
        <td><input name="txtNom" value="" type="text" size="20"></td>
      </tr>
      <tr>
        <td>Age</td>
        <td><input name="txtAge" value="" type="text" size="3"></td>
      </tr>
    </table>
    <table>
      <tr>
        <td><input type="submit" value="Envoyer"></td>
        <td><input type="reset" value="Retablir"></td>
        <td><input type="button" value="Effacer"></td>
      </tr>
    </table>
    </form>
  </center>
</body>
</html>

O código HTML acima corresponde ao formulário abaixo:

Image

tipo HTML
nome
código HTML
função
1
<input type="text">
txtNom
linha 14
inserção do nome
2
<input type="text">
txtAge
linha 18
inserção da idade
3
<input type="submit">
 
linha 23
envio dos valores inseridos ao servidor na URL /pessoa1/main
4
<input type="reset">
 
linha 24
para restaurar a página ao estado em que foi recebida inicialmente pelo navegador
5
<input type="button">
 
linha 25
para limpar o conteúdo dos campos de entrada [1] e [2]

Vamos salvar o documento na pasta <pessoa>/WebContent. Iniciemos o Tomcat, se necessário. Com um navegador, acessemos a página URL http://localhost:8080/personne/formulaire.html:

Image

A arquitetura cliente/servidor desta aplicação básica é a seguinte:

Image

O servidor web fica entre o usuário e o aplicativo web e não foi representado aqui. [formulaire.html] é um documento estático que fornece o mesmo conteúdo a cada solicitação do cliente. A programação web tem como objetivo gerar conteúdo adaptado à solicitação do cliente. Esse conteúdo é, então, gerado por programa. Uma primeira solução é utilizar uma página JSP (Java Server Page) em vez do arquivo estático HTML. É isso que veremos agora.

3.5. Criação de uma página JSP


Leituras [ref1]: capítulo 1, capítulo 2: 2.2, 2.2.1, 2.2.2, 2.2.3, 2.2.4


A arquitetura cliente/servidor anterior é transformada da seguinte forma:

Image

Uma página JSP é uma variante configurada da página HTML. Alguns elementos da página só recebem seus valores no momento da execução. Esses valores são calculados pelo programa. Portanto, temos uma página dinâmica: solicitações sucessivas à página podem gerar respostas diferentes. Chamamos aqui de resposta a página HTML exibida pelo navegador do cliente. No final, é sempre um documento HTML que o navegador recebe. Esse documento HTML é gerado pelo servidor web a partir da página JSP. Esta última serve de modelo. Seus elementos dinâmicos são substituídos por seus valores efetivos no momento da geração do documento HTML.

Para criar uma página JSP, clicamos com o botão direito do mouse na pasta [WebContent] e selecionamos a opção [New -> Other]:

Image

Escolhemos o tipo [JSP] e fazemos [Next] ->

Image

Acima, selecionamos a pasta pai [WebContent] em (1) ou em (2) e, em seguida, especificamos em (3) o nome do arquivo a ser criado. Feito isso, passamos para a próxima página do assistente:

Image

Com (1), podemos gerar um arquivo JSP pré-preenchido com (2). Se desmarcarmos (1), geramos um arquivo JSP vazio. Mantemos a opção (1) marcada para obter um esboço de código. Concluímos o assistente com [Finish]. O arquivo [formulaire.jsp] é então criado:

Image

com o seguinte conteúdo:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

A linha 1 indica que estamos lidando com uma página JSP. Transformamos o texto acima da seguinte maneira:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // recuperam-se os parâmetros
  String nom=request.getParameter("txtNom");
  if(nom==null) nom="inconnu";
  String age=request.getParameter("txtAge");
  if(age==null) age="xxx";  
%>

<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title>Personne - formulaire</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire</h2>
      <hr>
      <form action="" method="post">
          <table>
            <tr>
              <td>Nom</td>
            <td><input name="txtNom" value="<%= nom %>" type="text" size="20"></td>
          </tr>
          <tr>
              <td>Age</td>
            <td><input name="txtAge" value="<%= age %>" type="text" size="3"></td>
          </tr>
        </table>
        <table>
            <tr>
              <td><input type="submit" value="Envoyer"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="Effacer"></td>
          </tr>
        </table>
      </form>
    </center>
  </body>
</html>

O documento, inicialmente estático, tornou-se agora dinâmico com a introdução de código Java. Para esse tipo de documento, sempre procederemos da seguinte forma:

  • inserimos código Java logo no início do documento para recuperar os parâmetros necessários à sua exibição. Esses parâmetros geralmente estarão no objeto `request`. Esse objeto representa a solicitação do cliente. Ela pode passar por vários servlets e páginas JSP que possam tê-la enriquecido. Aqui, ela chegará diretamente do navegador.
  • O código HTML vem a seguir. Na maioria das vezes, ele se limitará a exibir variáveis calculadas anteriormente no código Java por meio das tags <%= variável %>. Observe aqui que o sinal = está colado ao sinal %. Essa é uma causa frequente de erros.

O que faz o documento dinâmico anterior?

  • linhas 6-9: ele recupera da solicitação dois parâmetros chamados [txtNom] e [txtAge] e atribui seus valores às variáveis [nom] (linha 6) e [age] (linha 8). Caso não encontre os parâmetros, ele atribui valores padrão às variáveis associadas.
  • Ele exibe o valor das duas variáveis [nom, age] no código HTML a seguir (linhas 25 e 29).

Vamos fazer um primeiro teste. Inicie o Tomcat, se necessário, e, em seguida, usando um navegador, acesse o endereço http://localhost:8080/personne/formulaire.jsp:

Image

O documento formulaire.jsp foi chamado sem a passagem de parâmetros. Portanto, os valores padrão foram exibidos. Agora, vamos solicitar o URL http://localhost:8080/personne/formulaire.jsp?txtNom=martin&txtAge=14:

Image

Desta vez, passamos para o documento formulaire.jsp os parâmetros txtNom e txtAge que ele esperava. Assim, ele os exibiu. Sabemos que existem dois métodos para passar parâmetros a um documento da web: GET e POST. Em ambos os casos, os parâmetros passados são encontrados no objeto predefinido **request**. Aqui, eles foram passados pelo método GET.

3.6. Criação de um servlet


Leituras [ref1]: capítulo 1, capítulo 2: 2.1, 2.1.1, 2.1.2, 2.3.1


Na versão anterior, a solicitação do cliente era processada por uma página JSP. Na primeira chamada a essa página, o servidor web — neste caso, o Tomcat — cria uma classe Java a partir dela e a compila. É o resultado dessa compilação que, por fim, processa a solicitação do cliente. A classe gerada a partir da página JSP é um servlet porque implementa a interface [javax.Servlet]:

Image

A solicitação do cliente pode ser processada por qualquer classe que implemente essa interface. Agora, criamos uma classe desse tipo: ServletFormulaire. A arquitetura cliente/servidor anterior é transformada da seguinte forma:

Image

Com a arquitetura baseada na página JSP, o documento HTML enviado ao cliente era gerado pelo servidor web a partir da página JSP, que servia de modelo. Nesse caso, o documento HTML enviado ao cliente será inteiramente gerado pelo servlet.

3.6.1. Criação do servlet

No Eclipse, clique com o botão direito do mouse na pasta [src] e selecione a opção para criar uma classe:

Image

em seguida, definamos as características da classe a ser criada:

Image

Em (1), insira o nome do pacote; em (2), o nome da classe a ser criada. Esta deve derivar da classe indicada em (3). Não é necessário digitar manualmente o nome completo desta. O botão (4) permite acessar as classes atualmente presentes no Classpath do aplicativo web:

Image

Em (1), digite o nome da classe procurada. Em (2), são exibidas as classes do Classpath cujo nome contém a sequência digitada em (1).

Após a validação do assistente de criação, o projeto web [personne] é alterado da seguinte forma:

Image

A classe [ServletFormulaire] foi criada com um esboço de código:

Image

A captura de tela acima mostra que o Eclipse sinaliza um [warning] na linha que declara a classe. Vamos clicar no ícone (lâmpada) que sinaliza esse [warning]:

Image

Após clicar em (1), são apresentadas em (2) soluções para remover o [warning]. Ao selecionar uma delas, aparece em (3) a alteração no código que essa escolha irá provocar.

O Java 1.5 trouxe alterações à linguagem Java, e o que era correto em uma versão anterior agora pode ser alvo de [warnings]. Essas notificações não sinalizam erros que possam impedir a compilação da classe. Elas servem para chamar a atenção do desenvolvedor para pontos do código que poderiam ser aprimorados. O [warning] indicado aqui sinaliza que uma classe deve ter um número de versão. Esse número é utilizado para a serialização/desserialização de objetos, c.a.d. quando um objeto Java .class na memória precisa ser transformado em uma sequência de bits enviada sequencialmente em um fluxo de gravação, ou o inverso, quando um objeto Java .class na memória precisa ser criado a partir de uma sequência de bits lida sequencialmente em um fluxo de leitura. Tudo isso está muito distante de nossas preocupações atuais. Portanto, vamos pedir ao compilador para ignorar esse aviso, escolhendo a solução [Add @SuppressWarnings ...]. O código passa a ser o seguinte:

Image

Não há mais [warning]. A linha adicionada é chamada de “anotação”, um conceito que surgiu com o Java 1.5. Completaremos esse código posteriormente.

3.6.2. Classpath de um projeto Eclipse

O Classpath de um aplicativo Java é o conjunto de pastas e archives.jar exploradas quando o compilador o compila ou quando o JVM o executa. Esses dois Classpath não são necessariamente idênticos, pois algumas classes são úteis apenas na execução e não na compilação. Tanto o compilador Java quanto o JVM possuem um argumento que permite especificar o Classpath da aplicação a ser compilada ou executada. De forma mais ou menos transparente para o usuário, o Eclipse garante a construção e a passagem desse argumento para o JVM.

Como é possível conhecer os elementos do Classpath de um projeto do Eclipse? Com a opção [<projet> / Build Path / Configure Build Path]:

Image

Assim, obtemos o seguinte assistente de configuração:

Image

A guia (1) [Libraries] permite definir a lista de arquivos .jar que fazem parte do Classpath do aplicativo. Assim, eles são explorados pelo JVM quando o aplicativo solicita uma classe. Os botões [2] e [3] permitem adicionar arquivos ao Classpath. O botão [2] permite selecionar arquivos presentes nas pastas dos projetos gerenciados pelo Eclipse, enquanto o botão [3] permite selecionar qualquer arquivo do sistema de arquivos do computador.

Acima, aparecem três bibliotecas (Libraries):

  • [JRE System Library]: biblioteca básica para projetos Java do Eclipse:

Image

  • [Tomcat v5.5 runtime]: biblioteca fornecida pelo servidor Tomcat. Ela contém as classes necessárias para o desenvolvimento web. Essa biblioteca está incluída em todos os projetos web do Eclipse que tenham sido associados ao servidor Tomcat.

Image

É o arquivo [servlet-api.jar] que contém a classe [javax.servlet.http.HttpServlet], classe pai da classe [ServletFormulaire] que estamos criando. É por estar esse arquivo no Classpath do aplicativo que ele pôde ser sugerido como classe pai no assistente mostrado abaixo.

Image

Se não fosse esse o caso, ela não teria aparecido entre as sugestões para [2]. Portanto, se nesse assistente quisermos referenciar uma classe pai e ela não for sugerida, isso significa que, ou estamos digitando o nome dessa classe incorretamente, ou o arquivo que a contém não está no Classpath do aplicativo.

  • O [Web App Libraries] reúne os arquivos presentes na pasta [WEB-INF/lib] do projeto. Aqui, ele está vazio:

Image

Os arquivos do Classpath do projeto Eclipse estão presentes no explorador de projetos. Por exemplo, para o projeto web [personne]:

Image

O explorador de projetos nos dá acesso ao conteúdo desses arquivos:

Image

Assim, como mostrado acima, podemos ver que é o arquivo [servlet-api.jar] que contém a classe [javax.servlet.http.HttpServlet].

3.6.3. Configuração do servlet


Leituras [ref1]: capítulo 2: 2.3, 2.3.1, 2.3.2, 2.3.3, 2.3.4


O arquivo [WEB-INF/web.xml] serve para configurar a aplicação web:

Image

Este arquivo, para o projeto [personne], está atualmente da seguinte forma (ver página 32):


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Ele indica apenas a existência de um arquivo de página inicial (linha 8). Vamos atualizá-lo para declarar:

  • a existência do servlet [ServletFormulaire]
  • os URL processados por essa servlet
  • os parâmetros de inicialização do servlet

O arquivo web.xml de nossa aplicação “pessoa” ficará da seguinte forma:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Os pontos principais desse arquivo de configuração são os seguintes:

  • as linhas 7 a 24 estão relacionadas à presença do servlet [ServletFormulaire]
  • linhas 7-20: a configuração de um servlet é feita entre as tags <servlet> e </servlet>. Um aplicativo pode conter vários servlets e, portanto, tantas seções de configuração <servlet>...</servlet>.
  • linha 8: a tag <servlet-name> define um nome para o servlet — pode ser qualquer um
  • linhas 9-11: a tag <servlet-class> indica o nome completo da classe correspondente ao servlet. O Tomcat irá procurar essa classe no Classpath do projeto web [personne]. Ele a encontrará em [build/classes]:

Image

  • linhas 12-15: a tag <init-param> serve para passar parâmetros de configuração para o servlet. Esses parâmetros são geralmente lidos no método init do servlet, pois os parâmetros de configuração deste devem ser conhecidos logo no seu primeiro carregamento.
  • linhas 13-14: a tag <param-name> define o nome do parâmetro e <param-value> define seu valor.
  • as linhas 12-15 definem um parâmetro [defaultNom,"inconnu"] e as linhas 16-19, um parâmetro [defaultAge,"XXX"]
  • linhas 21-24: a tag <servlet-mapping> serve para associar um servlet (servlet-name) a um modelo de URL (url-pattern). Aqui, o padrão é simples. Ele determina que, sempre que um URL tiver o formato /formulário, deverá ser utilizado o servlet formulário-pessoa, c.a.d, da classe [istia.st.servlets.ServletFormulaire] (linhas 8 a 11). Portanto, há apenas uma URL aceita pelo servlet [formulairepersonne].

3.6.4. O código do servlet [ServletFormulaire]

O servlet [ServletFormulaire] terá o seguinte código:

package istia.st.servlets.personne;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ServletFormulaire extends HttpServlet {

     // parâmetros de instância
    private String defaultNom = null;
    private String defaultAge = null;

     // inicialização
    public void init() {
         // recuperam-se os parâmetros de inicialização do servlet
        ServletConfig config = getServletConfig();
        defaultNom = config.getInitParameter("defaultNom");
        if (defaultNom == null)
            defaultNom = "NNNNNNNNNNNNNNN";
        defaultAge = config.getInitParameter("defaultAge");
        if (defaultAge == null)
            defaultAge = "AAA";
    }

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // recupera-se os parâmetros do formulário
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
         // exibe o formulário
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println(
                "<html>"+
                  "<head>"+
                    "<title>Personne - formulaire</title>"+
                  "</head>"+
                  "<body>"+
                    "<center>"+
                      "<h2>Personne - formulaire</h2>"+
                      "<hr>"+
                      "<form action='' method='post'>"+
                        "<table>"+
                          "<tr>"+
                            "<td>Nom</td>"+
                            "<td><input name='txtNom' value='"+nom+"' type='text' size='20'></td>"+
                          "</tr>"+
                          "<tr>"+
                            "<td>Age</td>"+
                            "<td><input name='txtAge' value='"+ age +"' type='text' size='3'></td>"+
                          "</tr>"+
                        "</table>"+
                        "<table>"+
                          "<tr>"+
                            "<td><input type='submit' value='Envoyer'></td>"+
                            "<td><input type='reset' value='Rétablir'></td>"+
                            "<td><input type='button' value='Effacer'></td>"+
                          "</tr>"+
                        "</table>"+
                      "</form>"+
                    "</center>"+
                  "</body>"+
                "</html>"
      );
    }

     // POST
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // passa o controle para o GET
        doGet(request, response);
    }
}

Ao analisar a servlet, percebe-se que ela é muito mais complexa do que a página JSP correspondente. Trata-se de uma regra geral: uma servlet não é adequada para gerar código HTML. São as páginas JSP que foram criadas para isso. Teremos a oportunidade de voltar a esse assunto. Vamos explicar alguns pontos importantes da servlet acima:

  • quando uma servlet é chamada pela primeira vez, seu método init (linha 20) é chamado. Esse é o único caso em que ele é chamado.
  • Se a servlet tiver sido chamada pelo método HTTP GET, o método doGet (linha 32) é chamado para processar a solicitação do cliente.
  • Se o servlet tiver sido chamado pelo método HTTP POST, o método doPost (linha 82) é chamado para processar a solicitação do cliente.

O método init serve aqui para recuperar, no [web.xml], os valores dos parâmetros de inicialização denominados “defaultNom” e “defaultAge”. O método init, executado no carregamento inicial do servlet, é o local adequado para recuperar o conteúdo do arquivo [web.xml].

  • linha 22: a configuração [config] do projeto web é recuperada. Esse objeto reflete o conteúdo do arquivo [WEB-INF/web.xml] do aplicativo.
  • linha 23: nesta configuração, recupera-se o valor do tipo String do parâmetro chamado “defaultNom”. Esse parâmetro terá como valor o nome de uma pessoa. Caso ele não exista, será obtido o valor null.
  • linhas 24-25: se o parâmetro chamado “defaultNom” não existir, atribui-se um valor padrão à variável [defaultNom].
  • linhas 26-29: faz-se o mesmo para o parâmetro chamado “defaultAge”.

O método doPost remete ao método doGet. Isso significa que o cliente poderá enviar seus parâmetros tanto por meio de um POST quanto de um GET.

O método doGet:

  • linha 32: o método recebe dois parâmetros, request e response. request é um objeto que representa a solicitação completa do cliente. É do tipo HttpServletRequest, que é uma interface. response é do tipo HttpServletResponse, que também é uma interface. O objeto response serve para enviar uma resposta ao cliente.
  • request.getParameter("param") serve para recuperar, na solicitação do cliente, o valor do parâmetro chamado param. Na linha 36, recupera-se o valor do parâmetro “txtNom”; na linha 40, o valor do parâmetro “txtAge”. Se esses parâmetros não estiverem presentes na solicitação, obtém-se o valor null como valor do parâmetro.
  • linhas 37-39: se o parâmetro “txtNom” não estiver na consulta, atribui-se à variável “nom” o nome padrão “defaultNom”, inicializado no método init. O mesmo procedimento é seguido nas linhas 41-43 para a idade.
  • linha 45: response.setContentType(String) serve para definir o valor do cabeçalho HTTP Content-type. Esse cabeçalho indica ao cliente a natureza do documento que ele receberá. O tipo text/html indica um documento HTML.
  • linha 46: response.getWriter() serve para obter um fluxo de gravação para o cliente
  • linhas 47-78: escreve-se o documento HTML a ser enviado ao cliente no fluxo de gravação obtido na linha 46.

A compilação deste servlet produzirá um arquivo .class na pasta [build/classes] do projeto [personne]:

Image

Recomenda-se ao leitor que consulte a documentação do Java sobre servlets. Para isso, pode-se utilizar o Tomcat. Na página inicial do Tomcat 5, há um link [Documentation]:

Image

Esse link leva a uma página que o leitor é convidado a explorar. O link para a documentação sobre servlets é o seguinte:

Image

3.6.5. Teste do servlet

Estamos prontos para fazer um teste. Vamos iniciar o servidor Tomcat, se necessário.

Image

Em seguida, acessemos com um navegador o URL [http://localhost:8080/personne/formulaire]. Aqui, estamos acessando a URL [/formulaire] do contexto [/personne]. O arquivo [web.xml] desse contexto indica que a URL [/formulaire] é processada pelo servlet de nome [formulairepersonne]. No mesmo arquivo, é indicado que essa servlet é a classe [istia.st.servlets.ServletFormulaire]. Portanto, é a essa classe que o Tomcat confiará o processamento da solicitação do cliente. Se a classe ainda não estiver carregada, ela será carregada. Ela permanecerá então na memória para futuras solicitações.

Obtém-se o seguinte resultado com o navegador interno do Eclipse:

Image

Recebemos os valores padrão para nome e idade, aqueles registrados no arquivo [web.xml]. Agora, vamos solicitar o URL [http://localhost:8080/personne/formulaire?txtNom=tintin&txtAge=30]:

Image

Desta vez, obtemos os parâmetros passados na solicitação. Recomenda-se que o leitor releia o código do servlet [ServletFormulaire] caso não compreenda esses dois resultados.

3.6.6. Recarregamento automático do contexto da aplicação web

Vamos iniciar o Tomcat:

Image

e, em seguida, vamos modificar o código do servlet da seguinte maneira:

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // recuperam-se os parâmetros do formulário
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = "--"+defaultNom+"--";
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
...
  • a linha 8 foi alterada

Vamos salvar a nova classe. Esse salvamento fará com que o Eclipse recompile automaticamente a classe [ServletFormulaire], o que será detectado pelo Tomcat. Em seguida, ele recarregará o contexto da aplicação web [personne] para incorporar as alterações. Isso aparece nos logs da visualização [console]:

Image

Vamos acessar a URL [http://localhost:8080/personne/formulaire] sem reiniciar o Tomcat:

Image

A alteração feita foi efetivamente aplicada.

Agora, vamos modificar o arquivo [web.xml] da seguinte maneira:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
...
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>INCONNU</param-value>
        </init-param>
...
    </servlet>
...
</web-app>
  • a linha 12 foi alterada

Feito isso, vamos salvar o novo arquivo [web.xml]. Na visualização [console], nenhum registro indica a recarga do contexto da aplicação. Vamos acessar a URL [http://localhost:8080/personne/formulaire] sem reiniciar o Tomcat:

Image

A alteração feita não foi refletida. Vamos reiniciar o Tomcat [clic droit sur serveur -> Restart -> Start]:

Image

e, em seguida, acessemos novamente a URL [http://localhost:8080/personne/formulaire]:

Image

Desta vez, a alteração feita em [web.xml] está visível.

Portanto, uma alteração em [web.xml] não provoca uma recarga automática do aplicativo que levaria em conta o novo arquivo de configuração. Para forçar a recarga do aplicativo web, podemos reiniciar o Tomcat como fizemos, mas essa é uma operação bastante lenta. É preferível utilizar a ferramenta [manager] para administração de aplicativos implantados no Tomcat. Para que isso seja possível, é necessário que, no Eclipse, o Tomcat tenha sido configurado conforme mostrado no parágrafo 2.5.

Primeiro, usando o navegador interno do Eclipse, acessemos a URL [http://localhost:8080] e, em seguida, sigamos o link [Tomcat Manager], conforme explicado no final do parágrafo 2.5:

Image

Vamos abrir um segundo navegador [clic droit sur le navigateur -> New Editor]:

Nesta segunda janela do navegador, acessemos a URL [http://localhost:8080/formulaire]:

Image

Vamos modificar o arquivo [web.xml] da seguinte maneira e, em seguida, salvá-lo:


<!--   ServletFormulaire -->
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>YYY</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>

Em seguida, solicitemos novamente a URL [http://localhost:8080/formulaire]. Podemos observar que a alteração não foi aplicada. Agora, vamos ao primeiro navegador e recarregamos o aplicativo [personne]:

Image

Em seguida, acessemos novamente a URL [http://localhost:8080/formulaire] com o segundo navegador:

Image

A alteração em [web.xml] foi aplicada. Na prática, é útil ter um navegador aberto na aplicação [manager] do Tomcat para lidar com esse tipo de situação.

3.7. Cooperação entre servlet e páginas JSP


Leituras [ref1]: capítulo 2: 2.3.7


Voltemos às duas arquiteturas estudadas:

Image

Nenhuma dessas duas arquiteturas é satisfatória. Ambas apresentam a desvantagem de misturar duas tecnologias: a programação Java, que lida com a lógica do aplicativo web, e a codificação HTML, que lida com a apresentação de informações em um navegador.

  • A solução [1] baseada na página JSP tem a desvantagem de misturar código HTML e código Java dentro de uma mesma página. Não observamos isso no exemplo analisado, que era básico. Mas se [formulaire.jsp] precisasse verificar a validade dos parâmetros [txtNom, txtAge] da solicitação do cliente, seríamos obrigados a incluir código Java na página. Isso se torna rapidamente incontrolável.
  • A solução [2] baseada em servlet apresenta o mesmo problema. Embora haja apenas código Java na classe, ela precisa gerar um documento HTML. Mais uma vez, a menos que o documento HTML seja básico, sua geração se torna complicada e praticamente impossível de manter.

Vamos evitar a mistura das tecnologias Java e HTML adotando a seguinte arquitetura:

Image

  • o usuário envia sua solicitação ao servlet. Este a processa e constrói os valores dos parâmetros dinâmicos da página JSP [formulaire.jsp], que servirão para gerar a resposta HTML para o cliente. Esses valores formam o que é chamado de modelo da página JSP.
  • Assim que concluir seu trabalho, o servlet solicitará que a página JSP [formulaire.jsp] gere a resposta HTML para o cliente. Ao mesmo tempo, ela fornecerá ao cliente os elementos de que a página JSP precisa para gerar essa resposta — esses elementos que formam o modelo da página.

Vamos agora explorar essa nova arquitetura.

3.7.1. O servlet [ServletFormulaire2]

Na arquitetura acima, o servlet se chamará [ServletFormulaire2]. Ele será criado no mesmo projeto [personne] que anteriormente, assim como todos os servlets futuros:

Image

[ServletFormulaire2] é obtida, em primeiro lugar, por meio de copiar/colar de [ServletFormulaire] no Eclipse:

  • selecionar [ServletFormulaire.java] -> clicar com o botão direito -> Copiar
  • selecionar [istia.st.servlets.personne] -> clicar com o botão direito -> Colar -> renomear para [ServletFormulaire2.java]

Em seguida, modificamos o código de [ServletFormulaire2] da seguinte maneira:

package istia.st.servlets.personne;

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ServletFormulaire2 extends HttpServlet {

     // parâmetros de instância
    private String defaultNom = null;

    private String defaultAge = null;

     // inicialização
    public void init() {
         // recupera-se os parâmetros de inicialização do servlet
        ServletConfig config = getServletConfig();
        defaultNom = config.getInitParameter("defaultNom");
        if (defaultNom == null)
            defaultNom = "NNNNNNNNNNNNNNN";
        defaultAge = config.getInitParameter("defaultAge");
        if (defaultAge == null)
            defaultAge = "AAA";
    }

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // recupera-se os parâmetros do formulário
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
         // exibe o formulário
        request.setAttribute("nom", nom);
        request.setAttribute("age", age);
        getServletContext().getRequestDispatcher("/formulaire2.jsp").forward(request, response);
    }

     // POST
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // passamos o controle para o GET
        doGet(request, response);
    }
}

Apenas a parte de geração da resposta HTTP foi alterada (linhas 44-46):

  • linha 46: a geração da resposta é delegada à página JSP formulaire2.jsp. Essa página, que ainda não foi analisada, será responsável por exibir os parâmetros recuperados na solicitação do cliente: um nome (linhas 35-38) e uma idade (linhas 39-42).
  • Esses dois valores são colocados nos atributos da solicitação [request], associados a chaves. Os atributos de uma solicitação são gerenciados como um dicionário.
  • linha 44: o nome é inserido na consulta associado à chave “nome”
  • linha 45: a idade é inserida na consulta associada à chave “idade”
  • linha 46: solicita a exibição da página JSP [formulaire2.jsp]. São passados como parâmetros para ela:
  • a consulta [request] do cliente, o que permitirá que a página JSP tenha acesso aos atributos da consulta, que acabaram de ser inicializados pelo servlet
  • a resposta [response], que permitirá que a página JSP gere a resposta HTTP para o cliente

Depois que a classe [ServletFormulaire2] é escrita, seu código compilado aparece em [build/classes]:

Image

3.7.2. A página JSP [formulaire2.jsp]

A página JSP formulaire2.jsp é obtida por meio de copiar/colar da página [formulaire.jsp]

Image

e, em seguida, transformada da seguinte maneira:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // recupera-se os valores necessários para a exibição
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");  
%>

<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title>Personne - formulaire2</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire2</h2>
      <hr>
      <form action="" method="post">
          <table>
            <tr>
              <td>Nom</td>
            <td><input name="txtNom" value="<%= nom %>" type="text" size="20"></td>
          </tr>
          <tr>
              <td>Age</td>
            <td><input name="txtAge" value="<%= age %>" type="text" size="3"></td>
          </tr>
        </table>
        <table>
            <tr>
              <td><input type="submit" value="Envoyer"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="Effacer"></td>
          </tr>
        </table>
      </form>
    </center>
  </body>
</html>

Apenas as linhas 4 a 8 foram alteradas em relação a [formulaire.jsp]:

  • linha 6: recupera o valor do atributo chamado “nom” na consulta [request], atributo criado pelo servlet [ServletFormulaire2].
  • linha 7: faz o mesmo para o atributo “idade”

3.7.3. Configuração do aplicativo

O arquivo de configuração [web.xml] é modificado da seguinte forma:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <!--  ServletFormulaire -->
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXXX</param-value>
        </init-param>
    </servlet>
     <!--  ServletFormulaire 2-->
    <servlet>
        <servlet-name>formulairepersonne2</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire2
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>
    <!--  Mapeamento ServletFormulaire -->
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
     <!--  Mapeamento ServletFormulaire 2-->
    <servlet-mapping>
        <servlet-name>formulairepersonne2</servlet-name>
        <url-pattern>/formulaire2</url-pattern>
    </servlet-mapping>
    <!--  arquivos de acolhimento -->
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Mantivemos o que já existia e adicionamos:

  • linhas 22-36: uma seção <servlet> para definir o novo servlet ServletFormulaire2
  • linhas 42-46: uma seção <servlet-mapping> para associá-la ao URL /formulário2

Inicie ou reinicie o servidor Tomcat, se necessário. Solicitamos o URL

http://localhost:8080/personne/formulaire2?txtNom=milou&txtAge=10:

Image

Obtemos o mesmo resultado de antes, mas a estrutura da nossa aplicação ficou mais clara: um servlet que contém a lógica de aplicação e delega a uma página JSP o envio da resposta ao cliente. A partir de agora, sempre procederemos dessa maneira.