12. Aplicação web MVC [personne] – versão 7
12.1. Introduction
Nesta versão, partimos do princípio de que podem existir navegadores dos utilizadores que tenham desativado:
- o reenvio dos cookies enviados pelo servidor
- a execução de código JavaScript incorporado nas páginas HTML apresentadas
No entanto, queremos que este tipo de navegadores 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 passou a ser utilizado a partir da versão 3. A versão 2 permitia que a aplicação funcionasse sem JavaScript, pelo que o ponto 2 está resolvido.
O ponto 1 pode ou não ser complicado de gerir. A versão 6 da nossa aplicação funcionava sem cookies. Ao fundir as versões 2 e 6, obtemos o resultado pretendido. Vamos adicionar uma restrição adicional: a aplicação deve gerir uma sessão. Esta restrição não é sem sentido. Numa aplicação em que os utilizadores têm de se autenticar, o servidor deve memorizar o par (identificador/palavra-passe) do utilizador para evitar que este tenha de se autenticar em cada página que solicitar.
Até agora, utilizámos três soluções para memorizar informações ao longo das trocas cliente/servidor:
- a sessão
- os cookies
- os campos ocultos.
A solução 2 pode ser descartada, uma vez que o navegador do cliente pode ter desativado a utilização de cookies.
A solução 3 é a da versão 6 anteriormente analisada. Não pode ser utilizada por razões de segurança. Se o par (nome de utilizador/palavra-passe) estiver encapsulado em cada página enviada ao navegador, isso significa que transita pela rede em cada troca cliente/servidor. Isto não é bom para a segurança da aplicação. Pode-se 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 irá sobrecarregar o servidor.
Poder-se-ia querer eliminar a solução 1 porque também se baseia em cookies. Durante a primeira troca cliente/servidor, o servidor envia ao cliente um token de sessão que este irá reenviar ao servidor em cada nova solicitação. Graças a este token, o servidor poderá reconhecer o seu cliente e atribuir-lhe informações que tinha memorizado durante uma troca anterior. O token de sessão é enviado pelo servidor num cookie. O navegador que não tenha desativado os cookies pode reenviar esse cookie nas suas solicitações seguintes. Se tiver desativado os cookies, dispõe de outra solução: pode incluir o token de sessão no URL que solicita. É isso que vemos agora, retomando a análise do 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 a URL [/personne4/main?jsessionid=XX], em que XX é o token de sessão, tal como mostra a captura de ecrã abaixo, obtida após ter solicitado a URL [http://localhost:8080/personne4]:

Vamos analisar mais detalhadamente o funcionamento da tag <c:redirect> no que diz respeito ao token de sessão. Consideremos um navegador em que os cookies são aceites. Abaixo, configuramos o navegador Firefox:

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

O pedido inicial do cliente, HTTP, foi o seguinte:
Note-se simplesmente que o cliente não envia nenhum cookie de sessão. A resposta HTTP enviada pelo servidor é a seguinte:
- linha 1: o servidor solicita ao cliente que se 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> inseriu-o ali porque o cliente não tinha enviado nenhum cookie de sessão.
O navegador, ao qual foi solicitado que se redirecionasse, efetuou então o seguinte pedido:
- linha 1: solicita o URL de redirecionamento, incluindo o token de sessão. É por isso que, na captura de ecrã, o navegador apresenta esse URL.
- linha 10: o navegador reenvia o token de sessão que o servidor lhe enviou na troca anterior. Este é o funcionamento normal dos cookies quando estes estão autorizados no navegador do cliente. Se não for esse o caso, os cookies recebidos não são reenviados.
O servidor respondeu o seguinte a esta segunda solicitação:
Encontrou a página que lhe foi solicitada e envia-a. Note-se que já não envia o token de sessão. Este é o funcionamento normal do token de sessão: é enviado ao navegador uma única vez pelo servidor sob a forma de um cookie e o navegador reenvia-o posteriormente em cada pedido 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:

Verifica-se que a URL apresentada pelo navegador já não contém o token de sessão. Vejamos a primeira troca de dados entre o cliente e o servidor:
O navegador efetuou o seguinte pedido:
É exatamente a mesma solicitação da vez anterior, mas com uma diferença: na linha 10, o navegador reenvia o token de sessão que tinha recebido na primeira troca. Mais uma vez, este é o funcionamento normal se os cookies do navegador estiverem ativos.
O servidor enviou a seguinte resposta:
Solicita ao cliente que se redirecione. Como recebeu um token de sessão do cliente, dá continuidade à mesma 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 nenhum token de sessão.
Daqui, fica 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:
Esta regra também se aplica à tag <c:url>, com a qual teremos oportunidade de nos deparar mais tarde.
O que acontece num navegador em que os cookies foram desativados? Vamos experimentar. Primeiro, reiniciamos o navegador:

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

Obtemos o mesmo resultado que anteriormente. No entanto, as trocas HTTP não são exatamente as mesmas:
- linhas 1-9: o pedido n.º 1 do navegador. Este não envia nenhum cookie de sessão.
- linhas 11-17: a resposta do servidor que lhe pede para redirecionar-se para outro URL. Envia um cookie de sessão na linha 13: a tag <c:redirect> incluiu o token no URL de redirecionamento da linha 14.
- linhas 19-27: o pedido n.º 2 do navegador. Este não devolve o cookie de sessão que o servidor acabou de lhe enviar, porque os seus cookies estão desativados.
- linhas 29-33: a resposta do servidor. É possível constatar que, embora o navegador não lhe tenha enviado um cookie de sessão, o servidor não inicia, no entanto, uma nova sessão, como seria de esperar. Isto verifica-se pelo facto de não enviar o cabeçalho HTTP [Set-Cookie], tal como tinha feito na linha 13. Isto significa que dá continuidade à sessão anterior. Conseguiu recuperá-la graças ao token de sessão presente no URL solicitado pelo navegador na linha 19.
É importante notar que o servidor acompanha 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, com o mesmo navegador, vamos solicitar novamente a URL [http://localhost:8080/personne4], digitando-a manualmente, tal como foi feito quando os cookies estavam autorizados. Obtemos então a seguinte página:

Temos um resultado diferente do obtido quando os cookies estavam autorizados: o token de sessão está na URL apresentada pelo navegador. Vamos explicar este 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 tinha reenviado o cookie de sessão que tinha recebido do servidor na primeira solicitação dessa mesma URL. A tag <c:redirect> não tinha, 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 os 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 ecrã acima.
As tags <c:redirect> e <c:url> permitem 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] da aplicação 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 ficheiro web.xml da 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] não sofre alterações.
...
<c:redirect url="/do/formulaire"/>
12.4. O código das vistas
As vistas [formulaire, réponse, erreurs] voltam a ser o que eram na versão 2, c.a.d, sem JavaScript. No entanto, mantêm as balizas JSTL das últimas versões.
12.4.1. A vista [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: o URL de destino do POST é escrito com a baliza <c:url> para que o token de sessão nele conste, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
- O formulário tem dois botões do tipo [submit]: [Envoyer] (linha 28) e [Effacer] (linha 30). Ambos os botões têm o mesmo nome: bouton. Quando o POST for acionado, o navegador enviará o parâmetro:
- botão=Enviar se o POST tiver sido desencadeado pelo botão [Enviar]
- botão=Apagar se a solicitação POST tiver sido desencadeada pelo botão [Apagar]
É este parâmetro que nos ajudará a definir a ação exata a realizar, uma vez que a URL [/do/validationFormulaire] corresponde agora a duas ações distintas.
12.4.2. A vista [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 baliza <c:url> para que o token de sessão nela conste, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
12.4.3. A vista [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: o URL de destino do HREF é escrito com a baliza <c:url> para que o token de sessão nele conste, caso o cliente seja um navegador que não envie o cabeçalho HTTP [Cookie].
Convidamos o leitor a testar estas novas vistas seguindo o princípio apresentado nas versões anteriores.
12.5. O controlador [ServletPersonne]
O controlador [ServletPersonne] da 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 por um GET e já não por um POST, como na versão anterior.
- linhas 70-87: a ação [/validationFormulaire] é executada por um POST, acionado por um clique numum dos botões [Envoyer] ou [Effacer] da vista [formulaire]. O método [doValidationFormulaire] trata estes dois casos através de 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 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 apresentar um formulário vazio. Seria possível recorrer ao método [doInit], que já realiza essa tarefa. Aproveita-se esta oportunidade para eliminar também os elementos [nom, 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 [formulaire] sem inicialização aparente do modelo dessa vista. Este modelo é, na verdade, constituído pelos elementos [nom, age] já presentes na sessão. Não é necessário fazer mais nada.
12.6. Tests
Inicie ou reinicie o Tomcat após ter integrado o projeto Eclipse [personne-mvc-07] e, em seguida, aceda ao URL [http://localhost:8080/personne7] com um navegador no qual os cookies foram desativados e os já existentes foram eliminados. Obtém-se a seguinte resposta:

O código-fonte recebido pelo navegador é o seguinte:
Na linha 1, o token de sessão encontra-se no URL de destino de POST.
Preenchamos o formulário e submetamo-lo:

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

