5. Aplicação Web MVC [pessoa] – Versão 1
5.1. As vistas da aplicação
A aplicação utiliza o formulário dos exemplos anteriores. A primeira página da aplicação é a seguinte:

Chamaremos a esta vista a vista [form]. Se as entradas estiverem corretas, são apresentadas numa vista que será chamada [response]:

Se as entradas estiverem incorretas, os erros são apresentados numa vista chamada [erros]:

5.2. Arquitetura da aplicação
A aplicação web [person1] terá a seguinte arquitetura:

Trata-se de uma arquitetura de camada única: não existem camadas [business] ou [DAO], apenas uma camada [web]. [ServletPersonne] é o controlador da aplicação que trata de todos os pedidos dos clientes. Para responder a esses pedidos, utiliza uma das três vistas [form, response, errors].
Precisamos de determinar como o controlador [ServletPersonne] determina a ação que deve realizar ao receber uma solicitação do utilizador. Uma solicitação do cliente é um fluxo HTTP que difere consoante seja feita com um comando GET ou POST.
Pedido GET
Neste caso, o fluxo HTTP tem o seguinte aspeto:
A linha 1 especifica o URL solicitado, por exemplo:
Esta URL pode ser utilizada para especificar a ação a ser executada. Podem ser utilizados vários métodos:
- Um parâmetro de URL especifica a ação, por exemplo [/app?action=add&id=4]. Aqui, o parâmetro [action] indica ao controlador qual a ação que está a ser solicitada.
- O último elemento da URL especifica a ação, por exemplo [/app/add?id=4]. Aqui, o último elemento da URL [/add] é utilizado pelo controlador para determinar a ação que deve executar.
Existem outras soluções possíveis. As duas mencionadas acima são comuns.
Pedido POST
Neste caso, o fluxo HTTP é o seguinte:
A linha 1 especifica o URL solicitado, por exemplo:
Esta URL pode ser utilizada para especificar a ação a ser executada, tal como acontece com o GET. No caso do GET, o parâmetro [action] era incluído na URL. O mesmo pode acontecer aqui, como em:
No entanto, o parâmetro [action] também pode ser incluído nos parâmetros enviados (linha 15 acima), como em:
A seguir, utilizaremos estas diferentes técnicas para indicar ao controlador o que fazer:
- incluir o parâmetro de ação no URL solicitado:
- Envie o parâmetro de ação:
- Utilize o último elemento do URL como nome da ação:
5.3. O projeto Eclipse
Para criar o projeto Eclipse [mvc-personne-01] para a aplicação web [personne1], siga o procedimento descrito na secção 3.1.

Não vamos manter o contexto predefinido [mvc-personne-01]. Vamos escolher [personne1], conforme mostrado abaixo:

O resultado é o seguinte:

Se pretender alterar o contexto da aplicação web, utilize a opção [clique com o botão direito do rato no projeto -> Propriedades -> J2EE]:

Introduza o novo contexto em [1].
Vamos criar uma subpasta [vues] na pasta [WEB-INF]: [clique com o botão direito do rato em WEB-INF -> Novo -> Pasta]:
![]() | ![]() |
O novo projeto tem agora o seguinte aspeto:

Quando estiver concluído, o projeto ficará assim:

- O controlador [ServletPersonne] encontra-se na pasta [src]
- As páginas JSP para as visualizações [form, response, errors] encontram-se na pasta [WEB-INF/vues], o que impede o utilizador de aceder diretamente a elas, como se pode ver no exemplo abaixo:

