6. Aplicação Web MVC [person] – Versão 2
Vamos agora apresentar variantes da aplicação anterior [/person1], às quais daremos os nomes [/person2, /person3, ...]. Estas variantes não alteram a arquitetura original da aplicação, que permanece da seguinte forma:

Para estas variantes, manteremos as nossas explicações sucintas. Apresentaremos apenas as alterações feitas em comparação com a versão anterior.
6.1. Introdução
Vamos agora adicionar a gestão de sessões à nossa aplicação. Vamos rever os seguintes pontos:
- O diálogo HTTP cliente-servidor é uma série de sequências de pedido-resposta que são independentes umas das outras
- a sessão funciona como um buffer de memória entre diferentes sequências de pedido-resposta do mesmo utilizador. Se houver N utilizadores, haverá N sessões.
A sequência de ecrãs a seguir mostra o que agora se pretende na operação da aplicação:
Intercâmbio n.º 1
![]() | ![]() |
A nova funcionalidade é o link de retorno ao formulário, que foi adicionado à vista [erros].
Intercâmbio n.º 2
![]() | ![]() |
Na troca n.º 1, o utilizador forneceu os valores (xx, yy) para o par (nome, idade). Se o servidor tomou conhecimento destes valores durante a troca, «esquece-os» no final da troca. No entanto, podemos ver que, durante a troca n.º 2, ele consegue apresentar esses valores novamente na sua resposta. É o conceito de sessão que, neste caso, permite ao servidor web armazenar dados ao longo de sucessivas trocas cliente-servidor. Existem outras soluções possíveis para este problema.
Durante a troca n.º 1, o servidor armazenará o par (nome, idade) que o cliente lhe enviou na sessão, para que possa exibi-lo durante a troca n.º 2.
Aqui está outro exemplo de implementação de uma sessão entre duas trocas:
Intercâmbio n.º 1
![]() | ![]() |
A nova funcionalidade é o link de retorno ao formulário, que foi adicionado à página de resposta.
Intercâmbio n.º 2
![]() | ![]() |
6.2. O projeto Eclipse
Para criar o projeto Eclipse [mvc-personne-02] para a aplicação web [/personne2], vamos duplicar o projeto Eclipse [mvc-personne-01] para reutilizar o código existente. Para tal, siga estes passos:
[Clique com o botão direito do rato no projeto mvc-personne-01 -> Copiar]:

depois [clique com o botão direito do rato no Package Explorer -> Colar]:
![]() | ![]() - introduza o nome do novo projeto em [1] e o nome de uma pasta existente, mas vazia, em [2] |
O projeto [mvc-personne-02] é então criado:

Por enquanto, é idêntico ao projeto [mvc-personne-01]. Teremos de fazer algumas alterações manuais antes de o podermos utilizar. Vá para a vista [Servidores] e tente adicionar esta nova aplicação às geridas pelo Tomcat:
![]() | ![]() |
Podemos ver que em [1], o novo projeto [mvc-personne-02] não é reconhecido pelo Tomcat. Para que o Tomcat o reconheça, é necessário modificar um ficheiro de configuração do projeto [mvc-personne-02]. Utilize a opção [Ficheiro / Abrir Ficheiro] 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 especifica o nome do módulo web a ser implementado no Tomcat. Aqui, este nome é o mesmo do projeto [mvc-personne-01]. Alteramo-lo para [mvc-personne-02]:
<wb-module deploy-name="mvc-personne-02">
Além disso, podemos aproveitar esta oportunidade para modificar, na linha 7, o nome do contexto da aplicação [mvc-personne-02], que entra 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 passar pelo ficheiro de configuração.
Depois de fazer isto, guardamos o novo ficheiro [.content], saímos e reiniciamos o Eclipse para que as alterações tenham efeito.
Assim que o Eclipse tiver reiniciado, vamos tentar a operação que falhou anteriormente:
![]() | ![]() |
Desta vez, o projeto [mvc-personne-02] é reconhecido. Adicionamo-lo aos projetos configurados para serem executados no Tomcat:

6.3. Configurar a aplicação web [personne2]
O ficheiro web.xml para a aplicação /personne2 é 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>
<!-- Mapping ServletPersonne-->
<servlet-mapping>
<servlet-name>personne</servlet-name>
<url-pattern>/main</url-pattern>
</servlet-mapping>
<!-- welcome files -->
<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 mudou para [mvc-personne-02]
- linhas 31–36: definem o parâmetro de configuração denominado [urlController], que é a URL [principal] que conduz ao servlet [ServletPersonne]
- linhas 37–42: definem um parâmetro de configuração chamado [lienRetourFormulaire], que é o texto do link de retorno ao formulário nas páginas JSP [erreurs.jsp] e [reponse.jsp].
A página inicial [index.jsp] sofre as seguintes alterações:
<%@ 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] na aplicação [/personne2].
6.4. O código da vista
6.4.1. A vista [form]
Esta vista é idêntica à da versão anterior:

É gerada pela seguinte página JSP [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">
<%
// on récupère les données du modèle
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:
- Linha 19: O formulário tem agora um atributo [action] cujo valor é o URL para o qual o navegador enviará os valores do formulário quando o utilizador clicar no botão [Submit]. A variável [urlAction] terá o valor action="main". A vista [form] é apresentada depois de o utilizador realizar as seguintes ações:
- pedido inicial: GET /person2/main
- clicar no link [Voltar ao formulário]: GET /person2/main?action=retourFormulaire
Uma vez que 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 utilizará a primeira parte do URL da página atualmente exibida [/person2] e anexará o URL relativo a ela. A URL POST será, portanto, [/person2/main], que é a URL do controlador. Esta solicitação POST será acompanhada pelos parâmetros [txtName, txtAge, action] das linhas 23, 27 e 38.
- Linha 8: Recuperamos o valor do elemento [urlAction] do modelo. Este é recuperado a partir dos atributos da solicitação atual. Será utilizado na linha 19.
- Linhas 6–7: Recuperamos os valores dos elementos [name, age] do modelo. São recuperados a partir dos atributos da sessão, em vez dos atributos da solicitação, como na versão anterior. Isto serve para acomodar a solicitação [GET /person2/main?action=returnToForm] proveniente do link nas vistas [response] e [errors]. Antes de apresentar estas duas vistas, o controlador coloca os dados introduzidos no formulário na sessão, o que lhe permite recuperá-los quando o utilizador clica no link [Voltar ao formulário] nas vistas [response] e [errors].
6.4.2. A vista [response]
Esta vista apresenta os valores introduzidos no formulário quando estes são válidos:
![]() | ![]() |
Em comparação com a versão anterior, a nova funcionalidade é o link [Voltar ao formulário]. A visualização é gerada pela seguinte página JSP [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">
<%
// on récupère les données du modèle
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 retorno ao formulário. Este link tem dois componentes:
- o destino [href="?action=retourFormulaire"]. A vista [response] é apresentada após o formulário [formulaire.jsp] ser enviado via POST para o URL [/personne2/main]. É, portanto, este último URL que é apresentado no navegador quando a vista [response] é apresentada. Clicar no link [Voltar ao formulário] irá então desencadear um pedido GET do navegador para a URL especificada pelo atributo [href] do link, neste caso "?action=retourFormulaire". Se nenhuma URL for especificada em [href], o navegador utilizará a URL da vista atualmente exibida, ou seja, [/personne2/main]. Em última análise, clicar no link [Voltar ao formulário] irá desencadear um pedido GET do navegador para o URL [/person2/main?action=retourFormulaire], ou seja, o URL do controlador da aplicação acompanhado pelo parâmetro [action] para lhe indicar o que fazer.
- o texto do link. Isto fará parte do modelo enviado para a página pelo controlador e recuperado na linha 10.
6.4.3. A vista [errors]
Esta vista apresenta os erros de entrada no formulário:
![]() | ![]() |
Em comparação com a versão anterior, a nova funcionalidade é o link [Voltar ao formulário]. A visualização é gerada pela seguinte página JSP [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">
<%@ page import="java.util.ArrayList" %>
<%
// on récupère les données du modèle
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");
}//for
%>
</ul>
<br>
<a href="?action=retourFormulaire"><%= lienRetourFormulaire %></a>
</body>
</html>
- Linha 26: o link de retorno ao formulário. Este link é idêntico ao da vista [response]. Recomenda-se ao leitor que consulte as explicações fornecidas para essa vista, se necessário.
6.5. Testar as vistas
Para testar as vistas anteriores, duplicamos as suas páginas JSP na pasta /WebContent/JSP do projeto Eclipse:

Em seguida, na pasta JSP, as páginas são modificadas da seguinte forma:
[form.jsp]:
...
<%
// -- test : on crée le modèle de la page
session.setAttribute("nom","tintin");
session.setAttribute("age","30");
request.setAttribute("urlAction","main");
%>
<%
// on récupère les données du modèle
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 exigido pela página nas linhas 11–13.
[response.jsp]:
<%
// -- test : on crée le modèle de la page
request.setAttribute("nom","milou");
request.setAttribute("age","10");
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// on récupère les données du modèle
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 exigido pela página nas linhas 11–13.
[errors.jsp]:
<%
// -- test : on crée le modèle de la page
ArrayList<String> erreurs1=new ArrayList<String>();
erreurs1.add("erreur1");
erreurs1.add("erreur2");
request.setAttribute("erreurs",erreurs1);
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// on récupère les données du modèle
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
As linhas 4–8 foram adicionadas para criar o modelo exigido pela página nas linhas 13–14.
Vamos iniciar o Tomcat, caso ainda não esteja a funcionar, e, em seguida, solicitar os seguintes URLs:
![]() | ![]() |
![]() |
Recebemos as visualizações esperadas.
6.6. O controlador [ServletPersonne]
O controlador [ServletPersonne] da aplicação web [/personne2] irá tratar das seguintes ações:
Não. | pedido | origem | processamento |
1 | [GET /person2/hand] | URL introduzida pelo utilizador | - enviar a vista [form] vazia |
2 | [POST /person2/hand] com os parâmetros [txtName, txtAge, action] | clique no [Submit] no [formulário] | - verifique os valores dos parâmetros [txtName, txtAge] - se estiverem incorretos, enviar a vista [errors(errors)] - se estiverem corretos, enviar a visualização [response(name,age)] |
3 | [GET /person2/main? action=returnForm] | clique no [Voltar ao formulário] das vistas resposta] e [erros]. | - Envie a vista [formulário] pré-preenchida com os valores introduzidos mais recentemente |
Portanto, temos uma nova ação para tratar: [GET /person2/main?action=returnForm].
6.6.1. Estrutura do controlador
O esqueleto do controlador [ServletPersonne] é quase idêntico ao da versão anterior:
Novidades:
- linha 4: a utilização de uma sessão requer a importação do pacote [HttpSession]
- Linhas 28–30: O novo método [doRetourFormulaire] lida com 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 o ficheiro [web.xml] em busca dos elementos declarados na matriz [parameters]:
- Linha 5: Foram adicionados os parâmetros [controllerUrl] (URL do controlador) e [formBackLink] (texto do link para as vistas [response] e [errors]).
6.6.3. O método [doGet]
O método [doGet] deve tratar a ação [GET /person2/main?action=formSubmit], que não existia anteriormente:
- linhas 6–14: verificamos se a lista de erros de inicialização está vazia. Se não estiver, exibimos a vista [errors(initializationErrors)], que irá relatar o(s) erro(s).
Para compreender este código, é necessário recordar o modelo de visualização [errors]:
<%
// on récupère les données du modèle
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
A vista [errors] espera um elemento-chave denominado "errors" na solicitação. O controlador cria este elemento na linha 8. Espera também um elemento-chave denominado "formSubmitLink". O controlador cria este elemento na linha 9. Aqui, o texto do link ficará vazio. Por conseguinte, não haverá qualquer link na vista [errors] que é enviada. Com efeito, se ocorreram erros durante a inicialização da aplicação, esta deve ser reconfigurada. Não há necessidade de oferecer ao utilizador a opção de continuar a aplicação através de um link.
- Linhas 34–37: processamento da nova ação [GET /person2/main?action=returnForm]
6.6.4. O método [doInit]
Este método trata do pedido n.º 1 [GET /person2/main]. Para este pedido, deve devolver a vista vazia [form(name,age)]. O seu código é o seguinte:
- Linha 4: A sessão atual é recuperada, se existir; caso contrário, é criada (parâmetro getSession definido como true).
- Linhas 9–10: A vista [form] é apresentada. Recorde o modelo esperado por esta vista:
<%
// on récupère les données du modèle
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
- Linhas 6-7: Os elementos [name, age] do modelo de visualização [form] são inicializados com cadeias de caracteres vazias e colocados na sessão, porque é aí que a visualização os espera.
- Linha 8: O elemento [urlAction] do modelo é inicializado com o valor do parâmetro [urlController] do ficheiro [web.xml] e colocado na solicitação.
6.6.5. O método [doValidationFormulaire]
Este método processa a solicitação n.º 2 [POST /person2/main], na qual os parâmetros enviados são [action, txtName, txtAge]. O seu código é o seguinte:
- Linhas 5–6: Recuperamos os valores dos parâmetros «txtNom» e «txtAge» da solicitação do cliente.
- Linhas 8–10: Estes valores são armazenados na sessão para que possam ser recuperados quando o utilizador clicar na ligação [Voltar ao formulário] nas vistas [response] e [errors].
- Linhas 12–19: A validade dos valores de ambos os parâmetros é verificada.
- Linhas 21–28: se algum dos parâmetros for inválido, é apresentada a vista [errors(errors,returnToFormLink)]. Recorde o modelo para esta vista:
<%
// on récupère les données du modèle
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
- Linhas 30–34: Se os dois parâmetros recuperados "txtName" e "txtAge" tiverem valores válidos, exibimos a vista [response(name, age, formSubmitLink)]. Lembre-se do modelo de vista [response]:
<%
// on récupère les données du modèle
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 trata do pedido n.º 3 [GET /person2/main?action=formSubmit]. O seu código é o seguinte:
Após a conclusão deste método, a vista [form] deve ser apresentada, pré-preenchida com as entradas mais recentes do utilizador. Aqui está o modelo da vista [form]:
<%
// on récupère les données du modèle
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: Recuperamos a sessão na qual o controlador armazenou os valores introduzidos (nome, idade).
- Linha 7: recuperamos o nome da sessão
- Linhas 8–9: Se não estiver lá, adicionamo-lo com um valor vazio. Este cenário não deve ocorrer durante o funcionamento normal da aplicação, uma vez que a ação [returnForm] ocorre sempre após a ação [validateForm], que ocorre depois de os dados introduzidos terem sido guardados na sessão. No entanto, uma sessão pode expirar porque tem uma duração limitada, frequentemente algumas dezenas de minutos. Neste caso, a linha 4 criou uma nova sessão na qual o nome não será encontrado. Por isso, definimos um nome vazio na nova sessão.
- Linhas 11–13: Fazemos o mesmo para a idade
- Se ignorarmos a questão da sessão expirada, as linhas 3–13 são desnecessárias. Os elementos [name, age] do modelo já se encontram na sessão. Por conseguinte, não há necessidade de os colocar novamente lá.
- Linha 15: Definimos o valor do elemento [urlAction] no modelo
6.7. Testes
Inicie ou reinicie o Tomcat. Solicite a URL [http://localhost:8080/personne2] e, em seguida, repita os testes apresentados no exemplo da secção 6.1.
















