12. Aplicação Web MVC [person] – Versão 7
12.1. Introdução
Nesta versão, partimos do princípio de que poderá haver navegadores de clientes que tenham desativado:
- o envio de cookies pelo servidor
- a execução de código JavaScript incorporado nas páginas HTML apresentadas
No entanto, queremos que este tipo de navegador possa utilizar a nossa aplicação. O ponto 2 remete-nos para a versão 2 da nossa aplicação, uma vez que o JavaScript foi introduzido a partir da versão 3. A versão 2 executava a aplicação sem JavaScript, pelo que o ponto 2 fica resolvido.
O ponto 1 pode ou não ser difícil de resolver. A versão 6 da nossa aplicação funcionava sem cookies. Ao combinar as versões 2 e 6, alcançamos o resultado desejado. Iremos adicionar uma restrição adicional: a aplicação deve gerir uma sessão. Esta não é uma restrição sem sentido. Numa aplicação em que os utilizadores têm de se autenticar, o servidor deve armazenar o nome de utilizador e a palavra-passe do utilizador para evitar que este tenha de se autenticar em todas as páginas que solicitar.
Até agora, utilizámos três soluções para armazenar informações durante as trocas cliente/servidor:
- a sessão
- cookies
- campos ocultos.
A solução 2 pode ser descartada, uma vez que o navegador do cliente pode ter desativado os cookies.
A solução 3 é a da versão 6, que analisámos anteriormente. Não pode ser utilizada por motivos de segurança. Se o par nome de utilizador/palavra-passe estiver incorporado em todas as páginas enviadas para o navegador, isso significa que viaja pela rede em todas as trocas cliente-servidor. Isto não é bom para a segurança da aplicação. Poderíamos então considerar a utilização do protocolo HTTPS, que encripta as trocas cliente-servidor. No entanto, utilizá-lo em todas as páginas da aplicação aumentará a carga do servidor.
Poderá querer descartar a Solução 1, uma vez que esta também depende de cookies. Durante a primeira troca cliente-servidor, o servidor envia ao cliente um token de sessão, que o cliente, por sua vez, reenvia ao servidor em cada novo pedido. Graças a este token, o servidor consegue reconhecer o cliente e fornecer-lhe as informações que tinha armazenado durante uma troca anterior. O token de sessão é enviado pelo servidor num cookie. Um navegador que não tenha desativado os cookies pode reenviar este cookie ao servidor em pedidos subsequentes. Se os cookies estiverem desativados, existe outra solução: o navegador pode incluir o token de sessão no URL que solicita. É isto que vemos agora ao revisitar o ficheiro [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"/>
Recorde-se que a linha 5 acima redireciona o cliente para o URL [/personne4/main?jsessionid=XX], onde XX é o token de sessão, conforme mostrado na captura de ecrã abaixo, obtida após solicitar o URL [http://localhost:8080/personne4]:

Vamos analisar mais detalhadamente como a tag <c:redirect> funciona no que diz respeito ao token de sessão. Vamos utilizar um navegador que aceite cookies. Abaixo, configuramos o navegador Firefox:

Em [1], ativamos os cookies e, em [2], eliminamos todos os existentes para começar a partir de um estado conhecido. Em seguida, solicitamos a URL [http://localhost:8080/personne4]. Recebemos a seguinte resposta:

O pedido HTTP inicial do cliente foi o seguinte:
Note que o cliente não envia um cookie de sessão. A resposta HTTP enviada pelo servidor é a seguinte:
- Linha 1: O servidor solicita ao cliente que redirecione
- linha 3: o servidor envia um token de sessão associado ao atributo [JSESSIONID]
- linha 4: o URL de redirecionamento contém o token de sessão. A tag <c:redirect> colocou-o lá porque o cliente não tinha enviado um cookie de sessão.
O navegador, ao qual foi solicitado o redirecionamento, efetuou então o seguinte pedido:
- Linha 1: Solicita o URL de redirecionamento, incluindo o token de sessão. É por isso que o navegador exibe este URL na captura de ecrã.
- Linha 10: O navegador reenvia o token de sessão que o servidor lhe enviou na troca anterior. É assim que os cookies funcionam normalmente quando estão ativados no navegador do cliente. Se não estiverem ativados, os cookies recebidos não são reenviados.
O servidor respondeu a esta segunda solicitação com o seguinte:
Encontrou a página solicitada e está a enviá-la. Note que já não envia o token de sessão. É assim que os tokens de sessão funcionam normalmente: o servidor envia-o ao navegador uma vez na forma de um cookie, e o navegador, por sua vez, reenvia-o com cada pedido para ser reconhecido.
Agora, utilizando o mesmo navegador, vamos solicitar novamente a URL [http://localhost:8080/personne4] digitando-a manualmente. Obtemos então a seguinte página:

Podemos ver que a URL apresentada pelo navegador já não contém o token de sessão. Vejamos a primeira troca cliente/servidor:
O navegador efetuou a seguinte solicitação:
Esta é exatamente a mesma solicitação que a anterior, com uma diferença: na linha 10, o navegador reenvia o token de sessão que recebeu durante a primeira troca. Mais uma vez, este é um comportamento normal se os cookies do navegador estiverem ativados.
O servidor enviou a seguinte resposta:
Instrui o cliente a redirecionar. Uma vez que recebeu um token de sessão do cliente, continua a sessão e não envia um novo token de sessão. Pela mesma razão, a tag <c:redirect> não inclui este token de sessão no URL de redirecionamento. É por isso que o URL apresentado na captura de ecrã acima não contém um token de sessão.
A principal conclusão de tudo isto é a seguinte regra: a tag <c:redirect> só inclui o token de sessão no URL de redirecionamento se o cliente não tiver enviado o cabeçalho HTTP:
Esta regra também se aplica à tag <c:url>, que iremos abordar mais adiante.
O que acontece com um navegador no qual os cookies foram desativados? Vamos experimentar. Primeiro, reiniciamos o navegador:

Em [1], desativamos os cookies e, em [2], eliminamos todos os existentes para começar a partir de um estado conhecido. Em seguida, solicitamos a URL [http://localhost:8080/personne4]. Obtemos a seguinte resposta:

Obtemos o mesmo resultado que antes. No entanto, as trocas HTTP não são exatamente as mesmas:
- Linhas 1–9: A primeira solicitação do navegador. Não envia um cookie de sessão.
- Linhas 11–17: A resposta do servidor, que instrui o navegador a redirecionar para outro URL. Envia um cookie de sessão. Linha 13: A tag <c:redirect> incluiu o token no URL de redirecionamento na linha 14.
- Linhas 19–27: A segunda solicitação do navegador. Ele não reenvia o cookie de sessão que o servidor acabou de enviar porque os seus cookies estão desativados.
- Linhas 29–33: A resposta do servidor. Podemos ver 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 esperar. Isto é evidente pelo facto de não enviar o cabeçalho HTTP [Set-Cookie], como fez na linha 13. Isto significa que continua a sessão anterior. Conseguiu recuperar esta sessão graças ao token de sessão presente no URL solicitado pelo navegador na linha 19.
Note-se que o servidor rastreia uma sessão recuperando o token de sessão enviado pelo cliente de duas formas possíveis:
- no cabeçalho HTTP [Set-Cookie] enviado pelo cliente
- na URL solicitada pelo cliente
Agora, utilizando o mesmo navegador, vamos solicitar novamente a URL [http://localhost:8080/personne4] digitando-a manualmente, tal como fizemos quando os cookies estavam ativados. Obtemos então a seguinte página:

O resultado é diferente do que vimos quando os cookies estavam permitidos: o token de sessão está na URL apresentada pelo navegador. Vamos explicar este resultado sem analisar as trocas HTTP que ocorreram:
[cookies ativados]
- Durante a segunda solicitação da URL [http://localhost:8080/personne4], o navegador do cliente reenviou o cookie de sessão que tinha recebido do servidor durante a primeira solicitação dessa mesma URL. A tag <c:redirect> não incluiu, portanto, o token de sessão no endereço de redirecionamento.
[cookies desativados]
- Durante o segundo pedido para o URL [http://localhost:8080/personne4], o navegador do cliente não envia o cookie de sessão que recebeu do servidor durante o primeiro pedido para esse mesmo URL, uma vez que os seus cookies estão desativados. A tag <c:redirect> inclui, portanto, o token de sessão no URL de redirecionamento. É por isso que este aparece na captura de ecrã acima.
As tags <c:redirect> e <c:url> permitem-lhe incluir o token de sessão nas URLs. Esta é a solução aqui proposta.
12.2. O projeto Eclipse
Para criar o projeto Eclipse [mvc-personne-07] para a aplicação web [/personne7], duplique o projeto [mvc-personne-06] seguindo o procedimento descrito na secção 6.2.
![]() | ![]() |
12.3. Configurar a aplicação web [personne7]
O ficheiro web.xml para a aplicação /personne7 é o seguinte:
<?xml version="1.0" encoding="UTF-8"?>
...
<display-name>mvc-personne-07</display-name>
...
Este ficheiro é idêntico ao da versão anterior, exceto na linha 3, onde o nome de exibição da aplicação web mudou para [mvc-personne-07]. A página inicial [index.jsp] permanece inalterada.
...
<c:redirect url="/do/formulaire"/>
12.4. O código da vista
As vistas [form, response, errors] voltam a ser como eram na versão 2, ou seja, sem JavaScript. No entanto, mantêm as tags JSTL das versões mais recentes.
12.4.1. A vista [form]

Os botões associados ao código JavaScript foram removidos.
[form.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: O URL de destino do POST é escrito utilizando a tag <c:url> para que o token de sessão seja incluído, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
- O formulário tem dois botões [submit]: [Submit] (linha 28) e [Clear] (linha 30). Ambos os botões têm o mesmo nome: button. Quando o POST é acionado, o navegador enviará o parâmetro:
- button=Submit se o POST tiver sido acionado pelo botão [Submit]
- button=Clear se o POST tiver sido acionado pelo botão [Clear]
Este parâmetro irá ajudar-nos a determinar a ação exata a tomar, uma vez que a URL [/do/validationFormulaire] corresponde agora a duas ações distintas.
12.4.2. A vista [response]

[response.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: O URL de destino do HREF é escrito utilizando a tag <c:url>, de modo a incluir o token de sessão, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
12.4.3. A vista [errors]

[errors.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: O URL de destino HREF é escrito utilizando a tag <c:url> para que o token de sessão seja incluído, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
Convidamos os leitores a testar estas novas visualizações utilizando a mesma abordagem das versões anteriores.
12.5. O controlador [ServletPersonne]
O controlador [ServletPersonne] para a aplicação 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 através de uma solicitação GET, em vez de uma solicitação POST como na versão anterior.
- linhas 70–87: A ação [/validationFormulaire] é acionada por uma solicitação POST, resultante do clique num dos botões [Envoyer] ou [Effacer] na visualização [form]. O método [doValidationFormulaire] lida com estes dois casos utilizando dois métodos diferentes.
- linhas 90–103: O método [doEnvoyer] corresponde ao método [doValidationFormulaire] da versão anterior. Os dados introduzidos são armazenados na sessão (linhas 96–98), enquanto na versão anterior eram colocados na solicitação.
- Linhas 58–67: O novo método [doEffacer] deve apresentar um formulário vazio. Poderíamos chamar o método [doInit], que já executa esta tarefa. Aqui, aproveitamos a oportunidade para limpar também os elementos [name, age] da sessão, para que esta continue a refletir o estado mais recente do formulário.
- Linhas 50–55: solicitam a exibição da vista [form] sem qualquer inicialização aparente do modelo da vista. Este modelo é, na verdade, composto pelos elementos [name, age] já presentes na sessão. Não é necessária qualquer ação adicional.
12.6. Testes
Inicie ou reinicie o Tomcat após integrar o projeto Eclipse [personne-mvc-07] nele e, em seguida, solicite a URL [http://localhost:8080/personne7] utilizando um navegador com cookies desativados e os cookies existentes eliminados. Obtém-se a seguinte resposta:

O código-fonte recebido pelo navegador é o seguinte:
Linha 1: O token da sessão está no 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 da sessão encontra-se no URL de destino do link.