Vamos agora descrever os vários componentes da aplicação web [/personne1]. O leitor é convidado a criá-los à medida que lê.
5.4. Configuração da aplicação web [person1]
O ficheiro web.xml para a aplicação /person1 será 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-01</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>
</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>
O que diz este ficheiro de configuração?
- linhas 34–37: a URL /main é tratada pelo servlet chamado person
- linhas 10-13: o servlet chamado «person» é uma instância da classe [ServletPersonne]
- linhas 14–19: definem um parâmetro de configuração chamado [urlResponse]. Esta é a URL da vista [response].
- Linhas 20–25: definem um parâmetro de configuração chamado [urlErrors]. Esta é a URL da vista [errors].
- Linhas 26–31: definem um parâmetro de configuração chamado [urlForm]. Esta é a URL da vista [form].
- Linha 40: [index.jsp] será a página inicial da aplicação.
As URLs das páginas JSP para as vistas [form, response, errors] são definidas individualmente por um parâmetro de configuração. Isto permite que sejam movidas sem necessidade de recompilar a aplicação.
Quando o utilizador aceder ao URL [/person1], o ficheiro [index.jsp] enviará a resposta (ficheiro da página inicial, linha 40). Este ficheiro encontra-se na raiz da pasta [WebContent]:

O seu conteúdo é o 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">
<%
response.sendRedirect("/personne1/main");
%>
A página [index.jsp] redireciona simplesmente o cliente para o URL [/person1/main]. Assim, quando o navegador solicita o URL [/person1], [index.jsp] envia-lhe a seguinte resposta HTTP:
- Linha 1: Resposta HTTP/1.1 para instruir o servidor a redirecionar para outro URL
- Linha 4: O URL para o qual o navegador deve redirecionar
Após esta resposta, o navegador irá solicitar a URL [/person1/main] conforme indicado (linha 4). O ficheiro [web.xml] da aplicação [/person1] especifica que este pedido será tratado pelo controlador [ServletPersonne] (linhas 35–36).
5.5. O código da vista
Começamos a escrever a aplicação web criando as suas vistas. Estas ajudam a definir as necessidades do utilizador em termos de interface gráfica e podem ser testadas sem o controlador.
5.5.1. A vista [form]
Esta vista destina-se ao formulário utilizado para introduzir o nome e a idade:

Tipo de HTML | nome | função | |
<input type="text"> | txtName | Introduza o nome | |
<input type="text"> | txtIdade | Introduza a idade | |
<input type="submit"> | Envie os valores introduzidos para o servidor na URL /person1/main | ||
<input type="reset"> | para restaurar a página ao estado em que foi inicialmente recebida pelo navegador | ||
<input type="button"> | para limpar o conteúdo dos campos de entrada [1] e [2] |
É gerado pela página JSP [formulaire.jsp]. O seu modelo é composto pelos seguintes elementos:
- [name]: um nome (String) encontrado nos atributos da sessão associados à chave "name"
- [age]: uma idade (String) encontrada nos atributos da sessão associados à chave "age"
A vista [form] é obtida quando o utilizador solicita o URL [/person1/main], ou seja, o URL do controlador [ServletPersonne]. O código da página JSP [formulaire.jsp] que gera a vista [form] é o 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">
<%
// on récupère les données du modèle
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
<html>
<head>
<title>Personne - formulaire</title>
</head>
<body>
<center>
<h2>Personne - formulaire</h2>
<hr>
<form 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>
- linhas 6-7: A página JSP começa por recuperar os elementos [nome, idade] do seu modelo a partir do pedido. No funcionamento normal da aplicação, o controlador [ServletPersonne] irá construir este modelo.
- linhas 18-38: a página JSP gera um formulário HTML (tag <form>)
- linha 18: a tag <form> não possui o atributo action para especificar o URL que irá processar os valores enviados pelo botão [Submit] (linha 32). Os valores do formulário serão então enviados para a URL de onde o formulário foi obtido, ou seja, a URL do controlador [ServletPersonne]. Assim, este controlador é utilizado tanto para gerar o formulário vazio inicialmente solicitado por uma solicitação GET como para processar os dados introduzidos que lhe serão enviados através do botão [Submit].
- Os valores enviados são os dos campos HTML [txtName] (linha 22), [txtAge] (linha 26) e [action] (linha 37). Este último parâmetro permitirá ao controlador saber o que precisa de fazer.
- Quando o formulário é exibido pela primeira vez, os campos de entrada [txtName] e [txtAge] são inicializados com as variáveis [name] (linha 22) e [age] (linha 26), respetivamente. Estas variáveis obtêm os seus valores a partir dos atributos do pedido (linhas 6–7), que se sabe serem inicializados pelo servlet. É, portanto, o servlet que define o conteúdo inicial dos campos de entrada do formulário.
- Linha 33: O botão [Reset] do tipo [reset] restaura o formulário para o estado em que se encontrava quando o navegador o recebeu.
- linha 34: o botão [Limpar] do tipo [reset] não tem atualmente nenhuma função.
Daqui em diante, referir-nos-emos a esta vista como a vista [form(name, age)] quando quisermos especificar tanto o nome da vista como o seu modelo. Além disso, note que quando o utilizador clica no botão [Submit], os parâmetros [txtName, txtAge] são enviados para o URL [/person1/main].
5.5.2. A vista [response]
Esta vista apresenta os valores introduzidos no formulário quando estes são válidos:

É gerada pela página JSP [reponse.jsp]. O seu modelo é composto pelos seguintes elementos:
- [name]: um nome (String) encontrado nos atributos da sessão, associado à chave "name"
- [age]: uma idade (String) que se encontra nos atributos da sessão, associada à chave "age"
O código da página JSP [reponse.jsp] é o 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">
<%
// on récupère les données du modèle
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
<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>
</body>
</html>
- Linhas 6-7: A página JSP começa por recuperar os elementos [name, age] do seu modelo a partir do pedido. Durante o funcionamento normal da aplicação, o controlador [ServletPersonne] irá construir este modelo.
- Os elementos do modelo [name, age] são então exibidos nas linhas 20 e 24
Posteriormente, referimo-nos a esta vista como a vista [response(name, age)].
5.5.3. A vista [errors]
Esta vista reporta erros de entrada no seguinte formato:

É gerada pela página JSP [errors.jsp]. O seu modelo é composto pelos seguintes elementos:
- [errors]: uma lista (ArrayList) de mensagens de erro que serão encontradas nos atributos da solicitação, associadas à chave "errors"
O código da página JSP [errors.jsp] é o 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" %>
<%
// on récupère les données du modèle
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
%>
<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>
</body>
</html>
- linha 8: a página JSP começa por recuperar o elemento [errors] do seu modelo na solicitação. Este elemento representa um objeto ArrayList contendo elementos String. Estes elementos são mensagens de erro. Durante o funcionamento normal da aplicação, o controlador [ServletPersonne] irá construir este modelo.
- Linhas 18–22: exibem a lista de mensagens de erro. Para tal, precisamos de escrever código Java no corpo HTML da página. Devemos sempre procurar manter isto ao mínimo para evitar sobrecarregar o código HTML. Veremos mais tarde que existem soluções para reduzir a quantidade de código Java nas páginas JSP.
- Linha 4: Repare na tag de importação para os pacotes necessários à página JSP
Iremos referir-nos a esta vista como a vista [errors(errors)].
5.6. Testar vistas
É possível testar a validade das páginas JSP sem ter escrito o controlador. Para isso, duas condições devem ser cumpridas:
- Deve ser possível solicitá-las diretamente a partir da aplicação, sem passar pelo controlador
- a página JSP deve inicializar o próprio modelo, que normalmente seria construído pelo controlador
Para realizar estes testes, duplicamos as páginas JSP das vistas 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
request.setAttribute("nom","tintin");
request.setAttribute("age","30");
%>
<%
// on récupère les données du modèle
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
<html>
<head>
...
As linhas 3–7 foram adicionadas para criar o modelo exigido pelas linhas 11–12.
[reponse.jsp]:
...
<%
// -- test : on crée le modèle de la page
request.setAttribute("nom","milou");
request.setAttribute("age","10");
%>
<%
// on récupère les données du modèle
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
<html>
<head>
...
As linhas 3–7 foram adicionadas para criar o modelo exigido pela página nas linhas 11–12.
[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);
%>
<%
// on récupère les données du modèle
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
%>
<html>
<head>
...
As linhas 3–9 foram adicionadas para criar o modelo exigido pela linha 13.
Inicie o Tomcat, se ainda não o fez, e, em seguida, solicite os seguintes URLs:
![]() | ![]() |
![]() |
Obtemos as visualizações esperadas. Agora que temos uma confiança razoável nas páginas JSP da aplicação, podemos passar à escrita do seu controlador [ServletPersonne].
5.7. O controlador [ServletPersonne]
Resta apenas escrever o núcleo da nossa aplicação web: o controlador. A sua função é:
- recuperar o pedido do cliente,
- processar a ação solicitada pelo cliente,
- enviar a vista apropriada em resposta.
O controlador [ServletPersonne] irá tratar das seguintes ações:
solicitar | solicitação | origem | processamento |
1 | [GET /pessoa1/mão] | URL introduzida pelo utilizador | - enviar a vista [form] vazia |
2 | [POST /person1/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, envie a visualização [response(name,age)] |
A aplicação inicia quando o utilizador solicita o URL [/person1/main]. De acordo com o ficheiro [web.xml] da aplicação (ver Secção 5.4), este pedido é tratado por uma instância da classe ServletPersonne, que iremos agora descrever.
5.7.1. Estrutura do controlador
O código do controlador [ServletPersonne] é o seguinte:
- linhas 20–22: o método [init] executado quando o servlet é carregado pela primeira vez
- linhas 25-28: o método [doGet] chamado pelo servidor web quando é feita uma solicitação GET à aplicação
- linhas 42-46: o método [doPost] chamado pelo servidor web quando é feita uma solicitação POST à aplicação. Conforme mostrado, isto também será tratado pelo método [doGet] (linha 45).
- linhas 31-33: o método [doInit] trata da ação n.º 1 [GET /person1/main]
- Linhas 36–39: o método [doValidationFormulaire] trata da ação n.º 2 [POST /person1/main] com os parâmetros enviados [txtName, txtAge, action].
Vamos agora descrever os vários métodos do controlador
5.7.2. Inicialização do controlador
Quando a classe do controlador é carregada pelo contentor de servlets, o seu método [init] é executado. Isto acontece apenas uma vez. Uma vez carregado na memória, o controlador permanece lá e processa pedidos de diferentes clientes. Cada cliente é tratado por um segmento de execução separado, pelo que os métodos do controlador são executados simultaneamente por diferentes segmentos. Note-se que, por esta razão, o controlador não deve ter quaisquer campos que os seus métodos possam modificar. Os seus campos devem ser de leitura apenas. São inicializados pelo método [init], que é a sua função principal. Este método tem a característica única de ser executado apenas uma vez por uma única thread. Portanto, não há problemas com o acesso simultâneo aos campos do controlador dentro deste método. O objetivo do método [init] é inicializar os objetos necessários à aplicação web, que serão partilhados em modo de leitura apenas por todas as threads do cliente. Estes objetos partilhados podem ser colocados em dois locais:
- os campos privados do controlador
- o contexto de execução da aplicação (ServletContext)
O código para o método [init] do controlador [ServletPersonne] é o seguinte:
- linha 16: a configuração da aplicação web é recuperada, ou seja, o conteúdo do ficheiro [web.xml]
- linhas 19–29: recuperam os parâmetros de inicialização do servlet, cujos nomes estão definidos na matriz [parameters] na linha 9
- linha 21: o valor do parâmetro é recuperado
- linha 25: se o parâmetro estiver em falta, o erro é adicionado à lista de erros [initializationErrors], inicialmente vazia (linha 8).
- Linha 28: Se o parâmetro estiver presente, é armazenado juntamente com o seu valor no dicionário [params], inicialmente vazio (linha 10).
- linhas 31–35: o parâmetro [urlErrors] deve estar presente, pois especifica a URL da vista [errors] capaz de exibir quaisquer erros de inicialização. Se não existir, a aplicação é encerrada através do lançamento de uma [ServletException] (linha 33).
5.7.3. O método [doGet]
O método [doGet] trata tanto de pedidos GET como POST para o servlet, uma vez que o método [doPost] redireciona para o método [doGet]. O seu código é o seguinte:
- Linhas 18–25: 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");
%>
A vista [erros] espera uma chave chamada "erros" na solicitação. O controlador cria essa chave na linha 20.
- Linha 28: Recuperamos o método [get] ou [post] que o cliente utilizou para efetuar a solicitação
- linha 30: recuperamos o valor do parâmetro [action] da solicitação. Lembre-se de que, na nossa aplicação, apenas a solicitação n.º 2 [POST /person1/main] possui o parâmetro [action]. Nesta solicitação, ele tem o valor [validationFormulaire].
- Linhas 31–34: Se o parâmetro [action] não estiver presente, atribuímos-lhe o valor "init". Este será o caso da solicitação inicial n.º 1 [GET /person1/main].
- Linhas 36–40: Processamento da solicitação n.º 1 [GET /person1/main].
- Linhas 41–45: Processamento da solicitação #2 [POST /person1/main].
- Linha 47: Se nenhum dos dois casos anteriores se aplicar, procedemos como se estivéssemos no caso n.º 1
5.7.4. O método [doInit]
Este método trata da solicitação n.º 1 [GET /person1/main]. Para esta solicitação, deve retornar a vista vazia [form(name, age)]. O seu código é o seguinte:
- linhas 18-19: a vista [form] é apresentada. Recorde o modelo esperado por esta vista:
<%
// on récupère les données du modèle
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
- Linhas 16-17: O modelo [name, age] da vista [form] é inicializado com cadeias de caracteres vazias.
5.7.5. O método [doValidationForm]
Este método processa a solicitação n.º 2 [POST /person1/main], na qual os parâmetros enviados são [action, txtName, txtAge]. O seu código é o seguinte:
- linhas 16-17: os valores dos parâmetros «txtNom» e «txtAge» são recuperados do pedido do cliente.
- linhas 19-26: verifica-se a validade destes dois parâmetros
- linhas 28-33: se algum dos parâmetros estiver incorreto, é apresentada a vista [errors(callErrors)]. Recorde o modelo para esta vista:
<%
// on récupère les données du modèle
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
%>
- linhas 35-38: se os dois parâmetros recuperados "txtNom" e "txtAge" tiverem valores válidos, a vista [response(name, age)] é apresentada. Recorde o modelo para a vista [response]:
<%
// on récupère les données du modèle
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
%>
5.8. Testes
Vamos incluir o projeto [mvc-personne-01] nas aplicações do Tomcat, seguindo o procedimento descrito na secção 3.3:

Inicie o Tomcat. Depois de o fazer, podemos retomar os testes apresentados como exemplos na Secção 5.1. Podemos adicionar mais testes. Por exemplo, podemos remover um dos parâmetros de configuração urlXXX do ficheiro web.xml e ver o resultado. Conforme mostrado abaixo, um dos parâmetros está comentado no ficheiro [web.xml]:
<!--
<init-param>
<param-name>urlFormulaire</param-name>
<param-value>
/WEB-INF/vues/formulaire.jsp
</param-value>
</init-param>
-->
Iniciamos ou reiniciamos o Tomcat e acedemos à URL [http://localhost:8080/personne1/main]. Obtemos a seguinte resposta:





