Skip to content

5. Aplicación web MVC [personne] – versión 1

5.1. Las vistas de la aplicación

La aplicación retoma el formulario utilizado en los ejemplos anteriores. La primera página de la aplicación es la siguiente:

Image

A esta vista la llamaremos [formulaire]. Si se introducen los datos correctamente, estos se muestran en una vista que se denominará [réponse]:

Image

Si los datos introducidos son incorrectos, los errores se señalan en una vista denominada [erreurs]:

Image

5.2. Arquitectura de la aplicación

La aplicación web [personne1] tendrá la siguiente arquitectura:

Image

Esta arquitectura es de un solo nivel: no hay capas [métier] ni [dao], solo una capa [web]. [ServletPersonne] es el controlador de la aplicación que gestiona todas las solicitudes de los clientes. Para responder a ellas, utiliza una de las tres vistas [formulaire, réponse, erreurs].

Tenemos que determinar cómo el controlador [ServletPersonne] decide qué acción debe realizar al recibir una solicitud de un usuario. Una solicitud de cliente es un flujo HTTP que varía en función de si se realiza con un comando GET o POST.

Solicitud GET

En este caso, el flujo HTTP tiene el siguiente aspecto:

GET /URL HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0,5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
[ligne vide]

La línea 1 especifica la URL solicitada, por ejemplo:

GET /personne1/ HTTP/1.1

Esta URL se puede utilizar para especificar la acción que se debe realizar. Se pueden emplear varios métodos:

  1. un parámetro de la URL especifica la acción, por ejemplo, [/appli?action=ajouter&id=4]. En este caso, el parámetro [action] indica al controlador la acción que se le solicita.
  2. el último elemento de la URL especifica la acción, por ejemplo, [/appli/ajouter?id=4]. En este caso, el controlador utiliza el último elemento de la URL [/ajouter] para determinar la acción que debe realizar.

Existen otras soluciones posibles. Las dos anteriores son las más habituales.

Solicitud POST

En este caso, el flujo HTTP tiene el siguiente aspecto:

POST /URL HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0,5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/persona1/principal
Cookie: JSESSIONID=9F5E5BFA29643FC6B1601EEED907E1F9
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
[ligne vide]
txtNom=&txtAge=&action=validationFormulaire

La línea 1 especifica la URL solicitada, por ejemplo:

POST /personne1/main HTTP/1.1

Esta URL se puede utilizar para especificar la acción que se debe realizar, como en el caso de GET. En el caso de GET, el parámetro [action] estaba integrado en URL. Esto también puede ser el caso aquí, como en:

POST /appli?action=ajouter&id=4 HTTP/1.1

Pero el parámetro [action] también puede estar incluido en los parámetros enviados (línea 15 anterior), como en:

POST /appli HTTP/1.1
...
[ligne vide]
action=ajouter&id=4

A continuación, utilizaremos estas diferentes técnicas para indicar al controlador lo que debe hacer:

  • incluir el parámetro action en la URL solicitada:
POST /appli?action=ajouter&id=4 HTTP/1.1
  • enviar el parámetro action:
POST /appli HTTP/1.1
...
[ligne vide]
action=ajouter&id=4
  • utilizar el último elemento de la URL como nombre de la acción:
POST /appli/ajouter?id=4 HTTP/1.1

5.3. El proyecto Eclipse

Para crear el proyecto Eclipse [mvc-personne-01] de la aplicación web [personne1], se seguirá el procedimiento descrito en el apartado 3.1.

Image

No se mantendrá el contexto [mvc-personne-01] propuesto por defecto. Se elegirá [personne1] tal y como se indica a continuación:

Image

El resultado obtenido es el siguiente:

Image

Si, por casualidad, se desea cambiar el contexto de la aplicación web, se utilizará la opción [clic droit sur projet -> Properties -> J2EE]:

Image

Se indicará el nuevo contexto en [1].

Vamos a crear una subcarpeta [vues] dentro de la carpeta [WEB-INF]: [clic droit sur WEB-INF -> New -> Folder]:

El nuevo proyecto es ahora este:

Image

Una vez completado, el proyecto quedará así:

Image

  • El controlador [ServletPersonne] se encuentra en la carpeta [src]
  • Las páginas JSP de las vistas [formulaire, réponse, erreurs] se encuentran en la carpeta [WEB-INF/vues], lo que impide que el usuario las solicite directamente, tal y como se muestra en el ejemplo siguiente:

Image

A continuación describimos los diferentes componentes de la aplicación web [/personne1]. Se invita al lector a crearlos a medida que avanza en la lectura.

5.4. Configuración de la aplicación web [personne1]

El archivo web.xml de la aplicación /personne1 tendrá el siguiente contenido:


<?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>
    <!--  Asignación ServletPersonne-->
    <servlet-mapping>
        <servlet-name>personne</servlet-name>
        <url-pattern>/main</url-pattern>
    </servlet-mapping>
    <!--  archivos de inicio -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

¿Qué indica este archivo de configuración?

  • líneas 34-37: el archivo URL /main es procesado por el servlet denominado «persona»
  • líneas 10-13: el servlet denominado «persona» es una instancia de la clase [ServletPersonne]
  • líneas 14-19: definen un parámetro de configuración denominado «[urlReponse]». Se trata de la URL de la vista «[réponse]».
  • líneas 20-25: definen un parámetro de configuración denominado «[urlErreurs]». Es la URL de la vista «[erreurs]».
  • Líneas 26-31: definen un parámetro de configuración denominado [urlFormulaire]. Es la URL de la vista [formulaire].
  • Línea 40: [index.jsp] será la página de inicio de la aplicación.

Las URL de las páginas JSP de las vistas [formulaire, réponse, erreurs] son objeto, cada una, de un parámetro de configuración. Esto permite moverlas sin tener que recompilar la aplicación.

Cuando el usuario solicite la URL [/personne1], será el archivo [index.jsp] el que envíe la respuesta (archivo de inicio, línea 40). Este archivo se encuentra en la raíz de la carpeta [WebContent]:

Image

Su contenido es el siguiente:


<%@ 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");
%>

La página [index.jsp] se limita a redirigir al cliente a la URL [/personne1/main]. Así, cuando el navegador solicita la URL [/personne1], [index.jsp] le envía la siguiente respuesta HTTP:

1
2
3
4
5
6
7
HTTP/1.x 302 Déplacé Temporairement
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=9F5E5BFA29643FC6B1601EEED907E1F9; Path=/personne1
Location: http://localhost:8080/persona1/main
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 0
Date: Thu, 18 May 2006 15:45:23 GMT
  • línea 1: respuesta HTTP/1.1 para indicar al servidor que redirija a otra URL
  • línea 4: la URL a la que debe redirigirse el navegador

Tras esta respuesta, el navegador solicitará la URL [/personne1/main] tal y como se le indica (línea 4). El archivo [web.xml] de la aplicación [/personne1] indica que esta solicitud será gestionada por el controlador [ServletPersonne] (líneas 35-36).

5.5. El código de las vistas

Comenzamos a escribir la aplicación web por las vistas. Estas permiten definir las necesidades del usuario en cuanto a la interfaz gráfica y pueden probarse sin necesidad de que el controlador esté presente.

5.5.1. La vista [formulaire]

Esta vista corresponde al formulario de introducción del nombre y la edad:

Image

tipo HTML
nombre
función
1
<input type="text">
txtNom
introducción del nombre
2
<input type="text">
txtAge
Introducción de la edad
3
<input type="submit">
 
Envío de los valores introducidos al servidor a la URL /persona1/main
4
<input type="reset">
 
para restablecer la página al estado en el que la recibió inicialmente el navegador
5
<input type="button">
 
para borrar el contenido de los campos de entrada [1] y [2]

La genera la página JSP [formulaire.jsp]. Su plantilla está compuesta por los siguientes elementos:

  • [nom]: un nombre (cadena) que se encuentra en los atributos de sesión asociados a la clave «nombre»
  • [age]: una edad (cadena de caracteres) que se encuentra en los atributos de sesión asociados a la clave «edad»

La vista [formulaire] se obtiene cuando el usuario solicita la URL [/personne1/main], c.a.d, la URL del controlador [ServletPersonne]. El código de la página JSP [formulaire.jsp] que genera la vista [formulaire] es el siguiente:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // se recuperan los datos del modelo
  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>

  • líneas 6-7: la página JSP comienza recuperando de la solicitud [request] los elementos [nom, age] de su modelo. En el funcionamiento normal de la aplicación, será el controlador [ServletPersonne] el que construya esta plantilla.
  • líneas 18-38: la página JSP generará un formulario HTML (etiqueta <form>)
  • línea 18: la etiqueta <form> no tiene el atributo action para indicar la URL que deberá procesar los valores enviados mediante el botón [Envoyer] de tipo submit (línea 32). Los valores del formulario se enviarán entonces a la URL desde la que se obtuvo el formulario, es decir, la URL del controlador [ServletPersonne]. De este modo, este se utiliza tanto para generar el formulario vacío solicitado inicialmente por un GET como para procesar los datos introducidos que se le enviarán mediante el botón [Envoyer].
  • Los valores enviados son los de los campos HTML, [txtNom] (línea 22), [txtAge] (línea 26) y [action] (línea 37). Este último parámetro permitirá al controlador saber qué debe hacer.
  • Al mostrarse el formulario por primera vez, los campos de entrada [txtNom, txtAge] se inicializan, respectivamente, con las variables [nom] (línea 22) y [age] (línea 26). Estas variables obtienen los valores de sus atributos de la consulta (líneas 6-7), atributos que sabemos que son inicializados por el servlet. Por lo tanto, es este último el que establece el contenido inicial de los campos de entrada del formulario.
  • línea 33: el botón [Rétablir], de tipo [reset], permite restablecer el formulario al estado en el que se encontraba cuando el navegador lo recibió.
  • línea 34: el botón [Effacer], de tipo [reset], no tiene por el momento ninguna función.

En adelante, nos referiremos a esta vista como la vista [formulaire(nom, age)] cuando queramos especificar tanto el nombre de la vista como su modelo. Por otra parte, recordaremos que cuando el usuario hace clic en el botón [Envoyer], los parámetros [txtNom, txtAge] se envían a la URL [/personne1/main].

5.5.2. La vista [reponse]

Esta vista muestra los valores introducidos en el formulario cuando son válidos:

Image

Se genera a partir de la página JSP [reponse.jsp]. Su plantilla está compuesta por los siguientes elementos:

  • [nom]: un nombre (cadena de caracteres) que se encontrará en los atributos de sesión, asociado a la clave «nombre»
  • [age]: una edad (cadena de caracteres) que se encontrará en los atributos de sesión, asociada a la clave «edad»

El código de la página JSP [reponse.jsp] es el siguiente:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // se recuperan los datos del modelo
  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>

  • líneas 6-7: la página JSP comienza recuperando de la solicitud [request] los elementos [nom, age] de su modelo. En el funcionamiento normal de la aplicación, será el controlador [ServletPersonne] el que construya esta plantilla.
  • A continuación, los elementos [nom, age] del modelo se muestran en las líneas 20 y 24

A continuación, denominamos a esta vista «[réponse(nom, age)]».

5.5.3. La vista [erreurs]

Esta vista señala los errores de introducción de datos en el formulario:

Image

Se genera a partir de la página JSP [erreurs.jsp]. Su plantilla está compuesta por los siguientes elementos:

  • [erreurs]: una lista (ArrayList) de mensajes de error que se encontrará en los atributos de la consulta, asociada a la clave «errores»

El código de la página JSP [erreurs.jsp] es el siguiente:


<%@ 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" %>

<%
// se recuperan los datos del modelo
  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");
        }//para
      %>
    </ul>
  </body>
</html>

  • línea 8: la página JSP comienza recuperando, de la consulta [request], el elemento [erreurs] de su modelo. Este elemento representa un objeto de tipo ArrayList compuesto por elementos de tipo String. Estos elementos son mensajes de error. En el funcionamiento normal de la aplicación, será el controlador [ServletPersonne] el que construya este modelo.
  • Líneas 18-22: muestran la lista de mensajes de error. Para ello, hay que escribir código Java en el cuerpo HTML de la página. Siempre hay que intentar reducirlo al mínimo para no saturar el código HTML. Más adelante veremos que existen soluciones que permiten reducir la cantidad de código Java en las páginas JSP.
  • Línea 4: cabe destacar la etiqueta de importación de los paquetes necesarios para la página JSP

A continuación, llamamos a esta vista «[erreurs(erreurs)]».

5.6. Pruebas de las vistas

Es posible comprobar la validez de las páginas JSP sin haber escrito el controlador. Para ello, se deben cumplir dos condiciones:

  • hay que poder solicitarlas directamente a la aplicación sin pasar por el controlador
  • la página JSP debe inicializar por sí misma el modelo que, normalmente, construiría el controlador

Para realizar estas pruebas, duplicamos las páginas JSP de las vistas en la carpeta [/WebContent/JSP] del proyecto Eclipse:

Image

A continuación, en la carpeta JSP, se modifican las páginas de la siguiente manera:

[formulaire.jsp]:


...

<%
  // -- prueba: se crea la plantilla de la página
  request.setAttribute("nom","tintin");
  request.setAttribute("age","30");
%>

<%
    // se recuperan los datos de la plantilla
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
    
<html>
    <head>
...

Se han añadido las líneas 3-7 para crear la plantilla que necesita la página de las líneas 11-12.

[reponse.jsp]:


...

<%
  // -- prueba: se crea la plantilla de la página
  request.setAttribute("nom","milou");
  request.setAttribute("age","10");
%>

<%
    // se recuperan los datos de la plantilla
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

    
<html>
    <head>
...

Se han añadido las líneas 3-7 para crear la plantilla que necesita la página de las líneas 11-12.

[erreurs.jsp]:


...

<%
  // -- prueba: se crea la plantilla de la página
  ArrayList<String> erreurs1=new ArrayList<String>();
  erreurs1.add("erreur1");
  erreurs1.add("erreur2");
  request.setAttribute("erreurs",erreurs1);
%>

<%
// se recuperan los datos de la plantilla
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

    
<html>
    <head>
...

Se han añadido las líneas 3-9 para crear la plantilla que necesita la página de la línea 13.

Inicia Tomcat, si aún no lo has hecho, y a continuación solicita las siguientes URL:

 

Efectivamente, obtenemos las vistas esperadas. Ahora que tenemos una confianza razonable en las páginas JSP de la aplicación, podemos pasar a escribir su controlador [ServletPersonne].

5.7. El controlador [ServletPersonne]

Aún nos queda por escribir el núcleo de nuestra aplicación web: el controlador. Su función consiste en:

  • recoger la solicitud del cliente,
  • procesar la acción solicitada por este,
  • enviar como respuesta la vista adecuada.

El controlador [ServletPersonne] gestionará las siguientes acciones:

n.º
solicitud
origen
procesamiento
1
[GET /personne1/main]
URL introducida por el usuario
- enviar la vista [formulaire] vacía
2
[POST /personne1/main]
con parámetros [txtNom,
txtAge, acción] enviados
al hacer clic en el botón
[Envoyer] de la vista
[formulaire]
- comprobar los valores de los parámetros [txtNom, txtAge]
- si son incorrectos, enviar la vista [erreurs(erreurs)]
- si son correctos, enviar la vista [reponse(nom,age)]

La aplicación se inicia cuando el usuario solicita la URL [/personne1/main]. Según el archivo [web.xml] de la aplicación (véase el apartado 5.4), esta solicitud es procesada por una instancia de tipo ServletPersonne que describimos a continuación.

5.7.1. Estructura básica del controlador

El código del controlador [ServletPersonne] es el siguiente:

package istia.st.servlets.personne;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
...

    // inicialización
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
    }

    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
...
    }

    // visualización de la vista inicial
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
...
    }

    // validación del formulario
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
...
    }

    // envío
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        // se pasa el control a GET
        doGet(request, response);
    }
}
  • líneas 20-22: el método [init] que se ejecuta al cargarse inicialmente el servlet
  • líneas 25-28: el método [doGet], invocado por el servidor web cuando se ha realizado una solicitud de tipo GET a la aplicación
  • líneas 42-46: el método [doPost], invocado por el servidor web cuando se ha realizado una solicitud de tipo POST a la aplicación. Como se muestra, esta también será procesada por el método [doGet] (línea 45).
  • líneas 31-33: el método [doInit] procesa la acción n.º 1 [GET /personne1/main]
  • líneas 36-39: el método [doValidationFormulaire] procesa la acción n.º 2 [POST /personne1/main] con los parámetros enviados [txtNom, txtAge, action].

A continuación describimos los distintos métodos del controlador

5.7.2. Inicialización del controlador

Cuando el contenedor de servlets carga la clase del controlador, se ejecuta su método [init]. Esto solo ocurrirá una vez. Una vez cargado en memoria, el controlador permanecerá allí y procesará las solicitudes de los distintos clientes. Cada cliente cuenta con un hilo de ejecución propio, por lo que los métodos del controlador se ejecutan simultáneamente en diferentes hilos. Cabe recordar que, por este motivo, el controlador no debe tener campos que sus métodos puedan modificar. Sus campos deben ser de solo lectura. Se inicializan mediante el método [init], cuya función principal es precisamente esa. De hecho, este método tiene la particularidad de ejecutarse una única vez por un solo hilo. Por lo tanto, no hay problemas de acceso concurrente a los campos del controlador en este método. El método [init] tiene como objetivo inicializar los objetos necesarios para la aplicación web, que serán compartidos en modo de solo lectura por todos los hilos de cliente. Estos objetos compartidos pueden colocarse en dos lugares:

  • los campos privados del controlador
  • el contexto de ejecución de la aplicación (ServletContext)

El código del método [init] del controlador [ServletPersonne] es el siguiente:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
    // parámetros de instancia
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

    // inicialización
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
        // se recuperan los parámetros de inicialización del servlet
        ServletConfig config = getServletConfig();
        // se procesan los demás parámetros de inicialización
        String valeur=null;
        for(int i=0;i<paramètres.length;i++){
            // valor del parámetro
            valeur=config.getInitParameter(paramètres[i]);
            // ¿Existe el parámetro?
            if(valeur==null){
                // se registra el error
                erreursInitialisation.add("Le paramètre ["+paramètres[i]+"] n'a pas été initialisé");
            }else{
                // se almacena el valor del parámetro
                params.put(paramètres[i],valeur);
            }
            // la URL de la vista [erreurs] tiene un tratamiento especial
            urlErreurs = config.getInitParameter("urlErreurs");
            if (urlErreurs == null)
                throw new ServletException(
                        "Le paramètre [urlErreurs] n'a pas été initialisé");
        }
    }
...
}
  • línea 16: se recupera la configuración de la aplicación web, c.a.d. El contenido del archivo [web.xml]
  • líneas 19-29: se recuperan los parámetros de inicialización del servlet, cuyos nombres se definen en la tabla [paramètres] de la línea 9
  • línea 21: se recupera el valor del parámetro
  • línea 25: si el parámetro no existe, el error se añade a la lista de errores [erreursInitialisation], inicialmente vacía (línea 8).
  • línea 28: si el parámetro está presente, se almacena junto con su valor en el diccionario [params], inicialmente vacío (línea 10).
  • líneas 31-35: el parámetro [urlErreurs] debe estar presente obligatoriamente, ya que designa la URL de la vista [erreurs] capaz de mostrar los posibles errores de inicialización. Si no existe, se interrumpe la aplicación lanzando un [ServletException] (línea 33).

5.7.3. El método [doGet]

El método [doGet] gestiona tanto las solicitudes GET como las POST en el servlet, ya que el método [doPost] redirige al método [doGet]. Su código es el siguiente:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
    // parámetros de instancia
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

...
    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        // se comprueba cómo se ha realizado la inicialización del servlet
        if (erreursInitialisation.size() != 0) {
            // se pasa el control a la página de errores
            request.setAttribute("erreurs", erreursInitialisation);
            getServletContext().getRequestDispatcher(urlErreurs).forward(
                    request, response);
            // fin
            return;
        }

        // se recupera el método de envío de la solicitud
        String méthode=request.getMethod().toLowerCase();
        // se recupera la acción que se debe ejecutar
        String action=request.getParameter("action");
        // ¿Acción?
        if(action==null){
            action="init";
        }
        // ejecución de la acción
        if(méthode.equals("get") && action.equals("init")){
            // inicio de la aplicación
            doInit(request,response);
            return;
        }
        if(méthode.equals("post") && action.equals("validationFormulaire")){
            // validación del formulario de introducción de datos
            doValidationFormulaire(request,response);
            return;
        }
        // otros casos
        doInit(request,response);
    }

    // publicación
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        // se pasa el control a GET
        doGet(request, response);
    }
}
  • líneas 18-25: se comprueba que la lista de errores de inicialización esté vacía. Si no es así, se muestra la vista [erreurs(erreursInitialisation)], que indicará el error o los errores.

Para entender este código, hay que recordar el modelo de la vista [erreurs]:

<%
// se recuperan los datos del modelo
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

