Skip to content

7. Aplicación web MVC [personne] – versión 3


Lecturas recomendadas en [ref1]: capítulo 9


7.1. Introduction

Nos proponemos agregar código JavaScript a las páginas HTML enviadas al navegador. Es este último el que ejecuta el código JavaScript incrustado en la página que muestra. Esta tecnología es independiente de la que utiliza el servidor web para generar el documento HTML (Java/servlets/JSP, ASP.NET, ASP, PHP, Perl, Python, ...).

[formulaire.jsp]

La vista resultante de esta página tendrá el siguiente aspecto:

Image

Los botones cuyo texto aparece en un recuadro utilizan código JavaScript integrado en la página HTML:

Texto
Tipo HTML
Función
Submit
<submit>
desempeña la función del botón [Envoyer] de las versiones anteriores: envía los valores ingresados al controlador
[Envoyer]
<button>
nuevo botón: verifica localmente la validez de los datos ingresados antes de enviarlos al controlador
Rétablir
<reset>
restablece el formulario al estado en el que lo recibió inicialmente el navegador
[Effacer]
<button>
borra el contenido de los dos campos de entrada

A continuación se muestra un ejemplo de uso de los botones [Envoyer] y [Effacer]:

También utilizaremos código JavaScript para gestionar el enlace [Retour au formulaire] de las vistas [erreurs] y [réponse]. Tomemos como ejemplo la vista [réponse]:

1

La diferencia está en la URL que se muestra en [1]. En la versión anterior, esta era:

[http://localhost:8080/persona2/main?action=retourFormulaire]

Aquí, la acción ya no forma parte de la URL porque se enviará mediante un POST en lugar de un GET. Esta modificación hará que la única URL que muestre el navegador sea [http://localhost:8080/personne3/main], independientemente de la acción solicitada.

7.2. El proyecto de Eclipse

Para crear el proyecto Eclipse [mvc-personne-03] de la aplicación web [/personne3], se duplicará el proyecto [mvc-personne-02] siguiendo el procedimiento descrito en el párrafo 6.2, página 78.

7.3. Configuración de la aplicación web [personne3]

El archivo web.xml de la aplicación /persona3 es el siguiente:


<?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-03</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>lienRetourFormulaire</param-name>
            <param-value>
                Retour au formulaire
            </param-value>
        </init-param>
    </servlet>
    <!--  Mapeo 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>

Este archivo es idéntico al de la versión anterior, salvo por algunos detalles:

  • línea 6: el nombre de visualización de la aplicación web ha cambiado a [mvc-personne-03]

El parámetro [urlControleur] ha desaparecido. En la versión anterior, se utilizaba para establecer el destino del POST de la vista [formulaire]. En esta nueva versión, el destino será la cadena vacía, c.a.d. La URL que muestra el navegador. Ya explicamos que esta siempre sería [http://localhost:8080/personne3/main], la que necesitamos para el POST de la vista [formulaire].

La página de inicio [index.jsp] cambia:


<%@ 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("/personne3/main");
%>
  • línea 5: la página [index.jsp] redirige al cliente a la URL del controlador [ServletPersonne] de la aplicación [/personne3].

7.4. El código de las vistas

7.4.1. La vista [formulaire]

Esta vista quedó así:

Image

Se genera a partir de la página JSP [formulaire.jsp] 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) session.getAttribute("nom");
            String age = (String) session.getAttribute("age");
%>


<html>
  <head>
    <title>Personne - formulaire</title>
    <script language="javascript">
        // -------------------------------
        function effacer(){
          // se borran los campos de entrada
          with(document.frmPersonne){
            txtNom.value="";
            txtAge.value="";
          }//con
        }//borrar
        // -------------------------------      
        function envoyer(){
          // verificación de los parámetros antes de enviarlos
          with(document.frmPersonne){
            // el nombre no debe estar en blanco
            champs=/^\s*$/.exec(txtNom.value);
            if(champs!=null){
              // el nombre está vacío
              alert("Vous devez indiquer un nom");
              txtNom.value="";
              txtNom.focus();
              // regreso a la interfaz visual
              return;
            }//si
             // la edad debe ser un número entero positivo
            champs=/^\s*\d+\s*$/.exec(txtAge.value);
            if(champs==null){
              // la edad es incorrecta
              alert("Age incorrect");
              txtAge.focus();
              // regreso a la interfaz visual
              return;
            }//si
             // los parámetros son correctos; se envían al servidor
            submit();
          }//con
        }//enviar
      </script>
  </head>
  <body>
    <center>
      <h2>Personne - formulaire</h2>
      <hr>
      <form name="frmPersonne" 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="Submit"></td>
            <td><input type="button" value="[Envoyer]" onclick="envoyer()"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="[Effacer]" onclick="effacer()"></td>
          </tr>
        </table>
        <input type="hidden" name="action" value="validationFormulaire">
      </form>
    </center>
  </body>
</html>


Novedades:

  • línea 56: el formulario tiene el nombre [frmPersonne]. Este nombre se utilizará en el código JavaScript. Cabe destacar la ausencia del atributo [action], lo que hace que el formulario [frmPersonne] se envíe a la URL que muestra el navegador.
  • línea 70: el botón [Submit] cumple la función del botón [Envoyer] de las versiones anteriores
  • línea 71: al hacer clic en el botón [Envoyer], del tipo [Button], se ejecuta la función de JavaScript [envoyer] definida en la línea 24
  • línea 72: el botón [Rétablir] no ha cambiado de función
  • línea 73: al hacer clic en el botón [Effacer], del tipo [Button], se ejecuta la función de JavaScript [effacer] definida en la línea 16

Antes de comentar el código de JavaScript, recordemos algunas notaciones:

JavaScript maneja la página que se muestra y su contenido como un árbol de objetos cuya raíz es el objeto [document]. En este documento, puede haber uno o varios formularios. [document.frmPersonne] se refiere al formulario con el nombre [frmPersonne] definido en la línea 56. Este formulario también contiene objetos. Los campos de entrada forman parte de ellos. Así, [document.frmPersonne.txtNom] hace referencia al objeto de imagen del campo de entrada HTML, definido en la línea 60. El objeto [txtNom] tiene diversas propiedades, entre ellas la propiedad [value], que designa el contenido del campo de entrada. Así, [document.frmPersonne.txtNom.value] designa el contenido del campo de entrada [txtNom].

  • líneas 16-22: la función de JavaScript [effacer] coloca una cadena vacía en los campos de entrada [txtNom, txtAge].
  • líneas 24-49: la función de JavaScript [envoyer] verifica la validez de los valores de los campos de entrada [txtNom, txtAge] antes de enviarlos. Para ello, utiliza expresiones regulares.
  • línea 28: verifica si el valor del campo de entrada [txtNom] coincide con el patrón /s*, que significa 0 o más espacios. Si la respuesta es sí, significa que el usuario no ha ingresado ningún nombre. Si hay coincidencia con el patrón, la variable champs tendrá un valor diferente al del puntero null; de lo contrario, tendrá el valor null.
  • línea 29: si hay coincidencia con el modelo
  • línea 30: se muestra un mensaje al usuario
  • línea 32: se coloca la cadena vacía en el campo [txtNom] (podría haber una secuencia de espacios)
  • línea 33: se coloca el cursor parpadeante en el campo [txtNom]
  • línea 34: se interrumpe la función. De esta manera, no se envían los valores ingresados al servidor en el campo POST.
  • líneas 38-45: se sigue un procedimiento similar con el campo [txtAge]
  • línea 47: si llegamos hasta aquí, significa que los valores ingresados son correctos. Entonces se envía (submit) el formulario [frmPersonne] al servidor web. Todo sucede entonces como si hubiéramos presionado el botón con la leyenda [Submit].

7.4.2. La vista [reponse]

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

A diferencia de la versión anterior, la novedad solo aparece cuando se utiliza el enlace [Retour au formulaire] de la vista [réponse]:

La diferencia está en la URL que se muestra en [1]. En la versión anterior, esta era:

[http://localhost:8080/persona2/main?action=retourFormulaire]

Aquí, la acción ya no forma parte de la URL porque se enviará mediante un POST en lugar de un GET. La nueva página JSP [reponse.jsp] es lqqqaaaaaaaaaqqAAAaaa

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");
  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>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      <%= lienRetourFormulaire %>
    </a>
  </body>
</html>

Novedades:

  • líneas 35-37: el enlace [Retour au formulaire] contiene JavaScript. Al hacer clic en este enlace, se ejecuta el código JavaScript del atributo [href]. Como vimos en el análisis de [formulaire.jsp], sabemos que este código envía los valores de los campos de tipo <input>, <select>, ... del formulario [frmPersonne].
  • Líneas 32-34: definen el formulario [frmPersonne]. Este solo tiene un campo de tipo <input type="hidden" ...>, es decir, un campo oculto. Este campo [action] sirve para transmitir al controlador el nombre de la acción que se debe ejecutar, en este caso [retourFormulaire].

7.4.3. La vista [erreurs]

Esta vista señala los errores de entrada en el formulario. La modificación realizada es la misma que para la vista [réponse]:

La diferencia radica en la URL que se muestra en [1]. En la versión anterior, esta era:

[http://localhost:8080/persona2/main?action=retourFormulaire]

Aquí, la acción ya no forma parte de la URL porque se enviará mediante un POST en lugar de un GET. La nueva página JSP [reponse.jsp] es la 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"); 
  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>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      <%= lienRetourFormulaire %>
    </a>
  </body>
</html>

Novedades:

  • líneas 30-32: la nueva gestión del clic en el enlace. Las explicaciones dadas al respecto en el estudio de [réponse.jsp] también son válidas aquí.

7.5. Pruebas de las vistas

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

Image

Luego, en la carpeta JSP, se modifican las páginas de la siguiente manera:

[formulaire.jsp]:


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

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

Se agregaron las líneas 4 y 5 para crear la plantilla que necesita la página de las líneas 9 y 10.

[reponse.jsp]:


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

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

Se agregaron las líneas 4 a 6 para crear la plantilla que necesita la página de las líneas 11 a 13.

[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);
  request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>

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

Se agregaron las líneas 4 a 8 para crear la plantilla que necesita la página de las líneas 13 a 14.

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

 

Sí, obtenemos las vistas esperadas.

7.6. El controlador [ServletPersonne]

El controlador [ServletPersonne] de la aplicación web [/personne3] procesará las siguientes acciones:

n.º
solicitud
origen
procesamiento
1
[GET /personne3/main]
URL ingresada por el usuario
- enviar la vista [formulaire] vacía
2
[POST /personne3/main]
con parámetros [txtNom,
txtAge, action=validationFormulaire]
publicados
al hacer clic en el botón
[Envoyer] de la vista
[formulaire]
- verificar 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)]
3
[POST /personne3/main]
con parámetros
[action=retourFormulaire]
ostés
al hacer clic en el enlace [Regresar al
formulario] de las vistas
[réponse] y [erreurs].
- Enviar la vista [formulaire] prellenada con los últimos valores ingresados

Por lo tanto, tenemos una nueva acción que procesar: [POST /personne3/main] con el parámetro enviado [action=retourFormulaire], en lugar de la acción anterior [GET /personne3/main?action=retourFormulaire].

7.6.1. Estructura básica del controlador

El esqueleto del controlador [ServletPersonne] es idéntico al de la versión anterior.

package istia.st.servlets.personne;

...
import javax.servlet.http.HttpSession;

@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","lienRetourFormulaire"};
    private Map params=new HashMap<String,String>();
    ...

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

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

     // visualización del formulario vacío
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        ...
    }

     // visualización del formulario prellenado
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        ...
    }

     // validación del formulario
    void doValidationFormulaire(HttpServletRequest request,
    ...
    }

     // enviar
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    ...
    }
}

