3. Introdução aos servlets Java e às páginas JSP
Neste capítulo, encontrar-se-ão diversos exemplos de servlets e páginas JSP. Eles foram testados com o servidor Tomcat, que opera na porta 8080. Seguindo os links da página inicial, é possível acessar exemplos de servlets e páginas JSP. A maioria dos exemplos abaixo foi retirada dos exemplos do Tomcat. Para testá-los, basta iniciar o Tomcat, acessar o URL http://localhost:8080 com um navegador e seguir o link dos servlets.
![]() | ![]() |
3.1. Servlets Java
3.1.1. Enviar um conteúdo HTML para um cliente da Web
Analisamos o exemplo “Hello World” acima. O servlet é o seguinte:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorld extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
Ao executar este servlet, obtém-se a seguinte exibição:

Observe os seguintes pontos:
- é necessário importar classes específicas para os servlets:
import javax.servlet.*;
import javax.servlet.http.*;
A biblioteca javax.servlet nem sempre é fornecida por padrão com o JDK. Nesse caso, é possível baixá-la diretamente do site da Sun.
- Um servlet é derivado da classe HttpServlet
public class HelloWorld extends HttpServlet {
- Uma solicitação GET feita ao servlet é processada pelo método doGet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
- Da mesma forma, uma solicitação POST feita ao servlet é processada pelo método doPost
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
- O objeto HttpServletRequest request é o objeto que nos dá acesso à solicitação feita pelo cliente da Web. A resposta do servlet será enviada por meio do objeto HttpServletResponse response
- O objeto response nos permite definir os cabeçalhos HTTP que serão enviados ao cliente. Por exemplo, o cabeçalho Content-type: text/html é definido aqui por:
- Para enviar a resposta ao cliente, o servlet utiliza um fluxo de saída fornecido pelo objeto response:
- Uma vez obtido esse fluxo de saída, o código HTML é gravado nele e, portanto, enviado ao cliente:
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
3.1.2. Recuperar os parâmetros enviados por um cliente web
O exemplo a seguir mostra como um servlet pode recuperar parâmetros enviados pelo cliente web. Um formulário de entrada:

A resposta enviada pelo servlet:

O código-fonte do servlet é o seguinte:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myRequestParamExample extends HttpServlet {
String title="Récupération des paramètres d'un formulaire";
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.println("<P>");
out.print("<form action=\"RequestParamExample\" method=\"POST\">");
out.println("firstname= <input type=text size=20 name=firstname>");
out.println("<br>");
out.println("lastname= <input type=text size=20 name=lastname>");
out.println("<br>");
out.println("<input type=submit>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
Observe as seguintes novidades em relação ao exemplo anterior:
- Os parâmetros enviados pelo navegador são recuperados da seguinte maneira:
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
O método request.getParameter("nomParamètre") retorna o ponteiro null, caso o parâmetro nomParamètre não faça parte dos parâmetros enviados pelo cliente web.
- O formulário especifica que o navegador deve enviar os parâmetros por meio do método POST
- Os parâmetros recebidos serão processados pelo método doPost do servlet. Nesse caso, esse método se limita a chamar o método doGet. Assim, esse servlet processa os valores do formulário, independentemente de terem sido enviados por um GET ou por um POST.
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
3.1.3. Recuperar os cabeçalhos HTTP enviados por um cliente web
O servlet a seguir mostra como recuperar os cabeçalhos HTTP enviados pelo cliente web:

O código-fonte do servlet é o seguinte:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestHeaderExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
Enumeration e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
String value = request.getHeader(name);
out.println(name + " = " + value);
}
}
}
Observações:
- São o objeto request e seu método getHeaderNames que nos dão acesso aos cabeçalhos HTTP enviados pelo navegador na forma de uma enumeração:
- O método request.getHeader("cabeçalho") permite obter um cabeçalho HTTP específico. O exemplo acima apresenta alguns deles. É importante lembrar que os cabeçalhos apresentados aqui são enviados pelo navegador. O servidor também possui seus próprios cabeçalhos HTTP, que às vezes reproduzem os do navegador. Os cabeçalhos HTTP enviados pelo navegador têm como objetivo informar ao servidor sobre as capacidades do navegador.
Header | Significado |
identidade do navegador | |
os formatos MIME aceitos pelo navegador. Assim, image/gif significa que o navegador sabe processar imagens no formato GIF | |
no formato hote:port. Indica qual máquina e qual porta o navegador deseja acessar. | |
formato de codificação aceito pelo navegador para os documentos enviados pelo servidor. Assim, se um servidor tiver um documento em formato normal não compactado e outro no formato compactado gzip, e o navegador tiver indicado que sabe processar o formato gzip, o servidor poderá enviar o documento no formato gzip para economizar largura de banda. | |
idiomas aceitos pelo navegador. Se um servidor tiver o mesmo documento em vários idiomas, ele enviará aquele cujo idioma seja aceito pelo navegador. | |
o URL solicitado pelo navegador | |
o modo de conexão solicitado pelo navegador. Keep-alive significa que o servidor não deve interromper a conexão após enviar a página solicitada ao navegador. Se este último detectar que a página recebida contém links para imagens, por exemplo, poderá fazer novas solicitações ao servidor para obtê-las sem precisar criar uma nova conexão. Será o navegador que tomará a iniciativa de encerrar a conexão assim que tiver recebido todos os elementos da página. |
3.1.4. Recuperar informações do ambiente
O servlet a seguir mostra como acessar informações do ambiente de execução do servlet. Algumas dessas informações são enviadas na forma de cabeçalhos HTTP pelo navegador e, portanto, podem ser recuperadas pelo método anterior.

O código do servlet é o seguinte:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestInfo extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>Request Information Example</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Request Information Example</h3>");
out.println("Method: " + request.getMethod());
out.println("Request URI: " + request.getRequestURI());
out.println("Protocol: " + request.getProtocol());
out.println("PathInfo: " + request.getPathInfo());
out.println("Remote Address: " + request.getRemoteAddr());
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
As informações aqui são obtidas por diversos métodos:
out.println("Method: " + request.getMethod());
out.println("Request URI: " + request.getRequestURI());
out.println("Protocol: " + request.getProtocol());
out.println("PathInfo: " + request.getPathInfo());
out.println("Remote Address: " + request.getRemoteAddr());
Segue abaixo uma lista de alguns dos métodos disponíveis e seus significados:
método | significado |
o nome do servidor web | |
a porta de trabalho do servidor web | |
o método GET ou POST utilizado pelo navegador para realizar sua solicitação | |
o nome do computador cliente a partir do qual o navegador fez a solicitação | |
o endereço IP dessa mesma máquina | |
o tipo de conteúdo enviado pelo navegador (cabeçalho HTTP Content-type) | |
o número de caracteres enviados pelo navegador (cabeçalho HTTP Content-length) | |
a versão do protocolo HTTP solicitada pelo navegador | |
o URI solicitado pelo navegador. Corresponde à parte do URL localizada após a identificação hote:port em http://hote:port/URI |
3.1.5. Criar um servlet com JBuilder e implantá-lo com o Tomcat
Descreveremos agora como criar e executar um servlet Java. Utilizaremos duas ferramentas: o JBuilder para compilar o servlet e o Tomcat para executá-lo. O Tomcat por si só poderia ser suficiente. No entanto, ele oferece recursos limitados de depuração. Retomamos o exemplo desenvolvido anteriormente, que exibe os parâmetros recebidos pelo servidor. O servlet envia, em primeiro lugar, o seguinte formulário de entrada:

A resposta enviada pela servlet:

O código-fonte da servlet é o seguinte:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myRequestParamExample extends HttpServlet {
String title="Récupération des paramètres d'un formulaire";
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.println("<P>");
out.print("<form action=\"RequestParamExample\" method=\"POST\">");
out.println("firstname= <input type=text size=20 name=firstname>");
out.println("<br>");
out.println("lastname= <input type=text size=20 name=lastname>");
out.println("<br>");
out.println("<input type=submit>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
- Crie um projeto myRequestParamExample com o JBuilder e inclua nele o programa myRequestParamExample.java anterior.
- Durante a compilação, pode ocorrer o seguinte problema: seu JBuilder não possui necessariamente a biblioteca javax.servlet necessária para a compilação dos servlets. Nesse caso, é necessário configurar o JBuilder para que ele utilize bibliotecas de classes adicionais. O procedimento está descrito nos anexos deste documento para o JBuilder 7. Repetimos parte dele aqui:
- ative a opção Tools/Configure JDKs ou (Options/Configurar JDK)

Na seção JDK Settings acima, normalmente há no campo Name a versão JDK 1.3.1. Se você tiver uma versão mais recente do JDK, use o botão Change para indicar o diretório de instalação dessa versão. Acima, foi especificado o diretório E:\Program Files\jdk14, onde estava instalado um JDK 1.4. A partir de agora, o JBuilder utilizará esse JDK para suas compilações e execuções. Na seção (Class, Source, Documentation), temos a lista de todas as bibliotecas de classes que serão exploradas pelo JBuilder; neste caso, as classes do JDK 1.4. As classes deste último não são suficientes para o desenvolvimento web em Java. Para adicionar outras bibliotecas de classes, usa-se o botão Add e indica-se os arquivos .jar adicionais que se deseja utilizar. Os arquivos .jar são bibliotecas de classes. O Tomcat 4.x traz consigo todas as bibliotecas de classes necessárias para o desenvolvimento web. Elas estão localizadas em <tomcat>\common\lib, onde <tomcat> é o diretório de instalação do Tomcat:

Com o botão Add, vamos adicionar essas bibliotecas, uma a uma, à lista de bibliotecas exploradas pelo JBuilder:

A partir de agora, é possível compilar programas Java em conformidade com a norma J2EE, incluindo servlets Java. O JBuilder serve apenas para a compilação; a execução é garantida posteriormente pelo Tomcat.
- Agora você pode compilar o programa myRequestParamExample.java e gerar o servlet myRequestParamExample.class. Onde colocar esse servlet? Se a configuração inicial do Tomcat não tiver sido alterada, os arquivos .class dos servlets devem ser colocados em <tomcat>\webapps\examples\WEB-INF\classes (Tomcat 4.x).
- Verifique se o Tomcat está em execução e, usando um navegador, acesse o URL em http://localhost:8080/examples/servlet/myRequestParamExample:

3.1.6. Exemplos
Para os exemplos a seguir, utilizamos o método descrito anteriormente:
- compilação do código-fonte XX.java do servlet com o JBuilder
- implantação do servlet XX.class em <tomcat>\webapps\examples\WEB-INF\classes
- Após iniciar o Tomcat, acesse com um navegador o endereço URL http://localhost:8080/examples/servlet/XX
3.1.6.1. Geração dinâmica de formulário - 1
Tomaremos como exemplo a geração de um formulário com apenas um controle: uma lista. O conteúdo dessa lista é construído dinamicamente com valores extraídos de uma matriz. Na prática, esses valores costumam ser obtidos de um banco de dados. O formulário é o seguinte:

Se, no exemplo acima, executarmos o comando Envoyer, obtemos a seguinte resposta:

Observe-se que o código URL que gera a resposta é o mesmo que exibe o formulário. Aqui, temos um servlet que processa por conta própria a resposta ao formulário que ele mesmo enviou. Esse é um caso comum. O código HTML do formulário é o seguinte:
<html>
<head><title>Génération de formulaire</title></head>
<body>
<h3>Choississez un nombre</h3><hr>
<form method="POST">
<select name="cmbValeurs" size="1">
<option>zéro</option>
<option>un</option>
<option>deux</option>
<option>trois</option>
<option>quatre</option>
<option>cinq</option>
<option>six</option>
<option>sept</option>
<option>huit</option>
<option>neuf</option>
</select>
<input type="submit" value="Envoyer">
</form>
</body>
</html>
Observe-se que os valores enviados pelo formulário são transmitidos pelo método POST. O código HTML da resposta:
<html>
<head><title>Voici ma réponse</title></head>
<body>
Vous avez choisi le nombre<h2>neuf</h2>
</body>
</html>
O código do servlet que gera este formulário e esta resposta é o seguinte:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class gener1 extends HttpServlet{
// variáveis de instância
private String title="Génération d'un formulaire";
private final String[] valeurs={"zéro","un","deux","trois","quatre","cinq","six",
"sept","huit","neuf"};
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choississez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\">";
private final String HTML3="</form>\n</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// informa-se ao cliente o tipo de documento enviado
response.setContentType("text/html");
// o formulário é enviado
PrintWriter out=response.getWriter();
// início
out.println(HTML1);
// menu suspenso
out.println("<select name=\"cmbValeurs\" size=\"1\">");
for (int i=0;i<valeurs.length;i++){
out.println("<option>"+valeurs[i]+"</option>");
}//para
out.println("</select>");
// fim do formulário
out.println(HTML2+HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// recuperamos a escolha do usuário
String choix=request.getParameter("cmbValeurs");
if(choix==null) doGet(request,response);
// prepara-se a resposta
String réponse="<html><head><title>Voici ma réponse</title></head>";
réponse+="<body>Vous avez choisi le nombre <h2>"+choix+"</h2></body></html>";
// informa-se ao cliente o tipo de documento enviado
response.setContentType("text/html");
// envia-se o formulário
PrintWriter out=response.getWriter();
out.println(réponse);
}//POST
}//classificação
O método doGet serve para gerar o formulário. Há uma parte dinâmica, que é o conteúdo da lista, proveniente, neste caso, de uma tabela. O método doPost serve para gerar a resposta. Aqui, a única parte dinâmica é o valor da escolha feita pelo usuário na lista do formulário. Esse valor é obtido por meio de request.getParameter("cmbValeurs"), onde cmbValeurs é o nome da lista:
Para concluir, observe os seguintes pontos:
- o navegador envia os valores do formulário para o servlet que o gerou, pois a tag <form> não possui o atributo <action>. Nesse caso, o navegador envia os dados inseridos no formulário para o URL que o forneceu.
- A tag <form> especifica que os dados do formulário devem ser enviados pelo método POST. É por isso que esses valores são recuperados pelo método doPost do servlet.
3.1.6.2. Geração dinâmica de formulário - 2
Retomamos o exemplo anterior, modificando-o da seguinte maneira. O formulário proposto continua sendo o mesmo:

A resposta é diferente:

Na resposta, o formulário é devolvido, com o número escolhido pelo usuário indicado abaixo dele. Além disso, esse número é o que aparece como selecionado quando a lista é exibida. O usuário pode então escolher outro número:

e, em seguida, executar Envoyer. Ele obtém a seguinte resposta:

O código do servlet chamado gener2.java é o seguinte:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class gener2 extends HttpServlet{
// variáveis de instância
private String title="Génération d'un formulaire";
private final String[] valeurs={"zéro","un","deux","trois","quatre","cinq","six",
"sept","huit","neuf"};
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choisissez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\"></form>\n";
private final String HTML3="</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// recupera-se a eventual escolha do usuário
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
// informa-se ao cliente o tipo de documento enviado
response.setContentType("text/html");
// envia-se o formulário
PrintWriter out=response.getWriter();
// início
out.println(HTML1);
// menu suspenso
out.println("<select name=\"cmbValeurs\" size=\"1\">");
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//para
out.println("</select>");
// continuação do formulário
out.println(HTML2);
if(! choix.equals("")){
// exibe a escolha do usuário
out.println("<hr>Vous avez choisi le nombre <h2>"+choix+"</h2>");
}//se
// fim do formulário
out.println(HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// redireciona para GET
doGet(request,response);
}//POST
}//classe
O método doGet realiza todas as tarefas: ele cria o formulário que é enviado ao cliente e processa os valores que este retorna. Os pontos a serem observados são os seguintes:
- verifica-se se o parâmetro cmbValeurs possui um valor.
- Se for o caso, ao criar o conteúdo da lista, compara-se cada elemento da lista com a escolha do usuário para atribuir o atributo selected ao elemento escolhido pelo usuário: <option selected>elemento</option>. Além disso, exibe-se abaixo do formulário o valor da escolha.
3.1.6.3. Geração dinâmica de formulário - 3
Retomamos o mesmo problema de antes, mas, desta vez, os valores são obtidos de um banco de dados. No nosso exemplo, trata-se do banco de dados MySQL:
- o banco de dados se chama dbValeurs
- seu proprietário é admDbValeurs, cuja senha é mdpDbValeurs
- O banco de dados possui uma única tabela chamada tvaleurs
- essa tabela possui apenas um campo inteiro chamado valor
E:\Program Files\EasyPHP\mysql\bin>mysql --database=dbValeurs --user=admDbValeurs --password=mdpDbVa
leurs
mysql> show tables;
+---------------------+
| Tables_in_dbValeurs |
+---------------------+
| tvaleurs |
+---------------------+
1 row in set (0.00 sec)
mysql> describe tvaleurs;
+--------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+-------+
| valeur | int(11) | | | 0 | |
+--------+---------+------+-----+---------+-------+
mysql> select * from tvaleurs;
+--------+
| valeur |
+--------+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 6 |
| 5 |
| 7 |
| 8 |
| 9 |
+--------+
10 rows in set (0.00 sec)
A base de dados MySQL dbValeurs foi disponibilizada por um driver ODBC para MySQL. Seu nome DSN (Data Source Name) é odbc-valeurs. O código do servlet é o seguinte:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.util.*;
public class gener3 extends HttpServlet{
// o título da página
private final String title="Génération d'un formulaire";
// o banco de dados dos valores da lista
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
// valores da lista
private String[] valeurs=null;
// mensagem de erro
private String msgErreur=null;
// código HTML
private final String HTML1=
"<html>" +
"<head>" +
"<title>Génération de formulaire</title>"+
"</head>" +
"<body>" +
"<h3>Choisissez un nombre</h3>"+
"<hr>" +
"<form method=\"POST\">";
private final String HTML2="<input type=\"submit\" value=\"Envoyer\"></form>\n";
private final String HTML3="</body>\n</html>";
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// informa-se ao cliente o tipo de documento enviado
response.setContentType("text/html");
// fluxo de saída
PrintWriter out=response.getWriter();
// a inicialização do servlet ocorreu normalmente?
if (msgErreur!=null){
// ocorreu um erro — é gerada uma página de erro
out.println("<html><head><title>"+title+"</title></head>");
out.println("<body><h3>Application indisponible ("+msgErreur+
")</h3></body></html>");
return;
}//if
// recuperamos a eventual escolha do usuário
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
// envia-se o formulário
// início
out.println(HTML1);
// menu suspenso
out.println("<select name=\"cmbValeurs\" size=\"1\">");
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//for
out.println("</select>");
// continuação do formulário
out.println(HTML2);
if(! choix.equals("")){
// exibe a escolha do usuário
out.println("<hr>Vous avez choisi le nombre <h2>"+choix+"</h2>");
}//se
// fim do formulário
out.println(HTML3);
}//GET
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// redireciona para GET
doGet(request,response);
}//POST
// inicialização do servlet
public void init(){
// preenche a matriz de valores a partir de um banco de dados ODBC
// com o nome DSN: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// conexão com o banco de dados ODBC
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// objeto Statement
st=connexion.createStatement();
// execução da consulta SELECT para recuperar os valores
rs=st.executeQuery("select valeur from Tvaleurs");
// os valores são recuperados e inseridos em uma tabela dinâmica
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// o valor é registrado na lista
lstValeurs.add(rs.getString("valeur"));
}//while
// transformação de lista em tabela
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// problema
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//inicializar
}//classe
Os pontos importantes a serem observados são os seguintes:
- Um servlet pode ser inicializado por um método cuja assinatura deve ser public void init(). Esse método é executado apenas no carregamento inicial do servlet
- Uma vez carregada, uma servlet permanece na memória o tempo todo. Isso significa que, após atender a um cliente, ela não é descarregada. Assim, ela responde mais rapidamente às solicitações dos clientes.
- Em nosso servlet, uma lista de valores deve ser buscada em um banco de dados. Como essa lista não se altera ao longo do tempo, o método init é o momento ideal para recuperá-la. Assim, o banco de dados é acessado apenas uma vez pelo servlet, no momento do carregamento inicial deste, e não a cada solicitação de um cliente.
- O acesso a um banco de dados pode falhar. O método init do nosso servlet gera uma mensagem de erro msgErreur em caso de falha. Essa mensagem é verificada no método doGet e, caso tenha ocorrido um erro, o método doGet gera uma página informando sobre o erro.
- A implementação do método init utiliza um acesso convencional a um banco de dados com os drivers ODBC-JDBC. Se necessário, o leitor é convidado a revisar os métodos de acesso a bancos de dados JDBC.
Ao executar o servlet e caso o servidor MySQL não tenha sido iniciado, é exibida a seguinte página de erro:
![]()
Se, agora, iniciarmos o servidor MySQL, obtemos a página:

Se selecionarmos o número 6 e clicarmos em “enviar”:

3.1.6.4. Recuperar os valores de um formulário
Vamos retomar um exemplo já visto, o do seguinte formulário da web:

O código HTML do formulário balises2.htm é o seguinte:
<html>
<head>
<title>balises</title>
<script language="JavaScript">
function effacer(){
alert("Vous avez cliqué sur le bouton Effacer");
}//apagar
</script>
</head>
<body background="/images/standard.jpg">
...
<form method="POST" action="http://localhost:8080/examples/servlet/parameters">
<table border="0">
<tr>
<td>Etes-vous marié(e)</td>
<td>
<input type="radio" value="Oui" name="R1">Oui
<input type="radio" name="R1" value="non" checked>Non
</td>
</tr>
<tr>
<td>Cases à cocher</td>
<td>
<input type="checkbox" name="C1" value="un">1
<input type="checkbox" name="C2" value="deux" checked>2
<input type="checkbox" name="C3" value="trois">3
</td>
</tr>
<tr>
<td>Champ de saisie</td>
<td>
<input type="text" name="txtSaisie" size="20" value="qqs mots">
</td>
</tr>
<tr>
<td>Mot de passe</td>
<td>
<input type="password" name="txtMdp" size="20" value="unMotDePasse">
</td>
</tr>
<tr>
<td>Boîte de saisie</td>
<td>
<textarea rows="2" name="areaSaisie" cols="20">
ligne1
ligne2
ligne3
</textarea>
</td>
</tr>
<tr>
<td>combo</td>
<td>
<select size="1" name="cmbValeurs">
<option>choix1</option>
<option selected>choix2</option>
<option>choix3</option>
</select>
</td>
</tr>
<tr>
<td>liste à choix simple</td>
<td>
<select size="3" name="lst1">
<option selected>liste1</option>
<option>liste2</option>
<option>liste3</option>
<option>liste4</option>
<option>liste5</option>
</select>
</td>
</tr>
<tr>
<td>liste à choix multiple</td>
<td>
<select size="3" name="lst2" multiple>
<option selected>liste1</option>
<option>liste2</option>
<option selected>liste3</option>
<option>liste4</option>
<option>liste5</option>
</select>
</td>
</tr>
<tr>
<td>bouton</td>
<td>
<input type="button" value="Effacer" name="cmdEffacer" onclick="effacer()">
</td>
</tr>
<tr>
<td>envoyer</td>
<td>
<input type="submit" value="Envoyer" name="cmdRenvoyer">
</td>
</tr>
<tr>
<td>rétablir</td>
<td>
<input type="reset" value="Rétablir" name="cmdRétablir">
</td>
</tr>
</table>
<input type="hidden" name="secret" value="uneValeur">
</form>
</body>
</html>
A tag <form> do formulário foi definida da seguinte forma:
O navegador “enviará” os valores do formulário para o URL http://localhost:8080/examples/servlet/parameters, que é o URL de um servlet gerenciado pelo Tomcat e que exibe os valores do formulário anterior. Se chamarmos a servlet parameters diretamente, obtemos os seguintes resultados:

Se o formulário balises2.htm preenchido for este:

e clicarmos no botão Enviar (do tipo submit), a servlet parameters é chamada, desta vez, com parâmetros. Ela retorna, então, a seguinte resposta:

Nessa resposta, podemos ver claramente os valores inseridos no formulário. O código do servlet é o seguinte:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class parameters extends HttpServlet{
// variáveis de instância
String title="Récupération des paramètres d'un formulaire";
private String getParameter(HttpServletRequest request, String contrôle){
// retorna o valor request.getParameter (verificação) ou "" caso não exista
String valeur=request.getParameter(contrôle);
if(valeur==null) return ""; else return valeur;
}//getParameter
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException
{
// começa-se por recuperar os parâmetros do formulário
String R1=getParameter(request,"R1");
String C1=getParameter(request,"C1");
String C2=getParameter(request,"C2");
String C3=getParameter(request,"C3");
String txtSaisie=getParameter(request,"txtSaisie");
String txtMdp=getParameter(request,"txtMdp");
String areaSaisie=getParameter(request,"areaSaisie");
String[] lignes=areaSaisie.split("\\r\\n");
String cmbValeurs=getParameter(request,"cmbValeurs");
String lst1=getParameter(request,"lst1");
String[] lst2=request.getParameterValues("lst2");
String secret=getParameter(request,"secret");
// indica-se o conteúdo do documento
response.setContentType("text/html");
// envia-se o documento
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h3>" + title + "</h3>");
out.println("<hr>");
out.println("<table border=\"1\">");
out.println("<tr><td>R1</td><td>"+R1+"</td></tr>");
out.println("<tr><td>C1</td><td>"+C1+"</td></tr>");
out.println("<tr><td>C2</td><td>"+C2+"</td></tr>");
out.println("<tr><td>C3</td><td>"+C3+"</td></tr>");
out.println("<tr><td>txtSaisie</td><td>"+txtSaisie+"</td></tr>");
out.println("<tr><td>txtMdp</td><td>"+txtMdp+"</td></tr>");
for(int i=0;i<lignes.length;i++)
out.println("<tr><td>areaSaisie["+i+"]</td><td>"+lignes[i]+"</td></tr>");
out.println("<tr><td>cmbValeurs</td><td>"+cmbValeurs+"</td></tr>");
out.println("<tr><td>lst1</td><td>"+lst1+"</td></tr>");
if(lst2==null)
out.println("<tr><td>lst2</td><td></td></tr>");
else
for(int i=0;i<lst2.length;i++)
out.println("<tr><td>lst2</td><td>"+lst2[i]+"</td></tr>");
out.println("<tr><td>secret</td><td>"+secret+"</td></tr>");
out.println("</body>");
out.println("</html>");
}
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException
{
// redireciona para GET
doGet(request,response);
}
}
Neste código, encontramos as técnicas apresentadas anteriormente em outro exemplo. Vale destacar dois pontos:
- o controle lst2 é uma lista de seleção múltipla e, portanto, vários elementos podem ser selecionados. É o caso do nosso exemplo, em que os elementos liste1 e liste3 foram selecionados. Os valores de lst2 foram transmitidos pelo navegador ao servidor na forma lst2=liste1&lst2=liste3. O servlet Java pode recuperar esses valores em um array com o método getParameterValues: aqui, request.getParameterValues("lst2") fornece um array com duas cadeias de caracteres ["liste1","liste3"].
- O controle areaSaisie é um campo de entrada multilinha. request.getParameter("areaSaisie") retorna o conteúdo do campo na forma de uma única sequência de caracteres. Se, nessa sequência, quisermos recuperar as diferentes linhas que a compõem, poderemos utilizar a função split da classe String. O código a seguir
recupera as linhas do campo de entrada. Essas linhas são terminadas pelos caracteres \r\n (0D0A).
Para realizar os testes, nós:
- construímos e compilamos o servlet parameters com JBuilder, conforme explicado anteriormente
- colocado a classe gerada em <tomcat>\webapps\examples\WEB-INF\classes, onde <tomcat> é o diretório de instalação do Tomcat.
- acessei o URL http://localhost:81/html/balises2.htm, cujo código foi apresentado acima
- preenchi o formulário e cliquei no botão Envoyer.
3.1.6.5. Recuperar os cabeçalhos HTTP de um cliente web
Retomamos o mesmo exemplo anterior, mas, em resposta ao cliente web que enviou os valores do formulário, enviamos a ele os cabeçalhos HTTP que ele enviou ao mesmo tempo. Introduzimos uma única alteração em nosso formulário:
Os valores do formulário serão enviados pelo método GET para um servlet Java chamado headers, localizado em <tomcat>\webapps\examples\WEB-INF\classes. O servlet headers foi criado e compilado junto com o JBuilder:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class headers extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
// define-se a natureza do documento
response.setContentType("text/html");
// obtém-se um fluxo de gravação
PrintWriter out = response.getWriter();
// exibição da lista de cabeçalhos HTTP
Enumeration e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
String value = request.getHeader(name);
out.println("<b>"+name + "</b> = " + value + "<br>");
}
}//GET
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
//GET
doGet(request,response);
}//POST
}
Solicitamos o URL http://localhost:81/html/balises2.htm e geramos o Envoyer sem alterar o formulário. Obtemos a seguinte resposta:

Observe-se que o parâmetro URL está presente no campo Address do navegador, o que mostra a forma (GET) utilizada para transmitir os parâmetros. Retomamos o mesmo exemplo, mas alterando a forma de enviar os parâmetros (POST):
Obtemos a seguinte resposta:

Observe-se que os cabeçalhos HTTP, content-type e content-length são característicos de um envio feito por POST. Além disso, observe-se que, no campo Address do navegador, os valores do formulário não aparecem mais.
3.2. Páginas JSP
As páginas JSP (Java Server Pages) são outra forma de desenvolver aplicativos de servidor web. Na verdade, essas páginas JSP são convertidas em servlets antes de serem executadas, e assim voltamos à tecnologia dos servlets. As páginas JSP permitem destacar melhor a estrutura das páginas HTML geradas. Apresentamos a seguir alguns exemplos, alguns dos quais podem ser acessados seguindo o link JSP na página inicial do Tomcat:
![]() | ![]() |
3.2.1. Recuperar informações de ambiente
Retomamos aqui um exemplo já abordado com um servlet: exibir as variáveis de ambiente de um servlet. Trata-se do exemplo snoop dos exemplos JSP:

O código-fonte da página JSP está localizado em <tomcat>\jakarta-tomcat\examples\jsp\snp\snoop.jsp (Tomcat 3.x) ou em <tomcat>\examples\jsp\snp\snoop.jsp (Tomcat 4.x)
<html>
<!--
Copyright (c) 1999 The Apache Software Foundation. All rights
reserved.
-->
<body bgcolor="white">
<h1> Request Information </h1>
<font size="4">
JSP Request Method: <%= request.getMethod() %>
<br>
Request URI: <%= request.getRequestURI() %>
<br>
Request Protocol: <%= request.getProtocol() %>
<br>
Servlet path: <%= request.getServletPath() %>
<br>
Path info: <%= request.getPathInfo() %>
<br>
Path translated: <%= request.getPathTranslated() %>
<br>
Query string: <%= request.getQueryString() %>
<br>
Content length: <%= request.getContentLength() %>
<br>
Content type: <%= request.getContentType() %>
<br>
Server name: <%= request.getServerName() %>
<br>
Server port: <%= request.getServerPort() %>
<br>
Remote user: <%= request.getRemoteUser() %>
<br>
Remote address: <%= request.getRemoteAddr() %>
<br>
Remote host: <%= request.getRemoteHost() %>
<br>
Authorization scheme: <%= request.getAuthType() %>
<hr>
The browser you are using is <%= request.getHeader("User-Agent") %>
<hr>
</font>
</body>
</html>
Observamos os seguintes pontos:
- temos aqui um código que se assemelha bastante ao HTML. No entanto, nele encontram-se as tags <%= expressão %>, que são específicas da linguagem JSP. O compilador JSP substitui, no texto HTML, a tag inteira pelo valor de expression.
- Este exemplo utiliza os métodos do objeto Java request, que é o objeto request já abordado no estudo sobre servlets. Trata-se, portanto, de um objeto HttpServletRequest. Assim, a tag <%= request.getRemoteHost() %> será substituída no código HTML pelo nome do computador do cliente da web que fez a solicitação.
- É possível chegar ao mesmo resultado com um servlet, mas, neste caso, a estrutura da página da web fica mais clara.
3.2.2. Recuperar os parâmetros enviados pelo cliente web
Retomamos aqui o exemplo já estudado com um servlet. É apresentado um formulário ao navegador:

Em resposta à solicitação acima, o navegador recebe a seguinte página:

O código da página JSP é o seguinte:
<%
// variáveis locais da procedimento principal
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
<!-- código HTML -->
<html>
<head>
<title><%= title %></title>
</head>
<body bgcolor="white">
<h3><%= title %></h3>
<%
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
%>
<P>
<form method="POST">
firstname= <input type="text" size="20" name="firstname">
<br>
lastname= <input type="text" size="20" name="lastname">
<br>
<input type="submit">
</form>
</body>
</html>
- Embora encontremos a tag <%= expressão %>, já vista no exemplo anterior, surge uma nova tag: <% instruções Java; %>. A tag <% introduz código Java. Esse código termina ao encontrar a tag de fechamento de código %>.
- Todo o código anterior (HTML + JSP) será convertido em um servlet Java. Ele será encapsulado em um único método, chamado de método principal da página JSP. É por isso que as variáveis Java declaradas no início da página JSP são reconhecidas nas outras partes do código JSP que se encontram espalhadas pelo código HTML: essas variáveis e partes do código farão parte do mesmo método Java. Mas se nosso código JSP contivesse métodos, as variáveis title, firstname e lastname não seriam reconhecidas nele devido ao isolamento entre métodos. Seria necessário transformá-las em variáveis globais ou passá-las como parâmetros para os métodos. Voltaremos a esse assunto.
- Para incluir partes dinâmicas no código HTML, há dois métodos possíveis: <%= expressão %> ou out.println(expressão). O objeto out é um fluxo de saída semelhante ao de mesmo nome encontrado nos exemplos de servlets, mas não é do mesmo tipo: trata-se de um objeto JspWriter e não de um PrintWriter. Ele permite gravar no fluxo HTML usando os métodos print e println.
- A página JSP reflete melhor a estrutura da página HTML gerada do que o servlet equivalente.
3.2.3. As tags JSP
Segue uma lista de tags que podem ser encontradas em uma página JSP e seus significados.
tag | significado |
Comentário HTML. É enviado ao cliente. | |
comentário JSP. Não é enviado ao cliente. | |
declara variáveis globais e métodos. As variáveis serão reconhecidas em todos os métodos | |
O valor da expressão será inserido na página HTML no lugar da tag | |
contém código Java que fará parte do método principal da página JSP | |
define atributos para a página JSP. Por exemplo: import="java.util.*,java.sql.*" para especificar as bibliotecas necessárias para a página JSP extends="umaClassePai" para fazer com que a página JSP seja derivada de outra classe |
3.2.4. Os objetos implícitos JSP
Nos exemplos anteriores, encontramos dois objetos não declarados: request e out. Esses são dois dos objetos que são definidos automaticamente no servlet no qual a página JSP é convertida. Eles são chamados de objetos implícitos ou predefinidos. Existem outros, mas esses são os mais utilizados junto com o objeto response:
objeto | significado |
o objeto a partir do qual se tem acesso à solicitação do cliente da Web (getParameter, getParameterNames, getParameterValues) | |
o objeto com o qual é possível construir a resposta do servidor Web ao seu cliente. Permite definir os cabeçalhos HTTP a serem enviados ao cliente Web. | |
o fluxo de saída que nos permite enviar o código HTML ao cliente (print, println) |
3.2.5. A transformação de uma página JSP em um servlet
Vamos retomar o código JSP de myRequestParamExample.jsp:
<%
// variáveis locais do procedimento principal
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
<!-- código HTML -->
<html>
<head>
<title><%= title %></title>
</head>
<body bgcolor="white">
<h3><%= title %></h3>
<%
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
%>
<P>
<form method="POST">
firstname= <input type="text" size="20" name="firstname">
<br>
lastname= <input type="text" size="20" name="lastname">
<br>
<input type="submit">
</form>
</body>
</html>
Quando o navegador solicita essa página JSP ao servidor Tomcat, este a transforma em um servlet. Se a página URL solicitada for
http://localhost:8080/examples/jsp/perso/intro/myRequestParamExample.jsp, o Tomcat 4.x colocará o servlet gerado no diretório <tomcat>\work\localhost\examples\jsp\perso\intro:

Nesse nome, encontramos o http://localhost:8080/examples/jsp/perso/intro/myRequestParamExample.jsp da página JSP. Vemos acima que temos acesso ao código Java do servlet gerado para a página JSP. No nosso exemplo, ele é o seguinte:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class myRequestParamExample$jsp extends HttpJspBase {
static {
}
public myRequestParamExample$jsp( ) {
}
private static boolean _jspx_inited = false;
public final void _jspx_init() throws org.apache.jasper.runtime.JspException {
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String _value = null;
try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
// variáveis locais do procedimento principal
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
out.write("\r\n\r\n<!-- code HTML -->\r\n<html>\r\n <head>\r\n <title>");
out.print( title );
out.write("</title>\r\n </head>\r\n <body bgcolor=\"white\">\r\n <h3>");
out.print( title );
out.write("</h3>\r\n ");
if (firstName != null || lastName != null) {
out.println("firstname= " + firstName + "<br>");
out.println("lastname= " + lastName);
} else {
out.println("pas de paramètres");
}
out.write("\r\n <P>\r\n <form method=\"POST\">\r\n firstname= <input type=\"text\" size=\"20\" name=\"firstname\">\r\n <br>\r\n lastname= <input type=\"text\" size=\"20\" name=\"lastname\">\r\n <br>\r\n <input type=\"submit\">\r\n </form>\r\n </body>\r\n</html>\r\n");
} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}
O código gerado é bastante complexo. Vamos nos concentrar apenas nos seguintes pontos:
- O método principal do servlet é o seguinte:
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
É esse método que é executado no início da servlet. Vemos que ele recebe dois parâmetros: a solicitação request do cliente e um objeto response para gerar sua resposta ao cliente web.
- No método principal, um objeto JspWriter chamado `out` é declarado e, em seguida, inicializado. É ele que permitirá enviar o código HTML ao cliente por meio das instruções out.print("codeHTML").
- O código Java
<%
// variáveis locais do procedimento principal
String title="Récupération des paramètres d'un formulaire";
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
%>
foi incorporado na íntegra ao método principal _jspService do servlet. O mesmo se aplica a todo o código localizado entre as tags <%… %>
- O código HTML da página JSP é alvo das instruções out.print("codeHTML") ou out.write(...). Por exemplo
out.write("</title>\r\n </head>\r\n <body bgcolor=\"white\">\r\n <h3>");
- Neste exemplo, não há outros métodos além do método principal _jspService.
3.2.6. Os métodos e variáveis globais de uma página JSP
Consideremos a seguinte página JSP:
<%!
// a tag anterior inicia a seção de variáveis e métodos globais
// essa seção será reproduzida sem alterações no servlet
// uma variável global
String prenom="inconnu";
// um método
private String sonChien(){
return "milou";
}//sonChien
// outro método
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// fim da parte global do servlet
%>
<%
// a tag anterior indica que o código a seguir será gravado
// no método principal do servlet
// variável local do método principal
String nom="tintin";
%>
<%-- código HTML --%>
<html>
<head>
<title>Page JSP</title>
</head>
<body>
<center>
<h2>Page JSP</h2>
<p>Son nom est <%= nom %></p>
<p>Son prénom est <%= prenom %></p>
<p>Son chien s'appelle <%= sonChien() %></p>
<%
// o nome do amigo dele
afficheAmi(out);
%>
</center>
</body>
</html>
Esta página JSP gera a seguinte página da Web:

Vamos analisar como as quatro linhas acima são geradas:
<p>Son nom est <%= nom %></p>
<p>Son prénom est <%= prenom %></p>
<p>Son chien s'appelle <%= sonChien() %></p>
<%
// o nome do amigo dele
afficheAmi(out);
%>
As linhas acima estão dentro de uma tag <%..%> e, portanto, farão parte do método principal _jspService do servlet que será gerado. Como elas têm acesso às variáveis nom, prenom e aos métodos sonChien e afficheAmi?
é uma variável local do método principal da página JSP e, portanto, reconhecida nesse método | |
é uma variável global da página JSP e, portanto, conhecida no método principal | |
é um método público da página JSP e, portanto, acessível a partir do método principal | |
é um método público da página JSP e, portanto, acessível a partir do método principal. Observe-se que o objeto out é passado como parâmetro para o método. Isso é obrigatório neste caso. De fato, o objeto out é declarado e inicializado no método principal do servlet e não é uma variável global. |
Vejamos agora o código do servlet Java gerado a partir desta página JSP, após a remoção do código desnecessário:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class tintin$jsp extends HttpJspBase {
// a tag anterior inicia a seção de variáveis e métodos globais
// essa seção será reproduzida sem alterações no servlet
// uma variável global
String prenom="inconnu";
// um método
private String sonChien(){
return "milou";
}//sonChien
// outro método
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// fim da parte global do servlet
static {
}
public tintin$jsp( ) {
}
private static boolean _jspx_inited = false;
public final void _jspx_init() throws org.apache.jasper.runtime.JspException {
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String _value = null;
try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
out.write(" \r\n\r\n");
// a tag anterior indica que o código a seguir será gravado
// no método principal do servlet
// variável local do método principal
String nom="tintin";
out.write("\r\n\r\n\r\n");
out.write("\r\n<html>\r\n <head>\r\n <title>Page JSP</title>\r\n </head>\r\n <body>\r\n <center>\r\n <h2>Page JSP</h2>\r\n <p>Son nom est ");
out.print( nom );
out.write("</p>\r\n <p>Son prénom est ");
out.print( prenom );
out.write("</p>\r\n <p>Son chien s'appelle ");
out.print( sonChien() );
out.write("</p>\r\n ");
// o nome do amigo dele
afficheAmi(out);
out.write("\r\n </center>\r\n </body>\r\n</html>\r\n");
} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}
Vemos acima que o código Java que estava entre as tags JSP <%! .. %> foi reproduzido na íntegra e não faz parte do método principal _jspService do servlet. As variáveis declaradas nessa parte são, portanto, variáveis de instância, ou seja, globais para os métodos, e é também ali que se pode definir outros métodos além de _jspService.
// essa parte será reproduzida sem alterações no servlet
// uma variável global
String prenom="inconnu";
// um método
private String sonChien(){
return "milou";
}//sonChien
// outro método
private void afficheAmi(JspWriter out) throws Exception{
out.println("<p>Son ami s'appelle Haddock</p>");
}//afficheAmi
// fim da parte global do servlet
3.2.7. Implantação e depuração das páginas JSP no servidor Tomcat
Quando se deseja criar uma página JSP e utilizá-la com o servidor Tomcat, surge a questão de onde posicionar a página na estrutura de diretórios do servidor. Existem diferentes maneiras de fazer isso, sobre as quais falaremos mais adiante. Por enquanto, a mais simples é colocar a página JSP em uma pasta da árvore de diretórios <tomcat>\webapps\examples\jsp (Tomcat 4.x), onde <tomcat> é o diretório de instalação do Tomcat. Assim, o URL do exemplo anterior era http://localhost:8080/examples/jsp/perso/tintin/tintin.jsp. Isso significa que a página tintin.jsp estava na pasta <tomcat>\webapps\examples\jsp\perso\tintin.
Uma página JSP é convertida em um arquivo-fonte Java, que é então compilado pelo Tomcat quando a página JSP (URL) é solicitada por um navegador. Podem ocorrer erros de compilação. O Tomcat 4.x os sinaliza em sua resposta ao navegador. Ele indica, em particular, as linhas do arquivo .java que estão incorretas. Os erros podem ter diversas causas:
- o código JSP da página está incorreto (erros nas tags JSP utilizadas, por exemplo)
- o código Java incluído na página JSP está incorreto
A primeira causa pode ser eliminada verificando-se o código JSP da página. A segunda pode ser eliminada verificando-se o código Java. Isso pode ser feito compilando diretamente o arquivo .java gerado para a página JSP com uma ferramenta como o JBuilder, que oferece recursos de depuração mais avançados do que os do Tomcat.
3.2.8. Exemplos
Retomamos o exemplo já abordado com um servlet em que um usuário escolhe um número em uma lista e o servidor informa qual número ele escolheu, ao mesmo tempo em que retorna a mesma lista com o elemento selecionado pelo usuário:

Para construir essa página, recuperamos o código do servlet e o modificamos da seguinte maneira:
- mantivemos inalterado o código Java que não gerava o código HTML
- o código Java que gerava o código HTML foi transformado em uma combinação do código HTML com o código JSP
Assim, obtém-se a seguinte página JSP:
<%@ page import="java.sql.*, java.util.*" %>
<%!
// variáveis globais do aplicativo
// o título da página
private final String title="Génération d'un formulaire";
// banco de dados dos valores da lista
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
// valores da lista
private String[] valeurs=null;
// mensagem de erro
private String msgErreur=null;
// inicialização da página JSP — executada apenas uma vez
public void jspInit(){
// preenche a tabela de valores a partir de um banco de dados ODBC
// com o nome DSN: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// conexão com o banco de dados ODBC
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// objeto Statement
st=connexion.createStatement();
// execução da consulta SELECT para recuperar os valores
rs=st.executeQuery("select valeur from Tvaleurs");
// os valores são recuperados e inseridos em uma tabela dinâmica
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// o valor é registrado na lista
lstValeurs.add(rs.getString("valeur"));
}//while
// transformação de lista em tabela
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// problema
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//inicialização
%>
<%
// código de _jspService executado a cada solicitação do cliente
// ocorreu algum erro durante a inicialização da página JSP?
if(msgErreur!=null){
%>
<!-- código HTML -->
<html>
<head>
<title>Erreur</title>
</head>
<body>
<h3>Application indisponible (<%= msgErreur %></h3>
</body>
</html>
<%
// fim de jspService
return;
}//se
// recupera-se a eventual escolha do usuário
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
%>
<%-- sem erro — código HTML da página normal --%>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST">
<select name="cmbValeurs">
<%
// exibição dinâmica dos valores
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//para
%>
</select>
<input type="submit" value="Envoyer">
</form>
<%
// havia algum valor selecionado?
if(! choix.equals("")){
// exibe a escolha do usuário
%>
<hr>Vous avez choisi le nombre<h2><%= choix %></h2>
<%
}//if
%>
</body>
</html>
Observe os seguintes pontos:
- as instruções import do servlet foram alvo de uma diretiva <% page import="..." %>
- a tag <%! ... %> engloba as variáveis globais e os métodos Java do aplicativo
- o método init do servlet, que é executado uma única vez, no momento do carregamento do servlet, é chamado para uma página JSP: jspInit. Esses dois métodos têm a mesma função. Portanto, reproduzimos aqui integralmente o código do método init do servlet.
- As variáveis de instância do servlet, aquelas que devem ser conhecidas em vários métodos, foram reproduzidas exatamente da mesma forma. Trata-se essencialmente das variáveis title, valeurs e msgErreur, que são posteriormente utilizadas no código JSP.
- As tags <% ... %> delimitam o código Java que será incluído no método _jspService, executado no momento de uma solicitação de um cliente.
- Assim como no servlet, o método _jspService começará verificando o valor da variável msgErreur para determinar se deve gerar uma página de erro. Se houver erro, ela gera a página de erro e encerra a execução (return).
- Se não houver erro, ela gera o formulário com a lista de valores
- feito isso, ela verifica se o usuário escolheu um número; nesse caso, exibe esse número na página gerada
O que ganhamos em relação ao servlet? Sem dúvida, uma melhor visualização do código HTML gerado. Mas ainda há muito código Java que “polui” essa visualização. Veremos posteriormente outro método chamado delegação, no qual poderemos colocar a maior parte do código Java em um servlet, ficando a página JSP com apenas os códigos HTML e JSP. Assim, separamos claramente a parte de processamento da parte de apresentação.
3.3. Implantação de uma aplicação web no servidor Tomcat
Apresentamos agora como implantar aplicações web Java no servidor Tomcat. Embora o que será explicado seja específico para esse servidor, a implantação de uma aplicação web Java em outro contêiner J2EE apresentará características semelhantes às que serão descritas a seguir.
3.3.1. Os arquivos de configuração server.xml e web.xml
Até agora, para testar nossos servlets e páginas JSP, colocamos
- os servlets na pasta <tomcat>\webapps\examples\WEB-INF\classes. Eles ficavam, então, acessíveis pelo endereço http://localhost:8080/examples/servlet/nomServlet
- as páginas JSP na árvore de diretórios <tomcat>\webapps\examples\jsp. Elas estavam, então, acessíveis por meio do URL http://localhost:8080/examples/jsp/nomPageJSP
Nunca explicamos por que era assim. A configuração do servidor Tomcat é feita em um arquivo de texto chamado server.xml, localizado na pasta <tomcat>\conf:

Esse arquivo de texto é, na verdade, um arquivo XML (eXtended Markup Language). Um documento XML é um documento de texto que contém tags, assim como um documento HTML. No entanto, enquanto as tags da linguagem HTML estão bem definidas, as da linguagem XML não estão. Assim, o documento a seguir é um documento XML:
Um documento XML é simplesmente um documento “marcado” que segue determinadas regras de marcação:
- um texto marcado na forma <xx att1="val1" att2="val2" ....>texto</xx>
- uma tag pode estar sozinha e ter o formato <xx att1="val1" att2="val2" ..../>
Os campos “atti” são chamados de atributos da tag xx e os campos “vali” são os valores associados a esses atributos. Alguns documentos HTML não são documentos XML válidos. Por exemplo, a tag HTML <br> não é uma tag XML válida. Ela deveria ser escrita como <br/> para ser válida, a fim de respeitar a regra que determina que toda tag XML deve ser fechada. Uma variante de HTML chamada XHTML foi criada para transformar qualquer documento XHTML em um documento XML válido. Alguns navegadores mais recentes são capazes de exibir arquivos XML. Assim, se chamarmos de personne.xml o documento XML apresentado no exemplo acima e o visualizarmos com o IE6, obteremos a seguinte exibição:

O IE6 reconhece as tags e as destaca com cores. Ele também reconhece a estrutura do documento por meio das tags. Assim, se chamarmos de personne2.xml o seguinte documento:
e o visualizarmos com o IE6, obtemos a mesma exibição:

O IE6 reconheceu corretamente a estrutura e o conteúdo do documento. Todo o valor do documento XML reside nessa propriedade: é fácil recuperar a estrutura e o conteúdo de um documento XML. Isso é feito com um programa chamado analisador XML. Os documentos XML tendem a se tornar o padrão nas trocas de documentos na web. Consideremos uma máquina A que precisa enviar um documento DOC para uma máquina B. O documento DOC é gerado a partir das informações contidas em um banco de dados DB-A. Já a máquina B deve armazenar o documento DOC em um banco de dados DB-B. A troca poderá ocorrer da seguinte maneira:
- a máquina A recupera os dados do banco de dados DB-A e os encapsula em um documento de texto XML
- o documento XML é enviado à máquina B pela rede
- a máquina B analisa o documento recebido com um analisador sintático XML e recupera tanto a estrutura quanto os dados (como fez o IE6 em nosso exemplo). Ela pode então armazenar os dados recebidos no banco de dados DB-B
Não falaremos mais sobre a linguagem XML, que mereceria um livro inteiro só para ela.
Aqui, portanto, o Tomcat é configurado pelo arquivo XML server.xml. Se visualizarmos esse arquivo com o IE6, obtemos um documento complexo. Vamos nos concentrar apenas nas seguintes linhas:

É a tag <Context ...> que nos interessa aqui. Ela serve para definir aplicativos web. Dois de seus atributos merecem destaque:
- path: é o nome da aplicação web
- docBase: é a pasta na qual ela está localizada. Aqui, trata-se de um nome relativo: examples. Relativo a qual pasta? A resposta também se encontra no arquivo server.xml, na linha seguinte:

A linha acima define o servidor web:
- name: nome do servidor web
- appBase: raiz da árvore de documentos que ele distribui. Mais uma vez, temos um nome relativo: webapps. Ele é relativo ao diretório de instalação do servidor Tomcat <tomcat>. Portanto, trata-se da pasta <tomcat>\webapps.
A aplicação web examples tem seus documentos na pasta examples (ver docBase acima). Esse nome é relativo à raiz da árvore de diretórios da web do servidor, c.a.d. <tomcat>\webapps. Trata-se, portanto, da pasta <tomcat>\webapps\examples. Vamos examinar essa pasta mais de perto:

Encontramos aqui a pasta WEB-INF\classes, na qual armazenamos nossos servlets para testá-los. A pasta WEB-INF contém um arquivo chamado web.xml:

Esse arquivo serve para configurar a aplicação web examples. Não entraremos em detalhes sobre esse arquivo, que é muito complexo, por enquanto. Vamos nos concentrar apenas nas seguintes linhas:
<servlet>
<servlet-name>
servletToJsp
</servlet-name>
<servlet-class>
servletToJsp
</servlet-class>
</servlet>
A tag <servlet> serve para definir um servlet dentro de uma aplicação web. Vale lembrar que a aplicação web em questão é examples. A tag servlet contém aqui duas outras tags:
- <servlet-name>servletToJsp</servlet-name>: define o nome do servlet
- <servlet-name>servletToJsp</servlet-name>: define o nome da classe a ser executada quando a servlet for solicitada. Neste exemplo, a servlet e sua classe têm o mesmo nome. Isso não é obrigatório.
Como a servlet servletToJsp é solicitada por um navegador ao servidor Tomcat?
- O navegador solicita o URL http://localhost:8080/examples/servlet/servletToJsp
- O Tomcat analisa o caminho da servlet /examples/servlet/servletToJsp. Ele interpreta a primeira parte do caminho, /examples, como o nome de uma aplicação web e procura em seu arquivo de configuração, server.xml, onde os documentos dessa aplicação foram armazenados. Como vimos anteriormente, é na pasta <tomcat>\webapps\examples.
- O Tomcat usa o restante do caminho do servlet para localizá-lo na aplicação web examples. Esse caminho /servlet/servletToJsp indica que ele deve executar o servlet com o nome servletToJsp. O Tomcat então lerá o arquivo de configuração web.xml da aplicação examples, que encontrará em <tomcat>\webapps\examples\WEB-INF. Nesse arquivo, ele verificará que o servlet servletToJsp está vinculado à classe Java servletToJsp (consulte o arquivo web.xml acima). Em seguida, ele procurará essa classe na pasta WEB-INF\classes da aplicação web examples, c.a.d. em <tomcat>\webapps\examples\WEB-INF\classes e a executará.

3.3.2. Exemplo: implantação da aplicação web “lista”
Retomamos um servlet já estudado, que apresentava ao usuário uma lista de números, dentre os quais ele escolhia um. O servlet, em seguida, confirmava o número que ele havia escolhido:

Conforme mostra o campo Address do navegador acima, o arquivo de classe do servlet se chamava gener3. De acordo com as explicações fornecidas anteriormente:
- o URL /examples/servlet/gener3 mostra que se trata de um servlet chamado gener3 do aplicativo web examples
- no arquivo web.xml da aplicação examples, não se encontrará nada que mencione uma servlet gener3. Como o Tomcat a encontrou, então? Depois de examinar todo o arquivo web.xml, não posso responder com certeza... A questão permanece em aberto...
Decidimos implantar a servlet gener3.class com o nome lstValeurs em uma aplicação web chamada “liste”, localizada na pasta E:\data\serge\Servlets\lstValeurs:

Colocamos o arquivo gener3.class na pasta WEB-INF\classes acima:

Configuramos a aplicação web “liste” adicionando, no arquivo server.xml, as seguintes linhas acima daquelas que definem a aplicação web manager:
<!-- Pessoal: lstValeurs -->
<Context path="/liste" docBase="e:/data/serge/servlets/lstValeurs" />
<!-- Contexto do Tomcat Manager -->
<Context path="/manager" docBase="manager" debug="0" privileged="true" />
<!-- Contexto de exemplos do Tomcat -->
<Context path="/examples" docBase="examples" debug="0" reloadable="true" crossContext="true">
........
A linha que define a lista de aplicativos indica que ela está localizada na pasta e:/data/serge/servlets/lstValeurs. Agora, precisamos definir o arquivo web.xml desse aplicativo. Esse arquivo definirá o único servlet do aplicativo:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
</web-app>
O arquivo acima indica que o servlet denominado lstValeurs está associado ao arquivo de classe gener3.class. Esse arquivo web.xml deve ser criado e salvo na pasta WEB-INF da aplicação lista:

A captura de tela acima mostra uma pasta src na qual foi colocado o arquivo de origem gener3.java. Essa pasta pode não existir. Ela não tem utilidade alguma nesta demonstração. Estamos prontos para realizar os testes:
- desligue e reinicie o Tomcat para que ele recarregue seu arquivo de configuração server.xml. Aqui estamos no Windows. No Unix, é possível forçar o Tomcat a recarregar seu arquivo de configuração sem precisar desligá-lo.
- Com um navegador, acesse o URL em http://localhost:8080/liste/servlet/lstValeurs

Percebe-se que o URL anterior contém a palavra-chave servlet, assim como todos os URL de servlets utilizados até agora. É possível dispensá-lo associando, no arquivo web.xml da aplicação “lista”, o servlet lstValeurs a um modelo de URL (url-pattern):
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
</web-app>
Na tag <servlet-mapping>, associamos o caminho /valores ao servlet lstValeurs definido nas linhas anteriores. Salvamos o novo arquivo web.xml e solicitamos o URL http://localhost:8080/liste/valeurs:

3.3.3. Implantação das páginas públicas de um aplicativo web
Acabamos de ver a implantação de um aplicativo web composto por um único servlet. Um aplicativo web pode ter diversos componentes: servlets, páginas JSP, arquivos HTML, applets Java, etc. Onde esses elementos do aplicativo são colocados? Se <application> é a pasta da aplicação web definida pelo atributo docBase da aplicação no arquivo de configuração do Tomcat server.xml, vimos que os servlets eram colocados em <application>\WEB-INF\classes. Os demais elementos da aplicação podem ser colocados em qualquer lugar na árvore de pastas de <application>, exceto na pasta WEB-INF. Consideremos a aplicação JSP listvaleurs.jsp já estudada:

Essa página JSP havia sido armazenada na pasta <tomcat>\webapps\examples\jsp\perso\listvaleurs. Essa página poderia ser um componente da aplicação “liste” implantada anteriormente. Vamos colocar o arquivo listvaleurs.jsp diretamente na pasta dessa aplicação:

Vamos relembrar a configuração da aplicação liste no arquivo server.xml:
Qualquer URL que comece com o caminho /liste é considerado parte do aplicativo liste e será procurado na pasta indicada. Vamos acessar o URL http://localhost:8080/liste/listvaleurs.jsp com um navegador:

Conseguimos, de fato, a página JSP esperada.
3.3.4. Parâmetros de inicialização de um servlet
Vimos que um servlet é configurado pelo arquivo <application>\WEB-INF\web.xml, onde <application> é a pasta do aplicativo web ao qual ele pertence. É possível incluir nesse arquivo parâmetros de inicialização do servlet. Voltemos ao nosso servlet lstValeurs da aplicação web liste, cujo arquivo de configuração era o seguinte:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
</web-app>
A classe associada ao servlet é a classe gener3. No código-fonte dessa classe, encontramos a definição de algumas constantes:
public class gener3 extends HttpServlet{
// o título da página
private final String title="Génération d'un formulaire";
// banco de dados dos valores da lista
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
Vale lembrar o significado das quatro constantes definidas acima:
título do documento HTML gerado pelo servlet | |
nome DSN do banco de dados ODBC de onde o servlet irá buscar os dados | |
nome de um usuário com permissão de leitura na base de dados anterior | |
sua senha |
Se o administrador do banco de dados DSNValeurs alterar a senha do usuário admDbValeurs, o código-fonte do servlet deverá ser modificado e recompilado. Isso não é muito prático. O arquivo de configuração da servlet web.xml oferece uma alternativa, permitindo a definição de parâmetros de inicialização da servlet com a tag <init-param>:
permite definir o nome do parâmetro | |
define o valor associado ao parâmetro anterior |
O servlet tem acesso aos seus parâmetros de inicialização por meio dos seguintes métodos:
método da classe Servlet, da qual deriva a classe HttpServlet, utilizada para programação web. Retorna um objeto ServletConfig que dá acesso aos parâmetros de configuração do servlet. | |
método da classe ServletConfig que retorna o valor do parâmetro de inicialização “paramètre” |
Configuramos o aplicativo liste com o novo arquivo web.xml a seguir:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet>
<servlet-name>lstValeurs2</servlet-name>
<servlet-class>gener5</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
<init-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</init-param>
<init-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</init-param>
<init-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>lstValeurs2</servlet-name>
<url-pattern>/valeurs2</url-pattern>
</servlet-mapping>
</web-app>
Na aplicação liste, definimos um segundo servlet chamado lstValeurs2 vinculado ao arquivo de classe gener5. Este último foi colocado em <application>\WEB-INF\classes:

O servlet lstValeurs2 possui quatro parâmetros de inicialização: title, DSNValeurs, admDbValeurs, mdpDbValeurs. Além disso, o alias /valeurs2 foi definido para o servlet por meio da tag <servlet-mapping>. Assim, o servlet lstValeurs2 do aplicativo liste estará acessível por meio do URL e do http://localhost:8080/liste/valeurs2.
O código-fonte do servlet foi modificado da seguinte forma para recuperar os parâmetros de inicialização do servlet:
public class gener5 extends HttpServlet{
// o título da página
private String title=null;
// banco de dados dos valores da lista
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
...............
// inicialização do servlet
public void init(){
// recuperam-se os parâmetros de inicialização do servlet
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
DSNValeurs=config.getInitParameter("DSNValeurs");
admDbValeurs=config.getInitParameter("admDbValeurs");
mdpDbValeurs=config.getInitParameter("mdpDbValeurs");
//todos os parâmetros foram recuperados?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// preenchimento da tabela de valores a partir de um banco de dados ODBC
// com o nome DSN: DSNvaleurs
...............
Para testar o servlet, é necessário reiniciar o Tomcat para que ele reconheça o novo arquivo de configuração web.xml do aplicativo liste. Usando um navegador, acesse o URL da servlet http://localhost:8080/liste/valeurs2:

Se algum dos parâmetros de inicialização necessários para o servlet estiver ausente do arquivo web.xml, será exibida a seguinte página:

3.3.5. Parâmetros de inicialização de uma aplicação web
No exemplo anterior, apenas o servlet lstValeurs2 tem acesso aos parâmetros title, DSNValeurs, admDbValeurs e mdpDbValeurs. Seria possível imaginar que outra servlet da mesma aplicação, liste, precisasse dos dados do mesmo banco de dados utilizado pela servlet lstValeurs2. Nesse caso, seria necessário redefinir os parâmetros DSNValeurs, admDbValeurs e mdpDbValeurs na seção de configuração do arquivo web.xml da nova servlet. Outra solução é definir os parâmetros comuns a várias servlets no nível da aplicação, e não mais no nível das servlets. O novo arquivo web.xml da aplicação fica da seguinte forma:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
<servlet>
<servlet-name>lstValeurs</servlet-name>
<servlet-class>gener3</servlet-class>
</servlet>
<servlet>
<servlet-name>lstValeurs3</servlet-name>
<servlet-class>gener6</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>lstValeurs</servlet-name>
<url-pattern>/valeurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>lstValeurs3</servlet-name>
<url-pattern>/valeurs3</url-pattern>
</servlet-mapping>
</web-app>
O novo servlet se chama lstValeurs3, está vinculado ao arquivo de classe gener6 e foi associado ao alias /valeurs3 (servlet-mapping). O parâmetro title é o único parâmetro que foi mantido na definição do servlet. Os demais foram colocados na configuração da aplicação, dentro das tags <context-param>. Essa tag serve para definir informações específicas da aplicação e não de um servlet ou página JSP em particular. Como o servlet Java tem acesso a esses parâmetros, frequentemente chamados de parâmetros de contexto? Os métodos disponíveis para obter as informações de contexto são muito semelhantes aos utilizados para obter os parâmetros de inicialização específicos de um servlet:
método da classe Servlet, da qual deriva a classe HttpServlet utilizada para programação web. Retorna um objeto ServletContext que dá acesso aos parâmetros de configuração da aplicação | |
método da classe ServletContext que retorna o valor do parâmetro de inicialização “paramètre” |
A classe gener6.java introduz apenas as seguintes alterações no código Java de gener5.java utilizado anteriormente:
// recuperam-se os parâmetros de inicialização do servlet
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//: todos os parâmetros foram recuperados?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// preenche-se a tabela de valores a partir de um banco de dados ODBC
// com o nome DSN: DSNvaleurs
...............
O parâmetro title, específico do servlet, é obtido por meio de um objeto ServletConfig. Os outros três parâmetros definidos no nível da aplicação são obtidos por meio de um objeto ServletContext. Compilamos essa classe e a colocamos, assim como as outras, em <application>\WEB-INF\classes:

Reiniciamos o Tomcat para que ele reconheça o novo arquivo web.xml da aplicação e solicitamos o URL e o http://localhost:8080/liste/valeurs3:

3.3.6. Parâmetros de inicialização de uma página JSP
Vimos como definir parâmetros de inicialização para um servlet ou uma aplicação web. Será que podemos fazer o mesmo para uma página JSP? Voltemos ao início do código da página listvaleurs.jsp já estudada:
<%@ page import="java.sql.*, java.util.*" %>
<%!
// variáveis globais do aplicativo
// o título da página
private final String title="Génération d'un formulaire";
// banco de dados dos valores da lista
private final String DSNValeurs="odbc-valeurs";
private final String admDbValeurs="admDbValeurs";
private final String mdpDbValeurs="mdpDbValeurs";
.........
Encontramos as quatro constantes title, DSNValeurs, admDbValeurs e mdpDbValeurs definidas no arquivo web.xml do aplicativo. As constantes DSNValeurs, admDbValeurs e mdpDbValeurs foram agora definidas no nível do aplicativo e, portanto, podemos supor que uma página JSP que faça parte desse aplicativo terá acesso a elas. É esse o caso. Sabemos que a página JSP será convertida em um servlet. Este terá acesso ao contexto por meio do método getServletContext(). Mais delicado é o caso da constante title. De fato, nós a definimos no nível do servlet e não no nível da aplicação, da seguinte maneira:
<servlet>
<servlet-name>lstValeurs3</servlet-name>
<servlet-class>gener6</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
Para a página JSP, a sintaxe anterior não é mais adequada, pois não existe mais o conceito de arquivo de classe. A sintaxe de configuração de uma página JSP, no entanto, é muito semelhante à de um servlet. É a seguinte:
<servlet>
<servlet-name>JSPlstValeurs</servlet-name>
<jsp-file>/listvaleurs2.jsp</jsp-file>
...
</servlet>
Na verdade, uma página JSP é considerada como um servlet ao qual se atribui um nome (servlet-name). Em vez de associar um arquivo de classe a esse servlet, associa-se o arquivo-fonte da página JSP a ser executada (jsp-file). Assim, as linhas anteriores definem um servlet chamado JSPlstvaleurs associado à página JSP /listvaleurs2.jsp. O caminho /listvaleurs2.jsp é medido em relação à raiz do aplicativo. Assim, no caso do nosso aplicativo liste, o arquivo listvaleurs2.jsp estaria na pasta docBase (cf. server.xml) da aplicação liste:

A configuração da página JSP será a seguinte no arquivo web.xml do aplicativo:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
.......
<servlet>
<servlet-name>JSPlstValeurs</servlet-name>
<jsp-file>/listvaleurs2.jsp</jsp-file>
<init-param>
<param-name>JSPtitle</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
</servlet>
..........
<servlet-mapping>
<servlet-name>JSPlstValeurs</servlet-name>
<url-pattern>/jspvaleurs</url-pattern>
</servlet-mapping>
<servlet-mapping>
........
</web-app>
A página JSP listvaleurs2.jsp está localizada na raiz do aplicativo liste e associada ao nome do servlet JSPlstValeurs (servlet-name), que, por sua vez, está associado ao alias /jspvaleurs (servlet-mapping). Assim, nossa página JSP ficará acessível por meio de URL http://localhost:8080/liste/jspvaleurs.
A página inicial JSP, listvaleurs.jsp, é alterada para listvaleurs2.jsp e recupera seus quatro parâmetros de inicialização no método jspInit():
<%!
// variáveis globais da aplicação
// o título da página
private String title=null;
// o banco de dados dos valores da lista
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
// valores da lista
private String[] valeurs=null;
// mensagem de erro
private String msgErreur=null;
// inicialização da página JSP — executada apenas uma vez
public void jspInit(){
// recuperação dos parâmetros de inicialização do servlet
ServletConfig config=getServletConfig();
title=config.getInitParameter("JSPtitle");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//: todos os parâmetros foram recuperados?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null){
msgErreur="Configuration incorrecte";
return;
}
// preenche a tabela de valores a partir de um banco de dados ODBC
// com o nome DSN: DSNvaleurs
..............
A página JSP recupera seus parâmetros de inicialização da mesma forma que os servlets. O arquivo anterior é salvo na raiz da aplicação web liste:

O servidor Tomcat é reiniciado para forçá-lo a recarregar o novo arquivo de configuração web.xml da aplicação. É então possível acessar o URL http://localhost:8080/liste/jspvaleurs:

3.3.7. Colaboração entre servlets e páginas JSP em uma aplicação web
Quando um cliente faz uma solicitação a um servidor web, a resposta pode ser elaborada por vários servlets e páginas JSP. Até agora, a resposta era elaborada por um único servlet ou página JSP. Vimos que a página JSP proporcionava maior legibilidade à estrutura do documento HTML gerado. No entanto, ela geralmente contém muito código Java. É possível melhorar a situação colocando
- em um ou mais servlets o código Java que não gera o código HTML da resposta
- em páginas JSP, o código de geração dos diversos documentos HTML enviados em resposta ao cliente
Dessa forma, podemos esperar melhorar a separação entre o código Java e o código HTML. Vamos aplicar essa nova estrutura à nossa aplicação liste: um servlet Java lstValeurs4 será responsável por ler, no início, os valores do banco de dados e, em seguida, analisar as solicitações dos clientes. Dependendo do resultado dessa análise, a solicitação do cliente será direcionada para uma página de erro erreur.jsp ou para a página de exibição da lista de números liste.jsp. A aplicação liste será, portanto, composta por um servlet e duas páginas JSP.
Como um servlet pode repassar a solicitação que recebeu de um cliente para outro servlet ou para uma página JSP? Utilizaremos os seguintes métodos:
método da classe ServletContext que retorna um objeto RequestDispatcher. O parâmetro url é o nome do URL para o qual se deseja transmitir a solicitação do cliente. Esse encaminhamento da solicitação só pode ocorrer dentro de uma mesma aplicação. Portanto, o parâmetro url é um caminho relativo à árvore de diretórios da web dessa aplicação. | |
método da interface RequestDispatcher que transmite ao método anterior URL a solicitação request do cliente e o objeto response que deve ser utilizado para elaborar a resposta. | |
quando um servlet ou uma página JSP encaminha uma solicitação para outro servlet ou página JSP, geralmente precisa passar para este outras informações além da mera solicitação do cliente, informações resultantes de seu próprio processamento da solicitação. O método setAttribute da classe ServletRequest permite adicionar atributos ao objeto request do cliente de uma forma que se assemelha a um dicionário de pares (atributo, valor), em que attribut é o nome do atributo e valeur é qualquer objeto que represente o valor desse atributo. | |
permite recuperar os valores dos atributos de uma solicitação. Esse método será utilizado pelo servlet ou pela página JSP, à qual foi encaminhada uma solicitação, para obter as informações que foram adicionadas a ela. |
O servlet responsável pelo processamento do formulário será configurado da seguinte maneira no arquivo web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>DSNValeurs</param-name>
<param-value>odbc-valeurs</param-value>
</context-param>
<context-param>
<param-name>admDbValeurs</param-name>
<param-value>admDbValeurs</param-value>
</context-param>
<context-param>
<param-name>mdpDbValeurs</param-name>
<param-value>mdpDbValeurs</param-value>
</context-param>
............
<servlet>
<servlet-name>lstValeurs4</servlet-name>
<servlet-class>gener7</servlet-class>
<init-param>
<param-name>title</param-name>
<param-value>Génération d'un formulaire</param-value>
</init-param>
<init-param>
<param-name>JSPerreur</param-name>
<param-value>/erreur.jsp</param-value>
</init-param>
<init-param>
<param-name>JSPliste</param-name>
<param-value>/liste.jsp</param-value>
</init-param>
<init-param>
<param-name>URLservlet</param-name>
<param-value>/liste/valeurs4</param-value>
</init-param>
</servlet>
...........
<servlet-mapping>
<servlet-name>lstValeurs4</servlet-name>
<url-pattern>/valeurs4</url-pattern>
</servlet-mapping>
.......
</web-app>
O servlet lstValeurs4 terá quatro parâmetros de inicialização próprios:
o título do documento HTML a ser gerado | |
o URL da página de erro JSP | |
o URL da página JSP que apresenta a lista de números | |
URL associada ao atributo action do formulário apresentado pela página JSPliste. Essa URL será a do servlet lstValeurs4 |
A servlet terá o alias /valeurs4 (servlet-mapping) e, portanto, será acessível por meio do URL http://localhost:8080/liste/valeurs4. Ela está vinculada ao arquivo de classe gener7.java, cujo código-fonte completo é o seguinte:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.util.*;
public class gener7 extends HttpServlet{
// o título da página
private String title=null;
// o banco de dados dos valores da lista
private String DSNValeurs=null;
private String admDbValeurs=null;
private String mdpDbValeurs=null;
// as páginas de exibição JSP
private String JSPerreur=null;
private String JSPliste=null;
// o URL do servlet
private String URLservlet=null;
// valores da lista
private String[] valeurs=null;
// mensagem de erro
private String msgErreur=null;
// -----------------------------------------------------------------
// GET
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// colocamos msgErreur,title nos atributos da solicitação
request.setAttribute("msgErreur",msgErreur);
request.setAttribute("title",title);
request.setAttribute("URLservlet",URLservlet);
// ocorreu algum erro ao carregar o servlet?
if(msgErreur!=null){
// redirecionamos para uma página de erro JSP
getServletContext().getRequestDispatcher(JSPerreur).forward(request,response);
// fim
return;
}
// não ocorreu nenhum erro
// colocamos a lista de valores nos atributos da solicitação
request.setAttribute("valeurs",valeurs);
// recupera-se a eventual escolha do usuário
String choix=request.getParameter("cmbValeurs");
if(choix==null) choix="";
request.setAttribute("choix",choix);
// passa-se o controle para a página JSP de apresentação da lista
getServletContext().getRequestDispatcher(JSPliste).forward(request,response);
// fim
return;
}//GET
// -----------------------------------------------------------------
// POST
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException{
// redireciona para GET
doGet(request,response);
}//POST
// -----------------------------------------------------------------
// inicialização do servlet
public void init(){
// recuperação dos parâmetros de inicialização do servlet
ServletConfig config=getServletConfig();
title=config.getInitParameter("title");
JSPerreur=config.getInitParameter("JSPerreur");
JSPliste=config.getInitParameter("JSPliste");
URLservlet=config.getInitParameter("URLservlet");
ServletContext context=getServletContext();
DSNValeurs=context.getInitParameter("DSNValeurs");
admDbValeurs=context.getInitParameter("admDbValeurs");
mdpDbValeurs=context.getInitParameter("mdpDbValeurs");
//todos os parâmetros foram recuperados?
if(title==null || DSNValeurs==null || admDbValeurs==null
|| mdpDbValeurs==null || JSPerreur==null || JSPliste==null || URLservlet==null){
msgErreur="Configuration incorrecte";
return;
}
// preenche a matriz de valores a partir de um banco de dados ODBC
// com o nome DSN: DSNvaleurs
Connection connexion=null;
Statement st=null;
ResultSet rs=null;
try{
// conexão com o banco de dados ODBC
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connexion=DriverManager.getConnection("jdbc:odbc:"+DSNValeurs,admDbValeurs,mdpDbValeurs);
// objeto Statement
st=connexion.createStatement();
// execução da consulta SELECT para recuperar os valores
rs=st.executeQuery("select valeur from Tvaleurs");
// os valores são recuperados e inseridos em uma tabela dinâmica
ArrayList lstValeurs=new ArrayList();
while(rs.next()){
// o valor é registrado na lista
lstValeurs.add(rs.getString("valeur"));
}//while
// transformação de lista em tabela
valeurs=new String[lstValeurs.size()];
for (int i=0;i<lstValeurs.size();i++){
valeurs[i]=(String)lstValeurs.get(i);
}
}catch(Exception ex){
// problema
msgErreur=ex.getMessage();
}finally{
try{rs.close();}catch(Exception ex){}
try{st.close();}catch(Exception ex){}
try{connexion.close();}catch(Exception ex){}
}//try
}//inicializar
}//classe
A novidade nesta classe é o encaminhamento da solicitação do cliente para a página JSPerreur em caso de erro e para a página JSPliste nos demais casos. A classe não elabora a resposta por conta própria. São as páginas JSP, JSPerreur e JSPliste que se encarregam disso. Anteriormente, o servlet adicionava atributos (setAttribute) à solicitação do cliente:
- uma mensagem de erro msgErreur em caso de erro na página JSPerreur
- os valores (valeurs) a serem exibidos, o valor selecionado (choix) pelo usuário, o título (title) do formulário, o URL (URLservlet) do atributo action do formulário para a página JSPliste
Essa classe é compilada e incluída nas classes do aplicativo:

A página JSP, que exibe uma mensagem de erro, está configurada da seguinte forma:
<servlet>
<servlet-name>JSPerreur</servlet-name>
<jsp-file>/erreur.jsp</jsp-file>
<init-param>
<param-name>mainServlet</param-name>
<param-value>/valeurs4</param-value>
</init-param>
</servlet>
.........
<servlet-mapping>
<servlet-name>JSPerreur</servlet-name>
<url-pattern>/JSPerreur</url-pattern>
</servlet-mapping>
O arquivo JSP associado à página de erro se chama erreur.jsp e está localizado na raiz do aplicativo:

Seu alias é /JSPerreur, o que o torna acessível por meio do http://localhost:8080/liste/JSPerreur URL. Ela possui um parâmetro de inicialização chamado mainServlet, cujo valor é o alias do servlet principal descrito anteriormente. Observe-se que esse alias é relativo à raiz da aplicação liste,; caso contrário, teríamos /liste/valeurs4.. O código da página erreur.jsp é o seguinte:
<%
// código de _jspService
// recupera-se o parâmetro de inicialização mainServlet
String servletListValeurs=config.getInitParameter("mainServlet");
// recupera-se o atributo msgErreur
String msgErreur=(String)request.getAttribute("msgErreur");
// o atributo é válido?
if(msgErreur!=null){
%>
<!-- código HTML -->
<html>
<head>
<title>Erreur</title>
</head>
<body>
<h3>Application indisponible (<%= msgErreur %>)</h3>
</body>
</html>
<%
} else { // atributo msgErreur inválido — retorno ao servlet principal
%>
<jsp:forward page="<%= servletListValeurs %>" />
<%
}
%>
Essa página normalmente deve ser chamada pelo servlet anterior, que deve passar a ela o atributo msgErreur. No entanto, nada impede que ela seja chamada diretamente, caso se conheça seu URL. Além disso, se for constatado que o atributo msgErreur está ausente, a solicitação é encaminhada para o servlet principal. Aqui, utiliza-se uma tag específica para as páginas JSP, cuja sintaxe é:
onde URL é o URL do servlet para o qual a solicitação do cliente é transferida. Se o atributo msgErreur estiver presente, a página de erro é exibida.
A página JSP, que exibe a lista de números, está configurada da seguinte maneira:
<servlet>
<servlet-name>JSPliste</servlet-name>
<jsp-file>/liste.jsp</jsp-file>
<init-param>
<param-name>mainServlet</param-name>
<param-value>/valeurs4</param-value>
</init-param>
.........
<servlet-mapping>
<servlet-name>JSPliste</servlet-name>
<url-pattern>/JSPliste</url-pattern>
</servlet-mapping>
O arquivo JSP associado à página de erro se chama liste.jsp e está localizado na raiz do aplicativo:

O alias do servlet é /JSPliste, o que o torna acessível por meio do endereço http://localhost:8080/liste/JSPliste. Ela possui um parâmetro de inicialização chamado mainServlet, cujo valor é o alias do servlet principal. O código da página liste.jsp é o seguinte:
<%-- página de exibição da lista de valores --%>
<%
// código de jspService
// recupera-se o parâmetro de inicialização
String servletListValeurs=config.getInitParameter("mainServlet");
// recuperam-se os atributos da solicitação proveniente do servlet principal
String title=(String) request.getAttribute("title");
String[] valeurs=(String[]) request.getAttribute("valeurs");
String choix=(String) request.getAttribute("choix");
String URLservlet=(String) request.getAttribute("URLservlet");
// atributos válidos?
if(title==null || valeurs==null || choix==null){
// há um atributo inválido — passamos o controle para o servlet
%>
<jsp:forward page="<%= servletListValeurs %>" />
<%
}//if
%>
<%-- código HTML --%>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST" action="<%= URLservlet %>">
<select name="cmbValeurs">
<%
// exibição dinâmica dos valores
String selected="";
for (int i=0;i<valeurs.length;i++){
if(valeurs[i].equals(choix)) selected="selected"; else selected="";
out.println("<option "+selected+">"+valeurs[i]+"</option>");
}//for
%>
</select>
<input type="submit" value="Envoyer">
</form>
<%
// havia algum valor selecionado?
if(! choix.equals("")){
// exibe-se a escolha do usuário
%>
<hr>Vous avez choisi le nombre<h2><%= choix %></h2>
<%
}//if
%>
</body>
</html>
Esta página funciona da mesma forma que a página erreur.jsp. Normalmente, ela deve ser chamada pelo servlet /liste/valeurs4 e receber os atributos title, valeurs e choix. Se algum desses parâmetros estiver faltando, o controle é repassado para o servlet URLservlet (/liste/valeurs4). Se todos os parâmetros estiverem presentes, a lista de números é exibida, bem como o número escolhido pelo usuário, caso ele tenha escolhido um.
Se for chamada a servlet principal URL, obtém-se o seguinte resultado:

com o código-fonte a seguir (View/Source):
<html>
<head>
<title>Génération d'un formulaire</title>
</head>
<body>
<h3>Choisissez une valeur</h3>
<form method="POST" action="/liste/valeurs4">
<select name="cmbValeurs">
<option >0</option>
<option >1</option>
<option >2</option>
<option >3</option>
<option >4</option>
<option >6</option>
<option >5</option>
<option >7</option>
<option >8</option>
<option >9</option>
</select>
<input type="submit" value="Envoyer">
</form>
</body>
</html>
Este documento HTMl foi gerado pela página JSP liste.jsp. Percebe-se que os atributos title, valeurs e URLservlet foram efetivamente recuperados.
Para concluir sobre a colaboração entre servlets e páginas JSP, observamos que as páginas JSP são, neste caso, muito curtas e não contêm o código Java que não contribui diretamente para a criação da resposta HTML. A estrutura dos documentos gerados fica, assim, mais visível.
3.4. Ciclo de vida dos servlets e das páginas JSP
3.4.1. O ciclo de vida
Aqui, estamos interessados no ciclo de vida dos servlets. O das páginas JSP decorre dele. Consideremos um servlet chamado pela primeira vez. Uma instância da classe é então criada pelo servidor web e carregada na memória. Ela passará então a atender à solicitação. Feito isso, o servlet não é descarregado da memória. Ela permanece na memória para atender a outras solicitações, a fim de otimizar os tempos de resposta do servidor. Ela será liberada da memória quando tiver decorrido um período de tempo suficientemente longo sem que tenha atendido a novas solicitações. Esse tempo geralmente é configurável no servidor web.
Enquanto estiver na memória, a servlet pode atender a várias solicitações simultaneamente. O servidor web cria um thread por solicitação, e todos utilizam a mesma instância da servlet:
![]() |
Todas as threads acima compartilham as variáveis da instância do servlet. Pode ser necessário sincronizar as threads para evitar a corrupção dos dados do servlet. Voltaremos a esse assunto.
Ao carregar uma servlet, um método específico da servlet é executado:
Para uma página JSP, esse método é
public void jspInit(){
}
que é executado. Aqui está um exemplo de página JSP que utiliza o método jspInit:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// variáveis e métodos globais da página JSP
// variável de instância
int compteur;
// método para incrementar o contador
public int getCompteur(){
// incrementa-se o contador
int myCompteur=compteur;
myCompteur++;
compteur=myCompteur;
// o contador é restaurado
return compteur;
}
// o método executado no carregamento inicial da página
public void jspInit(){
// inicialização do contador
compteur=100;
}
%>
A página anterior JSP inicializa um contador em jspInit com o valor 100. Qualquer solicitação subsequente ao servlet incrementa e, em seguida, exibe o valor desse contador:
Na primeira vez:

Na segunda vez:

Como se pode ver acima, entre as duas solicitações, o servlet não foi liberado; caso contrário, o contador estaria em 101 na segunda solicitação. Quando o servlet é liberado, o método
é executado, caso exista. Para as páginas JSP, é o método
public void jspDestroy(){
}
Nesses métodos, é possível, por exemplo, fechar conexões com bancos de dados, conexões que tenham sido abertas nos métodos init correspondentes.
3.4.2. Sincronização de solicitações com um servlet
Voltemos à página JSP anterior, que incrementa um contador e o retorna ao cliente web. Suponhamos que haja duas solicitações simultâneas. Nesse caso, são criadas duas threads para executá-las, threads que utilizarão a mesma instância do servlet e, portanto, neste caso, o mesmo contador. Recordemos o código que incrementa o contador:
public int getCompteur(){
// incrementa o contador
int myCompteur=compteur;
myCompteur++;
compteur=myCompteur;
// retornando o valor
return compteur;
}
O incremento do contador foi escrito propositalmente de forma desajeitada. Suponhamos que a execução das duas threads ocorra da seguinte maneira:
![]() |
- no momento T1, a thread TH1 é executada. Ela lê o contador (=145) em myCompteur, depois é interrompida e perde o controle do processador. Portanto, ele não teve tempo de incrementar myCompteur e copiar o novo valor para compteur.
- No momento em que T2 é executado, a thread TH2 está em execução. Ela lê o contador (=145) em myCompteur, depois é interrompida e perde o processador. Observe-se que as duas threads possuem variáveis myCompteur diferentes. Elas compartilham apenas as variáveis de instância, aquelas que são globais aos métodos.
- No momento T3, a thread TH1 retoma o controle e é concluída. Assim, ela retorna 146 ao seu cliente.
- No momento T4, o thread TH2 retoma o controle e termina. Ele também retorna 146 ao seu cliente, quando deveria ter retornado 147.
Temos aqui um problema de sincronização de threads. Quando TH1 deseja incrementar o contador, seria necessário impedir que qualquer outra thread fizesse o mesmo. Para destacar esse problema, reescrevemos a página JSP da seguinte maneira:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// variáveis e métodos globais da página JSP
// variável de instância
int compteur;
// método para incrementar o contador
public int getCompteur(){
// lê-se o contador
int myCompteur=compteur;
// pausa de 10 segundos
try{
Thread.sleep(10000);
}catch (Exception ignored){}
// incrementa-se o contador
compteur=myCompteur+1;
// retornar o valor
return compteur;
}
// o método executado no carregamento inicial da página
public void jspInit(){
// inicializar contador
compteur=100;
}
%>
Aqui, forçamos a thread a parar 10 segundos após ler o contador. Assim, ela deve liberar o processador, permitindo que outra thread leia, por sua vez, um contador que não foi incrementado. Quando fazemos consultas com um navegador, não percebemos nenhuma diferença, exceto pela espera de 10 segundos antes de obter o resultado.

Agora, se abrirmos duas janelas do navegador e fizermos duas solicitações com intervalo de tempo suficientemente curto:


Obtemos o mesmo valor do contador. Podemos destacar melhor o problema com um cliente programado, em vez de um manual como o navegador. Segue um cliente em Perl que é chamado da seguinte maneira:
programa URL N
onde
URL é o URL do servlet de contagem
N é o número de solicitações a serem feitas a essa servlet
Aqui estão os resultados obtidos para 5 solicitações, que demonstram claramente o problema de sincronização incorreta das threads: todas obtêm o mesmo valor do contador.
DOS>java clientCompteurJSP http://localhost:8080/examples/jsp/perso/compteur/compteur2.jsp 5
Compteur=121
Compteur=121
Compteur=121
Compteur=121
Compteur=121
O código do cliente Java é o seguinte.
import java.net.*;
import java.util.regex.*;
import java.io.*;
public class clientCompteurJSP {
public static void main(String[] params){
// dados
String syntaxe="Syntaxe : pg URL nbAppels";
// verificação dos parâmetros
if(params.length!=2){
System.err.println(syntaxe);
System.exit(1);
}//if
// URL
URL urlCompteur=null;
try{
urlCompteur=new URL(params[0]);
String query=urlCompteur.getQuery();
if(query!=null) throw new Exception();
}catch (Exception ex){
System.err.println(syntaxe);
System.err.println("URL ["+params[0]+" incorrecte");
System.exit(2);
}//try-catch
// número de chamadas
int nbAppels=0;
try{
nbAppels=Integer.parseInt(params[1]);
if(nbAppels<=0) throw new Exception();
}catch(Exception ex){
System.err.println(syntaxe);
System.err.println("Nombre d'appels ["+params[1]+" incorrect");
System.exit(3);
}//try-catch
// os parâmetros estão corretos — é possível estabelecer as conexões com o URL
try{
getCompteurs(urlCompteur,nbAppels);
}catch(Exception ex){
System.err.println(syntaxe);
System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
System.exit(4);
}//try-catch
}//main
private static void getCompteurs (URL urlCompteur, int nbAppels)
throws Exception {
// executa nbAppels no URL urlCompteur
// exibe sempre o valor do contador retornado pelo servidor web
// retira do urlCompteur as informações necessárias para a conexão com o servidor da Receita Federal
String path=urlCompteur.getPath();
if(path.equals("")) path="/";
String host=urlCompteur.getHost();
int port=urlCompteur.getPort();
if(port==-1) port=urlCompteur.getDefaultPort();
// são feitas as chamadas para o URL
Socket[] clients=new Socket[nbAppels];
for(int i=0;i<nbAppels;i++){
// conecta-se ao servidor
clients[i]=new Socket(host,port);
// cria-se um fluxo de gravação para o servidor
PrintWriter OUT=new PrintWriter(clients[i].getOutputStream(),true);
// solicita-se o URL — envio dos cabeçalhos HTTP
OUT.println("GET " + path + " HTTP/1.1");
OUT.println("Host: " + host + ":" + port);
OUT.println("Connection: close");
OUT.println("");
}//para
// dados locais
String réponse=null; // resposta do servidor
// o modelo procurado na resposta HTML do servidor
Pattern modèleCompteur=Pattern.compile("^\\s*Compteur= (\\d+)");
// o modelo de uma resposta correta
Pattern réponseOK=Pattern.compile("^.*? 200 OK");
// o resultado da comparação com o modelo
Matcher résultat=null;
for(int i=0;i<nbAppels;i++){
// cada cliente lê a resposta enviada pelo servidor
// criam-se os fluxos de entrada e saída do cliente TCP
BufferedReader IN=new BufferedReader(new InputStreamReader(clients[i].getInputStream()));
// lê-se a primeira linha da resposta
réponse=IN.readLine();
// compara-se a linha HTTP com o modelo da resposta correta
résultat=réponseOK.matcher(réponse);
if(! résultat.find()){
// ocorre um problema com URL
throw new Exception("Client n° " + i + " - Le serveur a répondu : URL ["+ urlCompteur + "] inconnue");
}//se
// lê-se a resposta até o final dos cabeçalhos
while((réponse=IN.readLine())!=null && ! réponse.equals("")){
}//enquanto
// os cabeçalhos terminaram HTTP — passamos para o código HTML
// para recuperar o valor do contador
boolean compteurTrouvé=false;
while((réponse=IN.readLine())!=null){
// comparamos a linha com o modelo do contador
if(! compteurTrouvé){
résultat=modèleCompteur.matcher(réponse);
if(résultat.find()){
// contador encontrado
System.out.println("Compteur="+résultat.group(1));
compteurTrouvé=true;
}//se
}//se
}//enquanto
// concluído
clients[i].close();
}//for
}//getCompteurs
}//classe
Vamos explicar o código anterior:
- o programa aceita dois parâmetros:
- o URL da página JSP do contador
- o número de clientes a serem criados para essa URL
- o programa começa, portanto, verificando a validade dos parâmetros: se há de fato dois, se o primeiro se assemelha sintaticamente a um URL e se o segundo a um número inteiro >0. Para verificar se o URL está sintaticamente correto, utiliza-se a classe URL e seu construtor URL (String), que cria um objeto URL a partir de uma sequência de caracteres como http://istia.univ-angers.fr. É lançada uma exceção se a sequência de caracteres não for um URL sintaticamente válido. Isso nos permite verificar a validade do primeiro parâmetro.
- Após a verificação dos parâmetros, o controle é passado para a procedimento getCompteurs. Este procedimento criará clientes nbAppels, os quais se conectarão todos ao mesmo tempo (ou quase) ao URL urlCompteur.
- A porta e a máquina às quais os clientes devem se conectar são obtidas do URL urlCompteur: [URL].getHost() permite obter o nome do servidor e [URL].getPort() permite obter a porta.
- Um primeiro loop permite que cada cliente:
- conectar-se ao servidor web
- solicitar a ele o URL urlCompteur
Nesse ciclo, o cliente não aguarda a resposta do servidor. De fato, o objetivo é fazer com que o servidor receba solicitações quase simultâneas.
- Um segundo loop permite que cada cliente receba e processe a resposta enviada pelo servidor. O processamento consiste em localizar na resposta a linha que contém o valor do contador e exibi-la.
Para resolver o problema apontado anteriormente (o mesmo contador enviado aos cinco clientes), precisamos sincronizar as threads do serviço de contagem em um mesmo objeto antes de entrar na seção crítica de leitura e atualização do contador. A nova página JSP é a seguinte:
<html>
<head>
<title>Compteur synchronisé</title>
</head>
<body>
Compteur= <%= getCompteur() %>
</body>
</html>
<%!
// variáveis e métodos globais da página JSP
// variáveis de instância
int compteur;
Object verrou=new Object();
// método para incrementar o contador
public int getCompteur(){
// sincroniza-se a seção crítica
synchronized(verrou){
// lê-se o contador
int myCompteur=compteur;
// pausa de 10 segundos
try{
Thread.sleep(10000);
}catch (Exception ignored){}
// incrementa-se o contador
compteur=myCompteur+1;
}//sincronizado
// retornando
return compteur;
}//getCompteur
// o método executado no carregamento inicial da página
public void jspInit(){
// inicialização do contador
compteur=100;
}
%>
Ao executar, obtêm-se então os seguintes resultados:
dos>c:\perl\bin\perl.exe client2.pl http://localhost:8080/examples/jsp/perso/contador/compteur3.jsp 5
Compteur= 104
Compteur= 106
Compteur= 105
Compteur= 107
Compteur= 108
A documentação indica que o servidor web pode, às vezes, criar várias instâncias de um mesmo servlet. Nesse caso, a sincronização anterior deixa de funcionar, pois a variável verrou é local a uma instância e, portanto, não é reconhecida pelas outras instâncias. O mesmo se aplica à variável compteur. Para torná-las globais para todas as instâncias, escreveremos:
// variável de classe
static int compteur;
static Object verrou=new Object();
O restante do código permanece inalterado.





