12. Aplicativo web MVC [personne] – versão 7
12.1. Introduction
Nesta versão, partimos do princípio de que pode haver navegadores dos usuários que tenham desativado:
- o reenvio dos cookies enviados pelo servidor
- a execução de código JavaScript incorporado nas páginas HTML exibidas
No entanto, queremos que esse tipo de navegador possa utilizar nosso aplicativo. O ponto 2 nos remete à versão 2 do nosso aplicativo, já que o JavaScript passou a ser utilizado a partir da versão 3. A versão 2 fazia o aplicativo funcionar sem JavaScript; portanto, o ponto 2 está resolvido.
O ponto 1 pode ou não ser complicado de lidar. A versão 6 do nosso aplicativo funcionava sem cookies. Ao mesclar as versões 2 e 6, obtemos o resultado solicitado. Vamos adicionar uma restrição adicional: o aplicativo deve gerenciar uma sessão. Essa restrição não é sem sentido. Em um aplicativo em que os usuários precisam se autenticar, o servidor deve memorizar o par (identificador/senha) do usuário para evitar que ele precise se autenticar a cada página que solicitar.
Até agora, utilizamos três soluções para armazenar informações ao longo das trocas entre cliente e servidor:
- a sessão
- os cookies
- os campos ocultos.
A solução 2 pode ser descartada, pois o navegador do cliente pode ter desativado o uso de cookies.
A solução 3 é a da versão 6 analisada anteriormente. Ela não pode ser utilizada por motivos de segurança. Se o par (login/senha) estiver encapsulado em cada página enviada ao navegador, isso significa que ele transita pela rede a cada troca cliente/servidor. Isso não é bom para a segurança do aplicativo. Pode-se, então, considerar o uso do protocolo HTTPS, que criptografa as trocas cliente/servidor. No entanto, utilizá-lo para cada página do aplicativo aumentará a carga do servidor.
Pode-se querer descartar a solução 1 porque ela também se baseia em cookies. Na primeira troca cliente/servidor, o servidor envia ao cliente um token de sessão, que este reenviará ao servidor a cada nova solicitação. Graças a esse token, o servidor poderá reconhecer seu cliente e atribuir-lhe informações que havia memorizado durante uma troca anterior. O token de sessão é enviado pelo servidor em um cookie. O navegador que não desativou os cookies pode reenviar esse cookie nas solicitações seguintes. Se tiver desativado os cookies, ele dispõe de outra solução: pode incluir o token de sessão na URL que está solicitando. É isso que vemos agora, retomando a análise do arquivo [index.jsp] da versão 4:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<c:redirect url="/main"/>
Vale lembrar que a linha 5 acima redireciona o cliente para a URL [/personne4/main?jsessionid=XX], onde XX é o token de sessão, conforme mostra a captura de tela abaixo, obtida após a solicitação da URL [http://localhost:8080/personne4]:

Vamos examinar mais de perto o funcionamento da tag <c:redirect> no que diz respeito ao token de sessão. Consideremos um navegador em que os cookies são aceitos. A seguir, configuramos o navegador Firefox:

Em [1], habilitamos os cookies e, em [2], excluímos os que já existem para partir de uma situação conhecida. Em seguida, solicitamos a URL [http://localhost:8080/personne4]. Obtemos a seguinte resposta:

A solicitação inicial do cliente, HTTP, foi a seguinte:
Vale ressaltar que o cliente não envia nenhum cookie de sessão. A resposta HTTP enviada pelo servidor é a seguinte:
- linha 1: o servidor solicita que o cliente se redirecione
- linha 3: o servidor envia um token de sessão associado ao atributo [JSESSIONID]
- linha 4: a URL de redirecionamento contém o token de sessão. A tag <c:redirect> o inseriu ali porque o cliente não havia enviado nenhum cookie de sessão.
O navegador, ao qual foi solicitada a redireção, fez então a seguinte solicitação:
- linha 1: ele solicita a URL de redirecionamento, incluindo o token de sessão. É por isso que, na captura de tela, o navegador exibe essa URL.
- linha 10: o navegador reenvia o token de sessão que o servidor lhe enviou na troca anterior. Esse é o funcionamento normal dos cookies quando eles estão habilitados no navegador do cliente. Caso contrário, os cookies recebidos não são reenviados.
O servidor respondeu o seguinte a essa segunda solicitação:
Ele encontrou a página solicitada e a envia. Observe que ele não envia mais o token de sessão. Esse é o funcionamento normal do token de sessão: ele é enviado ao navegador uma única vez pelo servidor na forma de um cookie, e o navegador o reenvia a cada solicitação para ser reconhecido.
Agora, com o mesmo navegador, vamos solicitar novamente a URL [http://localhost:8080/personne4] digitando-a manualmente. Obtemos então a seguinte página:

Percebemos que a URL exibida pelo navegador não contém mais o token de sessão. Vejamos a primeira troca entre cliente e servidor:
O navegador fez a seguinte solicitação:
É exatamente a mesma solicitação da vez anterior, com uma diferença, porém: na linha 10, o navegador reenvia o token de sessão que havia recebido na primeira troca. Mais uma vez, esse é o funcionamento normal se os cookies do navegador estiverem ativos.
O servidor enviou a seguinte resposta:
Ele solicita que o cliente seja redirecionado. Como recebeu um token de sessão do cliente, ele dá continuidade à sessão e não envia um novo token de sessão. Pelo mesmo motivo, a tag <c:redirect> não inclui esse token de sessão na URL de redirecionamento. É por isso que a URL exibida na captura de tela acima não contém nenhum token de sessão.
Diante disso, devemos reter a seguinte regra: a tag <c:redirect> só inclui o token de sessão na URL de redirecionamento se o cliente não tiver enviado o cabeçalho HTTP:
Essa regra também se aplica à tag <c:url>, que veremos mais adiante.
O que acontece com um navegador no qual os cookies foram desativados? Vamos testar. Primeiro, reinicializamos o navegador:

Em [1], desativamos os cookies e, em [2], excluímos os que já existem para partirmos de uma situação conhecida. Em seguida, acessamos a URL [http://localhost:8080/personne4]. Obtemos a seguinte resposta:

Obtemos o mesmo resultado que anteriormente. No entanto, as trocas de dados em HTTP não são exatamente as mesmas:
- linhas 1-9: a solicitação nº 1 do navegador. Ele não envia nenhum cookie de sessão.
- linhas 11-17: a resposta do servidor, que solicita que ele seja redirecionado para outra URL. Ele envia um cookie de sessão na linha 13: a tag <c:redirect> incluiu o token na URL de redirecionamento da linha 14.
- linhas 19-27: a solicitação nº 2 do navegador. Ele não retorna o cookie de sessão que o servidor acabou de enviar porque seus cookies estão desativados.
- linhas 29-33: a resposta do servidor. Percebe-se que, embora o navegador não tenha enviado um cookie de sessão, o servidor não inicia uma nova sessão, como seria de se esperar. Isso fica evidente pelo fato de ele não enviar o cabeçalho HTTP [Set-Cookie], como havia feito na linha 13. Isso significa que ele dá continuidade à sessão anterior. Ele conseguiu recuperá-la graças ao token de sessão presente na URL solicitada pelo navegador na linha 19.
Vale ressaltar que o servidor acompanha uma sessão recuperando o token de sessão enviado pelo cliente de duas maneiras possíveis:
- no cabeçalho HTTP [Set-Cookie] enviado pelo cliente
- na URL solicitada pelo cliente
Agora, com o mesmo navegador, vamos solicitar novamente a URL [http://localhost:8080/personne4] digitando-a manualmente, como foi feito quando os cookies estavam habilitados. Obtemos então a seguinte página:

Temos um resultado diferente daquele obtido quando os cookies estavam permitidos: o token de sessão está na URL exibida pelo navegador. Vamos explicar esse resultado sem analisar as trocas de dados HTTP que ocorreram:
[cookies autorisés]
- na segunda solicitação da URL [http://localhost:8080/personne4], o navegador do cliente havia reenviado o cookie de sessão que havia recebido do servidor na primeira solicitação dessa mesma URL. A tag <c:redirect> não havia, portanto, incluído o token de sessão no endereço de redirecionamento.
[cookies inhibés]
- na segunda solicitação da URL [http://localhost:8080/personne4], o navegador do cliente não envia o cookie de sessão que recebeu do servidor na primeira solicitação dessa mesma URL, uma vez que seus cookies estão desativados. A tag <c:redirect> inclui, portanto, o token de sessão no endereço de redirecionamento. É por isso que ele aparece na captura de tela acima.
As tags <c:redirect> e <c:url> permitem incluir o token de sessão nas URLs. Essa é a solução proposta aqui.
12.2. O projeto Eclipse
Para criar o projeto Eclipse [mvc-personne-07] do aplicativo web [/personne7], duplicaremos o projeto [mvc-personne-06] seguindo o procedimento descrito no parágrafo 6.2.
![]() | ![]() |
12.3. Configuração da aplicação web [personne7]
O arquivo web.xml da aplicação /personne7 é o seguinte:
<?xml version="1.0" encoding="UTF-8"?>
...
<display-name>mvc-personne-07</display-name>
...
Esse arquivo é idêntico ao da versão anterior, exceto pela linha 3, onde o nome de exibição da aplicação web foi alterado para [mvc-personne-07]. A página inicial [index.jsp] permanece inalterada.
...
<c:redirect url="/do/formulaire"/>
12.4. O código das visualizações
As visualizações [formulaire, réponse, erreurs] voltam a ser o que eram na versão 2, c.a.d, sem JavaScript. No entanto, elas mantêm as tags JSTL das versões anteriores.
12.4.1. A visualização [formulaire]

Foram removidos os botões associados ao código JavaScript.
[formulaire.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne - formulaire</title>
</head>
<body>
<center>
<h2>Personne - formulaire</h2>
<hr>
<form name="frmPersonne" action="<c:url value="validationFormulaire"/>" method="post">
<table>
<tr>
<td>Nom</td>
<td><input name="txtNom" value="${nom}" type="text" size="20"></td>
</tr>
<tr>
<td>Age</td>
<td><input name="txtAge" value="${age}" type="text" size="3"></td>
</tr>
<tr>
</table>
<table>
<tr>
<td><input type="submit" name="bouton" value="Envoyer"></td>
<td><input type="reset" value="Rétablir"></td>
<td><input type="submit" name="bouton" value="Effacer"></td>
</tr>
</table>
</form>
</center>
</body>
</html>
- linha 14: a URL de destino do POST é definida com a tag <c:url> para que o token de sessão esteja presente, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
- O formulário possui dois botões do tipo [submit]: [Envoyer] (linha 28) e [Effacer] (linha 30). Ambos os botões têm o mesmo nome: bouton. Ao clicar no POST, o navegador enviará o parâmetro:
- botão=Enviar se a solicitação POST tiver sido acionada pelo botão [Enviar]
- botão=Apagar se a solicitação POST tiver sido acionada pelo botão [Apagar]
É esse parâmetro que nos ajudará a definir a ação exata a ser realizada, já que a URL [/do/validationFormulaire] agora corresponde a duas ações distintas.
12.4.2. A visualização [réponse]

[réponse.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Personne - réponse</h2>
<hr>
<table>
<tr>
<td>Nom</td>
<td>${nom}</td>
</tr>
<tr>
<td>Age</td>
<td>${age}</td>
</tr>
</table>
<br>
<a href="<c:url value="retourFormulaire"/>">${lienRetourFormulaire}</a>
</body>
</html>
- linha 24: a URL de destino do HREF é escrita com a tag <c:url> para que o token de sessão esteja presente, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
12.4.3. A visualização [erreurs]

[erreurs.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<ul>
<c:forEach var="erreur" items="${erreurs}">
<li>${erreur}</li>
</c:forEach>
</ul>
<br>
<a href="<c:url value="retourFormulaire"/>">${lienRetourFormulaire}</a>
</body>
</html>
- linha 18: a URL de destino do HREF é escrita com a tag <c:url> para que o token de sessão esteja presente, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
Recomenda-se ao leitor que teste essas novas visualizações seguindo o princípio apresentado nas versões anteriores.
12.5. O controlador [ServletPersonne]
O controlador [ServletPersonne] do aplicativo web [/personne7] é o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
- linha 35: a ação [/retourFormulaire] é executada por um GET e não mais por um POST, como na versão anterior.
- linhas 70-87: a ação [/validationFormulaire] é executada por um POST, acionado por um clique emum dos botões [Envoyer] ou [Effacer] da visualização [formulaire]. O método [doValidationFormulaire] trata esses dois casos por meio de dois métodos diferentes.
- linhas 90-103: o método [doEnvoyer] corresponde ao método [doValidationFormulaire] da versão anterior. Os dados inseridos são colocados na sessão (linhas 96-98), enquanto na versão anterior eram colocados na consulta.
- linhas 58-67: o novo método [doEffacer] deve exibir um formulário vazio. Seria possível utilizar o método [doInit], que já realiza essa tarefa. Aqui, aproveitamos para também apagar os elementos [nom, age] da sessão, para que ela continue refletindo o estado mais recente do formulário.
- linhas 50-55: solicitam a exibição da visualização [formulaire] sem inicialização aparente do modelo dessa visualização. Esse modelo é, na verdade, constituído pelos elementos [nom, age] que já estão na sessão. Não há necessidade de fazer mais nada.
12.6. Tests
Inicie ou reinicie o Tomcat após ter integrado o projeto Eclipse [personne-mvc-07] e, em seguida, acesse a URL [http://localhost:8080/personne7] com um navegador no qual os cookies foram desativados e os já existentes foram excluídos. Obtém-se a seguinte resposta:

O código-fonte recebido pelo navegador é o seguinte:
Na linha 1, o token de sessão está na URL de destino do POST.
Vamos preencher o formulário e enviá-lo:

O código-fonte recebido pelo navegador é o seguinte:
Linha 3: o token de sessão está na URL de destino do link.