Novedades:

  • En la línea 11, la tabla [paramètres] ya no contiene el parámetro [urlControleur], el cual se ha eliminado del archivo [web.xml].

Los métodos [init, doValidationFormulaire] siguen siendo los mismos. Los métodos [doGet, doInit, doRetourFormulaire] cambian ligeramente.

7.6.2. El método [doGet]

El método [doGet] debe procesar la acción [POST /personne3/main] con el parámetro enviado [action=retourFormulaire]:

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

...
        if(méthode.equals("post") && action.equals("retourFormulaire")){
             // regreso al formulario de ingreso
            doRetourFormulaire(request,response);
            return;
        }
         // otros casos
        doInit(request,response);
    }
  • líneas 6-9: procesamiento de la acción [POST /personne3/main] con el parámetro enviado [action=retourFormulaire]

7.6.3. El método [doInit]

Este método procesa la solicitud n.º 1 [GET /personne3/main]. Su código es el siguiente:

             // visualización del formulario en blanco
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // se recupera la sesión del usuario
        HttpSession session = request.getSession(true);        
         // se envía el formulario vacío
        session.setAttribute("nom", "");
        session.setAttribute("age", "");
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

La novedad es que la vista [formulaire] que se muestra en la línea 8 ya no incluye el elemento [action] en su modelo.

7.6.4. El método [doRetourFormulaire]

Este método procesa la solicitud n.º 1 [POST /personne3/main] con [action=retourFormulaire] en los elementos enviados. Su código es el siguiente:

     // se muestra el formulario prellenado
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // se recupera la sesión del usuario
        HttpSession session = request.getSession(true);        
         // ¿Aparece el nombre en la sesión?
        String nom = (String) session.getAttribute("nom");
        if (nom == null)
            session.setAttribute("nom", "");
         // ¿La edad está presente en la sesión?
        String age = (String) session.getAttribute("age");
        if (age == null)
            session.setAttribute("age", "");
         // se muestra el formulario
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

La novedad es que la vista [formulaire] que se muestra en la línea 14 ya no incluye el elemento [action] en su modelo.

7.7. Tests

Inicie o reinicie Tomcat después de haber integrado en él el proyecto de Eclipse [personne-mvc-03]. Solicite la URL [http://localhost:8080/personne3] y luego reanude las pruebas mostradas como ejemplo en el párrafo 7.1.