La vista [erreurs] espera un elemento clave «errores» en la solicitud. El controlador crea este elemento en la línea 20.

  • Línea 28: se recupera el método [get] o [post] que el cliente ha utilizado para realizar su consulta
  • línea 30: se recupera el valor del parámetro [action] de la consulta. Recordemos que, en nuestra aplicación, solo la solicitud n.º 2, [POST /personne1/main], tiene el parámetro [action]. En esta solicitud, tiene el valor [validationFormulaire].
  • líneas 31-34: si el parámetro [action] no está presente, se le asigna el valor «init». Este será el caso en la solicitud inicial n.º 1, [GET /personne1/main].
  • líneas 36-40: procesamiento de la solicitud n.º 1 [GET /personne1/main].
  • líneas 41-45: procesamiento de la solicitud n.º 2 [POST /personne1/main].
  • línea 47: si no se da ninguno de los dos casos anteriores, se procede como si se tratara del caso n.º 1

5.7.4. El método [doInit]

Este método procesa la solicitud n.º 1 [GET /personne1/main]. En esta solicitud, debe enviar la vista [formulaire(nom,age)] vacía. Su código es el siguiente:

package istia.st.servlets.personne;
...

@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
    // parámetros de instancia
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

...    
    // visualización de la vista inicial
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        // se envía el formulario vacío
        request.setAttribute("nom", "");
        request.setAttribute("age", "");
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }
...
}
  • líneas 18-19: se muestra la vista [formulaire]. Recordemos el modelo que espera esta vista:

<%
    // se recuperan los datos del modelo
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
  • líneas 16-17: el modelo [nom,age] de la vista [formulaire] se inicializa con cadenas vacías.

5.7.5. El método [doValidationFormulaire]

Este método procesa la solicitud n.º 2 [POST /personne1/main], en la que los parámetros enviados son [action, txtNom, txtAge]. Su código es el siguiente:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
    // parámetros de instancia
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();
...
    // validación del formulario
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
        // se recuperan los parámetros
        String nom = request.getParameter("txtNom");
        String age = request.getParameter("txtAge");
        // verificación de los parámetros
        ArrayList<String> erreursAppel = new ArrayList<String>();
        // el nombre no debe estar vacío
        nom = nom.trim();
        if (nom.equals(""))
            erreursAppel.add("Le champ [nom] n'a pas été rempli");
        // la edad debe ser un número entero >=0
        if (!age.matches("^\\s*\\d+\\s*$"))
            erreursAppel.add("Le champ [age] est erroné");
        // ¿Hay errores en los parámetros?
        if (erreursAppel.size() != 0) {
            // se envía la página de errores
            request.setAttribute("erreurs", erreursAppel);
            getServletContext().getRequestDispatcher(urlErreurs).forward(request, response);
            return;
        }
        // los parámetros son correctos: se envía la página de respuesta
        request.setAttribute("nom", nom);
        request.setAttribute("age", age);
        getServletContext().getRequestDispatcher((String)params.get("urlReponse")).forward(request,
                response);
        return;
    }
...
}
  • líneas 16-17: se recuperan de la solicitud del cliente los valores de los parámetros «txtNom» y «txtAge».
  • líneas 19-26: se comprueba la validez de estos dos parámetros
  • líneas 28-33: si alguno de los parámetros es erróneo, se muestra la vista [erreurs(erreursAppel)]. Recordemos el modelo de esta vista:

<%
// se recuperan los datos del modelo
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>
  • líneas 35-38: si los dos parámetros «txtNom» y «txtAge» recuperados tienen valores válidos, se muestra la vista [reponse(nom,age)]. Hay que recordar la plantilla de la vista [reponse]:

<%
    // se recuperan los datos del modelo
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

5.8. Pruebas

Incluimos el proyecto [mvc-personne-01] en las aplicaciones de Tomcat siguiendo el procedimiento descrito en el apartado 3.3:

Image

Inicie Tomcat. Una vez hecho esto, podremos retomar las pruebas que se muestran a modo de ejemplo en el apartado 5.1. También podremos añadir otras. Por ejemplo, podemos eliminar uno de los parámetros de configuración urlXXX de web.xml y ver el resultado. Así, como se muestra a continuación, uno de los parámetros se ha comentado en [web.xml]:


        <!-- 
            <init-param>
              <param-name>urlFormulaire</param-name>
              <param-value>
                /WEB-INF/vues/formulaire.jsp
              </param-value>
            </init-param>
        -->

Iniciamos o reiniciamos Tomcat y accedemos a la URL [http://localhost:8080/personne1/main]. Obtenemos la siguiente respuesta:

Image