6. Aplicação web MVC [personne] – versão 2
Vamos agora propor variantes da aplicação [/personne1] anterior, às quais daremos o nome de [/personne2, /personne3, ...]. Estas variantes não alteram a arquitetura inicial da aplicação, que continua a ser a seguinte:

Para estas variantes, as nossas explicações serão mais sucintas. Apresentaremos apenas as alterações introduzidas em relação à versão anterior.
6.1. Introduction
Propomos agora adicionar à nossa aplicação uma gestão de sessões. Recorde-se o seguinte:
- o diálogo cliente-servidor HTTP é uma sucessão de sequências de pedido-resposta independentes umas das outras
- a sessão funciona como memória entre diferentes sequências de pedido-resposta de um mesmo utilizador. Se houver N utilizadores, haverá N sessões.
A seguinte sequência de ecrãs mostra o que agora se pretende no funcionamento da aplicação:
Intercâmbio n.º 1
![]() | ![]() |
A novidade reside no link de retorno ao formulário, que foi adicionado à vista [erreurs].
Troca n.º 2
![]() | ![]() |
Na troca n.º 1, o utilizador forneceu os valores (xx, yy) para o par (nome, idade). Se, durante a troca, o servidor tiver tomado conhecimento desses valores, no final da troca «esquece-os». No entanto, verifica-se que, durante a troca n.º 2, o servidor consegue voltar a apresentar esses valores na sua resposta. É o conceito de sessão que, neste caso, permite ao servidor web memorizar dados ao longo das sucessivas trocas cliente-servidor. Existem outras soluções possíveis para resolver este problema.
Durante a troca n.º 1, o servidor vai memorizar na sessão o par (nome, idade) que o cliente lhe enviou, para poder apresentá-lo durante a troca n.º 2.
Eis outro exemplo de implementação da sessão entre duas interações:
Intercâmbio n.º 1
![]() | ![]() |
A novidade reside no link de regresso ao formulário, que foi adicionado à página da resposta.
Intercâmbio n.º 2
![]() | ![]() |
6.2. O projeto Eclipse
Para criar o projeto Eclipse [mvc-personne-02] da aplicação web [/personne2], vamos duplicar o projeto Eclipse [mvc-personne-01] para recuperar o que já existe. Para tal, procedamos da seguinte forma:
[clic droit sur projet mvc-personne-01 -> Copy]:

e, em seguida, [clic droit dans Package Explorer -> Paste]:
![]() | ![]() - definamos em [1] o nome do novo projeto e em [2] o nome de uma pasta existente, mas vazia |
O projeto [mvc-personne-02] é então criado:

Por enquanto, é idêntico ao projeto [mvc-personne-01]. Teremos de fazer algumas alterações manualmente antes de o podermos utilizar. Vamos à vista [Servers] e tentemos adicionar esta nova aplicação às que são geridas pelo Tomcat:
![]() | ![]() |
Verifica-se que, no [1], o novo projeto [mvc-personne-02] não é detetado pelo Tomcat. Para que este o detete, é necessário alterar um ficheiro de configuração do projeto [mvc-personne-02]. Vamos utilizar a opção [File / Open File] para abrir o ficheiro [<mvc-personne-02>/.settings/.component]:
<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId">
<wb-module deploy-name="mvc-personne-01">
<wb-resource deploy-path="/" source-path="/WebContent"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
<property name="java-output-path" value="/build/classes/"/>
<property name="context-root" value="personne1"/>
</wb-module>
</project-modules>
A linha 3 indica o nome do módulo web a ser implementado no Tomcat. Este nome é, neste caso, o mesmo que o do projeto [mvc-personne-01]. Alteramo-lo para [mvc-personne-02]:
<wb-module deploy-name="mvc-personne-02">
Além disso, podemos aproveitar para alterar, na linha 7, o nome do contexto da aplicação [mvc-personne-02], que está em conflito com o do projeto [mvc-personne-01]:
<property name="context-root" value="personne2"/>
Esta segunda alteração poderia ter sido feita diretamente no Eclipse. No entanto, não vi como fazer a primeira sem recorrer ao ficheiro de configuração.
Feito isto, guardamos o novo ficheiro [.content], saímos e reiniciamos o Eclipse para que as alterações sejam aplicadas.
Depois de reiniciar o Eclipse, vamos tentar realizar a operação que falhou anteriormente:
![]() | ![]() |
Desta vez, o projeto [mvc-personne-02] é reconhecido corretamente. Adicionamo-lo aos projetos configurados para serem executados pelo Tomcat:

6.3. Configuração da aplicação web [personne2]
O ficheiro web.xml da aplicação /pessoa2 é o seguinte:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>mvc-personne-02</display-name>
<!-- ServletPersonne -->
<servlet>
<servlet-name>personne</servlet-name>
<servlet-class>
istia.st.servlets.personne.ServletPersonne
</servlet-class>
<init-param>
<param-name>urlReponse</param-name>
<param-value>
/WEB-INF/vues/reponse.jsp
</param-value>
</init-param>
<init-param>
<param-name>urlErreurs</param-name>
<param-value>
/WEB-INF/vues/erreurs.jsp
</param-value>
</init-param>
<init-param>
<param-name>urlFormulaire</param-name>
<param-value>
/WEB-INF/vues/formulaire.jsp
</param-value>
</init-param>
<init-param>
<param-name>urlControleur</param-name>
<param-value>
main
</param-value>
</init-param>
<init-param>
<param-name>lienRetourFormulaire</param-name>
<param-value>
Retour au formulaire
</param-value>
</init-param>
</servlet>
<!-- Mapeamento ServletPersonne-->
<servlet-mapping>
<servlet-name>personne</servlet-name>
<url-pattern>/main</url-pattern>
</servlet-mapping>
<!-- ficheiros de acolhimento -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Este ficheiro é idêntico ao da versão anterior, exceto pelo facto de declarar dois novos parâmetros de inicialização:
- linha 6: o nome de exibição da aplicação web foi alterado para [mvc-personne-02]
- linhas 31-36: definem o parâmetro de configuração denominado [urlControleur], que corresponde ao URL [main], o qual remete para o servlet [ServletPersonne]
- linhas 37-42: definem um parâmetro de configuração denominado [lienRetourFormulaire], que corresponde ao texto do link de retorno para o formulário nas páginas JSP, [erreurs.jsp] e [reponse.jsp].
A página inicial [index.jsp] altera-se:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
response.sendRedirect("/personne2/main");
%>
- linha 5: a página [index.jsp] redireciona o cliente para o URL do controlador [ServletPersonne] da aplicação [/personne2].
6.4. O código das vistas
6.4.1. A vista [formulaire]
Esta vista é idêntica à da versão anterior:

É gerada pela página JSP [formulaire.jsp] seguinte:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
// Recuperam-se os dados do modelo
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
<html>
<head>
<title>Personne - formulaire</title>
</head>
<body>
<center>
<h2>Personne - formulaire</h2>
<hr>
<form action="<%=urlAction%>" 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" value="Envoyer"></td>
<td><input type="reset" value="Rétablir"></td>
<td><input type="button" value="Effacer"></td>
</tr>
</table>
<input type="hidden" name="action" value="validationFormulaire">
</form>
</center>
</body>
</html>
Novidades:
- na linha 19, o formulário tem agora um atributo [action] cujo valor é o URL para o qual o navegador deverá enviar os valores do formulário quando o utilizador clicar no botão [Envoyer] do tipo submit. A variável [urlAction] terá o valor action="main". A vista [formulaire] é apresentada após as seguintes ações do utilizador:
- pedido inicial: GET /pessoa2/main
- clique no link [Retour au formulaire]: GET /pessoa2/main?action=retourFormulaire
Como o atributo [action] não especifica um URL absoluto (que começa por /), mas sim um URL relativo (que não começa por /), o navegador irá utilizar a primeira parte do URL da página atualmente exibida, [/personne2], e adicionar-lhe o URL relativo. A URL de POST será, portanto, [/personne2/main], a do controlador. Esta solicitação POST será acompanhada pelos parâmetros [txtNom, txtAge, action] das linhas 23, 27 e 38.
- linha 8: recupera-se o valor do elemento [urlAction] do modelo. Este é procurado nos atributos da solicitação atual. Será utilizado na linha 19.
- linhas 6-7: recuperam-se os valores dos elementos [nom, age] do modelo. Estes são procurados nos atributos da sessão e não mais nos da consulta, como na versão anterior. Isto para responder às necessidades da consulta [GET /personne2/main?action=retourFormulaire] do link das vistas [réponse] e [erreurs]. Antes de apresentar estas duas vistas, o controlador coloca na sessão os dados introduzidos no formulário, o que lhe permite recuperá-los quando o utilizador utiliza o link [Retour au formulaire] das vistas [réponse] e [erreurs].
6.4.2. A vista [reponse]
Esta vista apresenta os valores introduzidos no formulário quando estes são válidos:
![]() | ![]() |
Em relação à versão anterior, a novidade reside na ligação [Retour au formulaire]. A vista é gerada pela página seguinte: JSP [reponse.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">
<%
// recuperam-se os dados do modelo
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Personne - réponse</h2>
<hr>
<table>
<tr>
<td>Nom</td>
<td><%= nom %>
</tr>
<tr>
<td>Age</td>
<td><%= age %>
</tr>
</table>
<br>
<a href="?action=retourFormulaire"><%= lienRetourFormulaire %></a>
</body>
</html>
- linha 31: o link de regresso ao formulário. Este link tem dois componentes:
- o destino [href="?action=retourFormulaire"]. A vista [réponse] é apresentada após a POST do formulário [formulaire.jsp] na URL [/personne2/main]. É, portanto, esta última URL que é apresentada no navegador quando a vista [réponse] é apresentada. Um clique no link [Retour au formulaire] provocará, então, uma solicitação GET do navegador para a URL especificada pelo atributo [href] do link, neste caso «?action=retourFormulaire». Na ausência de uma URL em [href], o navegador utilizará a da vista atualmente exibida, c.a.d. [/personne2/main]. Por fim, ao clicar no link [Retour au formulaire], o navegador irá efetuar uma requesta GET para a URL [/personne2/main?action=retourFormulaire], c.a.d, a URL do controlador da aplicação, acompanhada do parâmetro [action] para lhe indicar o que deve fazer.
- o texto do link. Este fará parte do modelo transmitido à página pelo controlador e recuperado na linha 10.
6.4.3. A vista [erreurs]
Esta vista sinaliza os erros de introdução de dados no formulário:
![]() | ![]() |
Em relação à versão anterior, a novidade reside no link [Retour au formulaire]. A vista é gerada pela página JSP [erreurs.jsp] seguinte:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ page import="java.util.ArrayList" %>
<%
// recuperam-se os dados do modelo
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<ul>
<%
for(int i=0;i<erreurs.size();i++){
out.println("<li>" + (String) erreurs.get(i) + "</li>\n");
}//para
%>
</ul>
<br>
<a href="?action=retourFormulaire"><%= lienRetourFormulaire %></a>
</body>
</html>
- linha 26: o link de regresso ao formulário. Este link é idêntico ao da vista [réponse]. Recomenda-se ao leitor que, se necessário, releia as explicações fornecidas para esta vista.
6.5. Testes das vistas
Para realizar os testes das vistas anteriores, duplicamos as respetivas páginas JSP na pasta /WebContent/JSP do projeto Eclipse:

Em seguida, na pasta JSP, as páginas são alteradas da seguinte forma:
[formulaire.jsp]:
...
<%
// -- teste: cria-se o modelo da página
session.setAttribute("nom","tintin");
session.setAttribute("age","30");
request.setAttribute("urlAction","main");
%>
<%
// recuperam-se os dados do modelo
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
As linhas 4-5 foram adicionadas para criar o modelo necessário à página das linhas 11-13.
[reponse.jsp]:
<%
// -- teste: cria-se o modelo da página
request.setAttribute("nom","milou");
request.setAttribute("age","10");
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// recuperam-se os dados do modelo
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
As linhas 4-6 foram adicionadas para criar o modelo necessário para a página das linhas 11-13.
[erreurs.jsp]:
<%
// -- teste: cria-se o modelo da página
ArrayList<String> erreurs1=new ArrayList<String>();
erreurs1.add("erreur1");
erreurs1.add("erreur2");
request.setAttribute("erreurs",erreurs1);
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// recuperam-se os dados do modelo
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
As linhas 4-8 foram adicionadas para criar o modelo necessário para a página das linhas 13-14.
Iniciemos o Tomcat, se ainda não o tivermos feito, e acedamos às seguintes URLs:
![]() | ![]() |
![]() |
Obtenemos, de facto, as visualizações esperadas.
6.6. O controlador [ServletPersonne]
O controlador [ServletPersonne] da aplicação web [/personne2] irá processar as seguintes ações:
n.º | pedido | origem | processamento |
1 | [GET /personne2/main] | URL introduzida pelo utilizador | - enviar a vista [formulaire] vazia |
2 | [POST /personne2/main] com parâmetros [txtNom, txtAge, ação] enviados | clicar no botão [Envoyer] da vista [formulaire] | - verificar os valores dos parâmetros [txtNom, txtAge] - se estiverem incorretos, enviar a vista [erreurs(erreurs)] - se estiverem corretos, enviar a vista [reponse(nom,age)] |
3 | [GET /pessoa2/main? action=retourFormulaire] | clique na ligação [Voltar ao formulário] das visualizações resposta] e [erreurs]. | - enviar a vista [formulaire] pré-preenchida com os últimos valores introduzidos |
Temos, portanto, uma nova ação a tratar: [GET /personne2/main?action=retourFormulaire].
6.6.1. Estrutura do controlador
A estrutura do controlador [ServletPersonne] é praticamente idêntica à da versão anterior:
Novidades:
- linha 4: a utilização de uma sessão obriga a importar o pacote [HttpSession]
- linhas 28-30: o novo método [doRetourFormulaire] processa a nova ação: [GET /personne2/main?action=retourFormulaire].
6.6.2. Inicialização do controlador [init]
O método [init] é idêntico ao da versão anterior. Verifica a presença, no ficheiro [web.xml], dos elementos declarados na tabela [paramètres]:
- linha 5: foram adicionados os parâmetros [urlControleur] (URL do controlador) e [lienRetourFormulaire] (texto do link das vistas [réponse] e [erreurs]).
6.6.3. O método [doGet]
O método [doGet] deve processar a ação [GET /personne2/main?action=retourFormulaire], que anteriormente não existia:
- linhas 6-14: verifica-se se a lista de erros de inicialização está vazia. Se não for esse o caso, é apresentada a vista [erreurs(erreursInitialisation)], que irá sinalizar o(s) erro(s).
Para compreender este código, é necessário recordar o modelo da vista [erreurs]:
<%
// recuperação dos dados do modelo
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
A vista [erreurs] espera um elemento-chave «erros» na consulta. O controlador cria esse elemento na linha 8. Espera também um elemento-chave «lienRetourFormulaire». O controlador cria esse elemento na linha 9. Aqui, o texto do link ficará vazio. Portanto, não haverá qualquer link na vista [erreurs] enviada. Com efeito, se tiverem ocorrido erros na inicialização da aplicação, esta deve ser reconfigurada. Não há motivo para propor ao utilizador que continue a aplicação através de um link.
- linhas 34-37: processamento da nova ação [GET /personne2/main?action=retourFormulaire]
6.6.4. O método [doInit]
Este método processa a solicitação n.º 1 [GET /personne2/main]. Nesta solicitação, deve enviar a vista [formulaire(nom,age)] vazia. O seu código é o seguinte:
- linha 4: a sessão atual é recuperada, se existir; caso contrário, é criada (parâmetro true de getSession).
- linhas 9-10: a vista [formulaire] é apresentada. Recorde-se o modelo esperado por esta vista:
<%
// recuperam-se os dados do modelo
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
- linhas 6-7: os elementos [nom,age] do modelo da vista [formulaire] são inicializados com cadeias de caracteres vazias e colocados na sessão, pois é aí que a vista os espera.
- linha 8: o elemento [urlAction] do modelo é inicializado com o valor do parâmetro [urlControleur] do ficheiro [web.xml] e colocado na consulta.
6.6.5. O método [doValidationFormulaire]
Este método processa a consulta n.º 2 [POST /personne2/main], na qual os parâmetros enviados são [action, txtNom, txtAge]. O seu código é o seguinte:
- linhas 5-6: recuperam-se da solicitação do cliente os valores dos parâmetros «txtNom» e «txtAge».
- linhas 8-10: estes valores são armazenados na sessão para que possam ser recuperados quando o utilizador clicar na ligação [Retour au formulaire] das visualizações [réponse] e [erreurs].
- linhas 12-19: verifica-se a validade dos valores dos dois parâmetros
- linhas 21-28: se algum dos parâmetros estiver errado, é apresentada a vista [erreurs(erreurs,lienRetourFormulaire)]. Recorde-se o modelo desta vista:
<%
// recuperam-se os dados do modelo
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
- linhas 30-34: se os dois parâmetros «txtNom» e «txtAge» recuperados tiverem valores válidos, é apresentada a vista [reponse(nom,age,lienRetourFormulaire)]. É importante recordar o modelo da vista [reponse]:
<%
// recuperam-se os dados do modelo
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
6.6.6. O método [doRetourFormulaire]
Este método processa a consulta n.º 3 [GET /personne2/main?action=retourFormulaire]. O seu código é o seguinte:
No final deste método, deve ser apresentada a vista [formulaire] pré-preenchida com as últimas entradas efetuadas pelo utilizador. Recorde-se o modelo da vista [formulaire]:
<%
// recuperam-se os dados do modelo
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
O método [doRetourFormulaire] deve, portanto, construir o modelo anterior.
- linha 4: recupera-se a sessão na qual o controlador memorizou os valores (nome, idade) introduzidos.
- linha 7: recupera-se o nome da sessão
- linhas 8-9: se não estiver presente, insere-se com um valor vazio. Este caso não deverá ocorrer no funcionamento normal da aplicação, uma vez que a ação [retourFormulaire] ocorre sempre após a ação [validationFormulaire], ou seja, após a gravação dos dados introduzidos na sessão. No entanto, uma sessão pode expirar, uma vez que tem uma duração limitada, frequentemente de algumas dezenas de minutos. Neste caso, a linha 4 recriou uma nova sessão na qual o nome não se encontra. Coloca-se, então, um nome vazio na nova sessão.
- linhas 11-13: faz-se o mesmo para a idade
- Se ignorarmos o problema da sessão expirada, então as linhas 3-13 são desnecessárias. Os elementos [nom,age] do modelo já se encontram na sessão. Não é, portanto, necessário inseri-los novamente.
- linha 15: define-se o valor do elemento [urlAction] do modelo
6.7. Tests
Inicie ou reinicie o Tomcat. Aceda ao URL [http://localhost:8080/personne2] e, em seguida, retome os testes apresentados como exemplo no parágrafo 6.1.
















