Skip to content

3. Fundamentos del desarrollo web en Java

Ahora abordamos el desarrollo de aplicaciones web dinámicas, c.a.d, en las que las páginas HTML enviadas al usuario son generadas por programas.

3.1. Creación de un proyecto web en Eclipse

Vamos a desarrollar una primera aplicación web con Eclipse/Tomcat. Seguiremos un procedimiento similar al utilizado para crear una aplicación web sin Eclipse. Una vez iniciado Eclipse, creamos un nuevo proyecto:

Image

que definimos como un proyecto web dinámico:

Image

En la primera página del asistente de creación, especificamos el nombre del proyecto [1] y su ubicación [2]:

Image

En la segunda página del asistente, aceptamos los valores por defecto:

Image

La última página del asistente nos pide que definamos el contexto [3] de la aplicación:

Image

Una vez validado el asistente mediante [Finish], Eclipse se conecta al sitio [http://java.sun.com] para recuperar ciertos documentos que desea almacenar en caché con el fin de evitar accesos innecesarios a la red. A continuación, se solicita una autorización de licencia:

Image

Lo aceptamos. Eclipse crea el proyecto web. Para mostrarlo, utiliza un entorno, denominado «perspectiva», diferente al que se utiliza para un proyecto Java clásico:

Image

La perspectiva asociada a un proyecto web es la perspectiva J2EE. La aceptamos para ver... El resultado obtenido es el siguiente:

Image

La perspectiva J2EE resulta, de hecho, innecesariamente compleja para proyectos web sencillos. En este caso, basta con la perspectiva Java. Para acceder a ella, utilizamos la opción [Window -> Open perspective -> Java]:

Image

src: contendrá el código Java de las clases de la aplicación, así como los archivos que deben estar en el Classpath de la aplicación.

build/classes (no representado): contendrá los archivos .class de las clases compiladas, así como una copia de todos los archivos que no sean .java y que se encuentren en src. Una aplicación web suele utilizar los denominados «archivos de recursos», que deben estar en el Classpath de la aplicación, c.a.d. El conjunto de carpetas que JVM explora cuando la aplicación hace referencia a una clase, ya sea durante la compilación o en tiempo de ejecución. Eclipse se encarga de que la carpeta build/classes forme parte del web. Los archivos «de recursos» se colocan en la carpeta src, sabiendo que Eclipse los copiará automáticamente a build/classes.

WebContent: contendrá los recursos de la aplicación web que no deben estar en el Classpath de la aplicación.

WEB-INF/lib: contendrá los archivos .jar que necesita la aplicación web.

Veamos el contenido del archivo [WEB-INF/web.xml] que configura la aplicación [personne]:


<?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>    personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Ya nos hemos encontrado con este tipo de configuración cuando estudiamos la creación de páginas de inicio en el apartado 2.3.4. Este archivo no hace más que definir una serie de páginas de inicio. Solo conservamos la primera. El archivo [web.xml] queda así:


<?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>personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

El contenido del archivo XML anterior debe cumplir las reglas sintácticas definidas en el archivo designado por el atributo [xsi:schemaLocation] de la etiqueta de apertura <web-app>. En este caso, dicho archivo es [http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd]. Se trata de un archivo XML al que se puede acceder directamente con un navegador. Si este es lo suficientemente reciente, podrá mostrar un archivo XML:

Image

Eclipse intentará verificar la validez del documento XML utilizando el archivo .xsd especificado en el atributo [xsi:schemaLocation] de la etiqueta de apertura <web-app>. Para ello, realizará un acceso a la red. Si tu ordenador está en una red privada, debes indicar a Eclipse el servidor que debe utilizarse para salir de la red privada, denominado proxy HTTP. Esto se hace con la opción [Window -> Preferences -> Internet]:

Image

Se marca la casilla (1) si se está en una red privada. En (2), se indica el nombre del servidor que aloja el proxy HTTP y en (3), el puerto de escucha de este. Por último, en (4), se indican los equipos para los que no hay que pasar por el proxy, es decir, aquellos que se encuentran en la misma red privada que el equipo con el que se está trabajando.

Ahora vamos a crear el archivo [index.html] de la página de inicio.

3.2. Creación de una página de inicio

Hacemos clic con el botón derecho del ratón en la carpeta [WebContent] y seleccionamos la opción [New -> Other]:

Image

Seleccionamos el tipo [HTML] y hacemos clic en [Next] ->

Image

En la imagen anterior, seleccionamos la carpeta principal [WebContent] en (1) o en (2) y, a continuación, especificamos en (3) el nombre del archivo que se va a crear. Una vez hecho esto, pasamos a la siguiente página del asistente:

Image

Con (1), podemos generar un archivo HTML ya rellenado con los datos de (2). Si desmarcamos (1), se genera un archivo HTML vacío. Dejamos marcada la casilla (1) para disponer de una estructura de código. Finalizamos el asistente con [Finish]. A continuación, se crea el archivo [index.html]:

Image

con el siguiente contenido:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

Modificamos este archivo de la siguiente manera:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Application personne</title>
</head>
<body>
Application personne active...
<br>
<br>
Vous êtes sur la page d'accueil
</body>
</html>

3.3. Prueba de la página de inicio

Si no aparece, abramos la vista [Servers] con la opción [Window - > Show View -> Other -> Servers] y, a continuación, hagamos clic con el botón derecho del ratón sobre el servidor Tomcat 5.5:

Image

La opción [Add and Remove Objects] anterior permite añadir o eliminar aplicaciones web del servidor Tomcat:

Image

Los proyectos web reconocidos por Eclipse aparecen en (1). Se pueden registrar en el servidor Tomcat mediante (2). Las aplicaciones web registradas en el servidor Tomcat aparecen en (4). Se pueden dar de baja con (3). Registramos el proyecto [personne]:

Image

y, a continuación, finalicemos el asistente de registro con [Finish]. La vista [Servers] muestra que el proyecto [personne] se ha registrado en Tomcat:

Image

Ahora, iniciemos el servidor Tomcat:

Abramos el navegador web:

Image

y, a continuación, introduzcamos la URL [http://localhost:8080/personne]. Esta URL corresponde a la raíz de la aplicación web. No se solicita ningún documento. En este caso, se muestra la página de inicio de la aplicación. Si no existe, se muestra un error. En este caso, la página de inicio sí existe. Se trata del archivo [index.html] que hemos creado anteriormente. El resultado obtenido es el siguiente:

Image

Es tal y como se esperaba. Ahora, utilicemos un navegador externo a Eclipse y solicitemos la misma URL:

Image

Por lo tanto, la aplicación web [personne] también es reconocible fuera de Eclipse.

3.4. Creación de un formulario HTML

Ahora creamos un documento estático HTML [formulaire.html] en la carpeta [personne]:

Image

Para crearlo, seguiremos el procedimiento descrito en el apartado 3.2, página 33. Su contenido será el siguiente:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Personne - formulaire</title>
</head>
<body>
  <center>
    <h2>Personne - formulaire</h2>
    <hr>
    <form action="" method="post">
    <table>
      <tr>
        <td>Nom</td>
        <td><input name="txtNom" value="" type="text" size="20"></td>
      </tr>
      <tr>
        <td>Age</td>
        <td><input name="txtAge" value="" type="text" size="3"></td>
      </tr>
    </table>
    <table>
      <tr>
        <td><input type="submit" value="Envoyer"></td>
        <td><input type="reset" value="Retablir"></td>
        <td><input type="button" value="Effacer"></td>
      </tr>
    </table>
    </form>
  </center>
</body>
</html>

El código HTML anterior corresponde al formulario que se muestra a continuación:

Image

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

Guardemos el documento en la carpeta <persona>/WebContent. Iniciemos Tomcat si es necesario. Con un navegador, accedamos a URL http://localhost:8080/personne/formulaire.html:

Image

La arquitectura cliente/servidor de esta aplicación básica es la siguiente:

Image

El servidor web se encuentra entre el usuario y la aplicación web y no se ha representado aquí. [formulaire.html] es un documento estático que proporciona el mismo contenido en cada solicitud del cliente. La programación web tiene como objetivo generar contenido adaptado a la solicitud del cliente. Este contenido se genera mediante un programa. Una primera solución consiste en utilizar una página JSP (Java Server Page) en lugar del archivo estático HTML. Esto es lo que vamos a ver ahora.

3.5. Creación de una página JSP


Contenido de [ref1]: capítulo 1, capítulo 2: 2.2, 2.2.1, 2.2.2, 2.2.3, 2.2.4


La arquitectura cliente/servidor anterior se transforma de la siguiente manera:

Image

Una página JSP es una variante configurada de la página HTML. Algunos elementos de la página no reciben su valor hasta el momento de la ejecución. Estos valores se calculan mediante un programa. Por lo tanto, se trata de una página dinámica: las sucesivas solicitudes de la página pueden dar lugar a respuestas diferentes. En este contexto, denominamos «respuesta» a la página HTML mostrada por el navegador del cliente. Al final, el navegador siempre recibe un documento HTML. Este documento HTML lo genera el servidor web a partir de la página JSP. Esta última sirve de plantilla. Sus elementos dinámicos se sustituyen por sus valores efectivos en el momento de la generación del documento HTML.

Para crear una página JSP, hacemos clic con el botón derecho del ratón en la carpeta [WebContent] y seleccionamos la opción [New -> Other]:

Image

Elegimos el tipo [JSP] y hacemos [Next] ->

Image

En la imagen anterior, seleccionamos la carpeta principal [WebContent] en (1) o en (2) y, a continuación, especificamos en (3) el nombre del archivo que se va a crear. Una vez hecho esto, pasamos a la siguiente página del asistente:

Image

Con (1), podemos generar un archivo JSP rellenado previamente con (2). Si desmarcamos (1), se genera un archivo JSP vacío. Dejamos marcada la casilla (1) para disponer de una estructura de código. Finalizamos el asistente con [Finish]. A continuación, se crea el archivo [formulaire.jsp]:

Image

con el siguiente contenido:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

La línea 1 indica que se trata de una página JSP. Transformamos el texto anterior de la siguiente manera:


<%@ 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 parámetros
  String nom=request.getParameter("txtNom");
  if(nom==null) nom="inconnu";
  String age=request.getParameter("txtAge");
  if(age==null) age="xxx";  
%>

<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title>Personne - formulaire</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire</h2>
      <hr>
      <form action="" 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>
        </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>
      </form>
    </center>
  </body>
</html>

El documento, que inicialmente era estático, se ha convertido ahora en dinámico mediante la introducción de código Java. Para este tipo de documentos, siempre procederemos de la siguiente manera:

  • insertamos código Java al principio del documento para recuperar los parámetros necesarios para que el documento se muestre. Estos suelen encontrarse en el objeto `request`. Este objeto representa la solicitud del cliente. Dicha solicitud puede pasar por varios servlets y páginas JSP que puedan haberla enriquecido. En este caso, nos llegará directamente desde el navegador.
  • El código HTML se encuentra a continuación. En la mayoría de los casos, se limitará a mostrar variables calculadas previamente en el código Java mediante las etiquetas <%= variable %>. Cabe señalar aquí que el signo = va pegado al signo %. Esto es una causa frecuente de errores.

¿Qué hace el documento dinámico anterior?

  • Líneas 6-9: recupera de la consulta dos parámetros denominados [txtNom] y [txtAge] y asigna sus valores a las variables [nom] (línea 6) y [age] (línea 8). Si no encuentra los parámetros, asigna valores por defecto a las variables asociadas.
  • Muestra el valor de las dos variables [nom, age] en el código HTML que aparece a continuación (líneas 25 y 29).

Hagamos una primera prueba. Iniciemos Tomcat si es necesario y, a continuación, con un navegador, solicitemos la página URL http://localhost:8080/personne/formulaire.jsp:

Image

Se ha accedido al documento formulaire.jsp sin pasar ningún parámetro. Por lo tanto, se han mostrado los valores por defecto. Ahora solicitemos el URLhttp://localhost:8080/personne/formulaire.jsp?txtNom=martin&txtAge=14:

Image

En esta ocasión, hemos pasado al documento formulaire.jsp los parámetros txtNom y txtAge que esperaba. Por lo tanto, los ha mostrado. Sabemos que hay dos métodos para pasar parámetros a un documento web: GET y POST. En ambos casos, los parámetros pasados se encuentran en el objeto predefinido request. En este caso, se han pasado mediante el método GET.

3.6. Creación de un servlet


Lecturas [ref1]: capítulo 1, capítulo 2: 2.1, 2.1.1, 2.1.2, 2.3.1


En la versión anterior, la solicitud del cliente se procesaba mediante una página JSP. Al realizar la primera llamada a dicha página, el servidor web —en este caso, Tomcat— crea una clase Java a partir de ella y la compila. Es el resultado de esta compilación el que, en última instancia, procesa la solicitud del cliente. La clase generada a partir de la página JSP es un servlet porque implementa la interfaz [javax.Servlet]:

Image

La solicitud del cliente puede ser procesada por cualquier clase que implemente esta interfaz. Ahora creamos una clase de este tipo: ServletFormulaire. La arquitectura cliente/servidor anterior se transforma de la siguiente manera:

Image

Con la arquitectura basada en páginas JSP, el documento HTML enviado al cliente era generado por el servidor web a partir de la página JSP, que servía de plantilla. En este caso, el documento HTML enviado al cliente será generado íntegramente por el servlet.

3.6.1. Creación del servlet

En Eclipse, hacemos clic con el botón derecho del ratón en la carpeta [src] y seleccionamos la opción para crear una clase:

Image

A continuación, definimos las características de la clase que vamos a crear:

Image

En (1) se introduce el nombre del paquete; en (2), el nombre de la clase que se va a crear. Esta debe derivar de la clase indicada en (3). No es necesario escribir manualmente el nombre completo de esta. El botón (4) permite acceder a las clases que se encuentran actualmente en Classpath de la aplicación web:

Image

En (1) se escribe el nombre de la clase que se busca. En (2) aparecen las clases del Classpath cuyo nombre contiene la cadena escrita en (1).

Tras validar el asistente de creación, el proyecto web [personne] se modifica de la siguiente manera:

Image

Se ha creado la clase [ServletFormulaire] con un esqueleto de código:

Image

La captura de pantalla anterior muestra que Eclipse señala un [warning] en la línea que declara la clase. Hagamos clic en el icono (lámpara) que señala este [warning]:

Image

Tras hacer clic en (1), en (2) se nos proponen soluciones para eliminar el [warning]. Al seleccionar una de ellas, aparece en (3) la modificación del código que conllevará dicha elección.

Java 1.5 introdujo cambios en el lenguaje Java y lo que era correcto en una versión anterior ahora puede dar lugar a [warnings]. Estos no indican errores que puedan impedir la compilación de la clase. Su finalidad es llamar la atención del desarrollador sobre aspectos del código que podrían mejorarse. El código [warning] indicado señala que una clase debería tener un número de versión. Este se utiliza para la serialización/deserialización de objetos, c.a.d. cuando un objeto Java .class en memoria debe transformarse en una secuencia de bits enviada secuencialmente en un flujo de escritura, o al contrario, cuando un objeto Java .class en memoria debe crearse a partir de una secuencia de bits leída secuencialmente en un flujo de lectura. Todo esto dista mucho de nuestras preocupaciones actuales. Por lo tanto, le pediremos al compilador que ignore esta advertencia eligiendo la solución [Add @SuppressWarnings ...]. El código queda entonces así:

Image

Ya no aparece [warning]. La línea añadida se denomina «anotación», un concepto que apareció con Java 1.5. Completaremos este código más adelante.

3.6.2. Classpath de un proyecto de Eclipse

El Classpath de una aplicación Java es el conjunto de carpetas y archives.jar que se exploran cuando el compilador la compila o cuando la JVM la ejecuta. Estas dos Classpath no tienen por qué ser idénticas, ya que algunas clases solo son necesarias en la ejecución y no en la compilación. Tanto el compilador de Java como el JVM disponen de un argumento que permite especificar el Classpath de la aplicación que se va a compilar o ejecutar. De forma más o menos transparente para el usuario, Eclipse se encarga de generar y pasar este argumento al JVM.

¿Cómo se pueden conocer los elementos del Classpath de un proyecto de Eclipse? Con la opción [<projet> / Build Path / Configure Build Path]:

Image

A continuación, aparece el siguiente asistente de configuración:

Image

La pestaña (1) [Libraries] permite definir la lista de archivos .jar que forman parte del Classpath de la aplicación. Por lo tanto, la JVM los explora cuando la aplicación solicita una clase. Los botones [2] y [3] permiten añadir archivos al Classpath. El botón [2] permite seleccionar archivos que se encuentran en las carpetas de los proyectos gestionados por Eclipse, mientras que el botón [3] permite seleccionar cualquier archivo del sistema de archivos del ordenador.

Arriba aparecen tres bibliotecas (Libraries):

  • [JRE System Library]: biblioteca básica para los proyectos Java de Eclipse:

Image

  • [Tomcat v5.5 runtime]: biblioteca aportada por el servidor Tomcat. Contiene las clases necesarias para el desarrollo web. Esta biblioteca se incluye en todos los proyectos web de Eclipse que se hayan asociado al servidor Tomcat.

Image

El archivo [servlet-api.jar] es el que contiene la clase [javax.servlet.http.HttpServlet], clase padre de la clase [ServletFormulaire] que estamos creando. El hecho de que este archivo se encuentre en el Classpath de la aplicación es lo que ha permitido que se sugiriera como clase principal en el asistente que se muestra a continuación.

Image

Si no hubiera sido así, no habría aparecido entre las propuestas de [2]. Por lo tanto, si en este asistente se desea hacer referencia a una clase principal y esta no aparece entre las propuestas, es porque o bien se ha escrito mal el nombre de dicha clase, o bien el archivo que la contiene no se encuentra en el Classpath de la aplicación.

  • [Web App Libraries] recoge los archivos presentes en la carpeta [WEB-INF/lib] del proyecto. En este caso, está vacía:

Image

Los archivos del Classpath del proyecto Eclipse aparecen en el explorador de proyectos. Por ejemplo, para el proyecto web [personne]:

Image

El explorador de proyectos nos permite acceder al contenido de estos archivos:

Image

Así pues, como se puede ver arriba, es el archivo [servlet-api.jar] el que contiene la clase [javax.servlet.http.HttpServlet].

3.6.3. Configuración del servlet


Lecturas [ref1]: capítulo 2: 2.3, 2.3.1, 2.3.2, 2.3.3, 2.3.4


El archivo [WEB-INF/web.xml] sirve para configurar la aplicación web:

Image

Este archivo, correspondiente al proyecto [personne], es actualmente el siguiente (véase la página 32):


<?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>personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Solo indica la existencia de un archivo de inicio (línea 8). Lo modificamos para declarar:

  • la existencia del servlet [ServletFormulaire]
  • los URL procesados por este servlet
  • los parámetros de inicialización del servlet

El archivo web.xml de nuestra aplicación «persona» quedará así:


<?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>personne</display-name>
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Los puntos principales de este archivo de configuración son los siguientes:

  • las líneas 7-24 están relacionadas con la presencia del servlet [ServletFormulaire]
  • líneas 7-20: la configuración de un servlet se realiza entre las etiquetas <servlet> y </servlet>. Una aplicación puede contener varios servlets y, por lo tanto, tantas secciones de configuración <servlet>...</servlet> como sea necesario.
  • línea 8: la etiqueta <servlet-name> asigna un nombre al servlet; puede ser cualquiera
  • líneas 9-11: la etiqueta <servlet-class> indica el nombre completo de la clase correspondiente al servlet. Tomcat buscará esta clase en el archivo Classpath del proyecto web [personne]. La encontrará en [build/classes]:

Image

  • líneas 12-15: la etiqueta <init-param> sirve para pasar parámetros de configuración al servlet. Estos suelen leerse en el método init del servlet, ya que sus parámetros de configuración deben conocerse desde su primera carga.
  • líneas 13-14: la etiqueta <param-name> establece el nombre del parámetro y <param-value> su valor.
  • Las líneas 12-15 definen un parámetro [defaultNom,"inconnu"] y las líneas 16-19, un parámetro [defaultAge,"XXX"]
  • Líneas 21-24: la etiqueta <servlet-mapping> sirve para asociar un servlet (servlet-name) a un patrón de URL (url-pattern) de URL. En este caso, el patrón es sencillo. Indica que cada vez que una URL tenga la forma /formulario, se deberá utilizar el servlet «formulario-persona», c.a.d, de la clase [istia.st.servlets.ServletFormulaire] (líneas 8-11). Por lo tanto, solo hay una URL aceptada por el servlet [formulairepersonne].

3.6.4. El código del servlet [ServletFormulaire]

El servlet [ServletFormulaire] tendrá el siguiente código:

package istia.st.servlets.personne;

import java.io.IOException;
import java.io.PrintWriter;

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 ServletFormulaire extends HttpServlet {

    // parámetros de instancia
    private String defaultNom = null;
    private String defaultAge = null;

    // inicialización
    public void init() {
        // se recuperan los parámetros de inicialización del servlet
        ServletConfig config = getServletConfig();
        defaultNom = config.getInitParameter("defaultNom");
        if (defaultNom == null)
            defaultNom = "NNNNNNNNNNNNNNN";
        defaultAge = config.getInitParameter("defaultAge");
        if (defaultAge == null)
            defaultAge = "AAA";
    }

    // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        // se recuperan los parámetros del formulario
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
        // se muestra el formulario
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println(
                "<html>"+
                  "<head>"+
                    "<title>Personne - formulaire</title>"+
                  "</head>"+
                  "<body>"+
                    "<center>"+
                      "<h2>Personne - formulaire</h2>"+
                      "<hr>"+
                      "<form action='' 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>"+
                        "</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>"+
                      "</form>"+
                    "</center>"+
                  "</body>"+
                "</html>"
      );
    }

    // POST
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        // se pasa el control a GET
        doGet(request, response);
    }
}

Con solo leer el servlet, se puede observar que es mucho más complejo que la página JSP correspondiente. Se trata de una regla general: un servlet no es adecuado para generar código HTML. Las páginas JSP son las que están diseñadas para ello. Ya tendremos ocasión de volver sobre este tema. Aclaremos algunos puntos importantes del servlet anterior:

  • cuando se invoca un servlet por primera vez, se llama a su método init (línea 20). Es el único caso en el que se invoca.
  • Si la servlet ha sido invocada por el método HTTP GET, se invoca el método doGet (línea 32) para procesar la solicitud del cliente.
  • Si se ha llamado al servlet mediante el método HTTP POST, se invoca el método doPost (línea 82) para procesar la solicitud del cliente.

El método init sirve aquí para recuperar en [web.xml] los valores de los parámetros de inicialización denominados «defaultNom» y «defaultAge». El método init, que se ejecuta al cargarse inicialmente el servlet, es el lugar adecuado para recuperar el contenido del archivo [web.xml].

  • Línea 22: se recupera la configuración [config] del proyecto web. Este objeto refleja el contenido del archivo [WEB-INF/web.xml] de la aplicación.
  • Línea 23: se recupera en esta configuración el valor de tipo String del parámetro denominado «defaultNom». Este parámetro tendrá como valor el nombre de una persona. Si no existe, se obtendrá el valor null.
  • Líneas 24-25: si el parámetro denominado «defaultNom» no existe, se asigna un valor por defecto a la variable [defaultNom].
  • Líneas 26-29: se hace lo mismo con el parámetro denominado «defaultAge».

El método doPost remite al método doGet. Esto significa que el cliente podrá enviar sus parámetros indistintamente mediante un POST o un GET.

El método doGet:

  • línea 32: el método recibe dos parámetros, `request` y `response`. `request` es un objeto que representa la totalidad de la solicitud del cliente. Es de tipo `HttpServletRequest`, que es una interfaz. `response` es de tipo `HttpServletResponse`, que también es una interfaz. El objeto `response` sirve para enviar una respuesta al cliente.
  • request.getParameter("param") sirve para recuperar de la solicitud del cliente el valor del parámetro denominado «param». En la línea 36 se recupera el valor del parámetro «txtNom», y en la línea 40, el del parámetro «txtAge». Si estos parámetros no están presentes en la solicitud, se obtiene el valor «null» como valor del parámetro.
  • Líneas 37-39: si el parámetro «txtNom» no está en la consulta, se asigna a la variable «nombre» el nombre por defecto «defaultNom», inicializado en el método init. Lo mismo ocurre en las líneas 41-43 con la edad.
  • línea 45: response.setContentType(String) sirve para establecer el valor del encabezado HTTP Content-type. Este encabezado indica al cliente la naturaleza del documento que va a recibir. El tipo text/html indica un documento HTML.
  • línea 46: response.getWriter() sirve para obtener un flujo de escritura hacia el cliente
  • líneas 47-78: se escribe el documento HTML que se va a enviar al cliente en el flujo de escritura obtenido en la línea 46.

La compilación de este servlet generará un archivo .class en la carpeta [build/classes] del proyecto [personne]:

Image

Se recomienda al lector que consulte la ayuda de Java sobre servlets. Para ello, puede utilizar Tomcat. En la página de inicio de Tomcat 5, hay un enlace [Documentation]:

Image

Este enlace conduce a una página que se invita al lector a explorar. El enlace a la documentación sobre servlets es el siguiente:

Image

3.6.5. Prueba del servlet

Ya estamos listos para realizar una prueba. Iniciemos el servidor Tomcat si es necesario.

Image

A continuación, solicitemos con un navegador la URL URL [http://localhost:8080/personne/formulaire]. Aquí solicitamos la URL [/formulaire] del contexto [/personne]. El archivo [web.xml] de este contexto indica que la URL [/formulaire] es gestionada por el servlet denominado [formulairepersonne]. En el mismo archivo, se indica que este servlet es la clase [istia.st.servlets.ServletFormulaire]. Por lo tanto, Tomcat confiará a esta clase el procesamiento de la solicitud del cliente. Si la clase aún no se ha cargado, se cargará. A continuación, permanecerá en memoria para futuras solicitudes.

Se obtiene el siguiente resultado con el navegador interno de Eclipse:

Image

Obtenemos los valores por defecto del nombre y la edad, los que figuran en el archivo [web.xml]. Ahora solicitemos el URL [http://localhost:8080/personne/formulaire?txtNom=tintin&txtAge=30]:

Image

Esta vez, obtenemos los parámetros pasados en la solicitud. Se recomienda al lector que vuelva a leer el código del servlet [ServletFormulaire] si no entiende estos dos resultados.

3.6.6. Recarga automática del contexto de la aplicación web

Iniciemos Tomcat:

Image

y, a continuación, modifiquemos el código del servlet de la siguiente manera:

    // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        // se recuperan los parámetros del formulario
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = "--"+defaultNom+"--";
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
...
  • Se ha modificado la línea 8

Guardemos la nueva clase. Al guardar, Eclipse recompilará automáticamente la clase [ServletFormulaire], lo que Tomcat detectará. A continuación, recargará el contexto de la aplicación web [personne] para tener en cuenta los cambios. Esto aparece en los registros de la vista [console]:

Image

Accedamos a la URL [http://localhost:8080/personne/formulaire] sin reiniciar Tomcat:

Image

El cambio realizado se ha aplicado correctamente.

Ahora, modifiquemos el archivo [web.xml] de la siguiente manera:


<?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>personne</display-name>
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
...
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>INCONNU</param-value>
        </init-param>
...
    </servlet>
...
</web-app>
  • Se ha modificado la línea 12

Una vez hecho esto, guardemos el nuevo archivo [web.xml]. En la vista [console], no hay ningún registro que indique la recarga del contexto de la aplicación. Accedamos a la URL [http://localhost:8080/personne/formulaire] sin reiniciar Tomcat:

Image

El cambio realizado no se ha aplicado. Reiniciemos Tomcat [clic droit sur serveur -> Restart -> Start]:

Image

y volvamos a solicitar la URL [http://localhost:8080/personne/formulaire]:

Image

Esta vez, el cambio realizado en [web.xml] es visible.

Por lo tanto, una modificación en [web.xml] no provoca una recarga automática de la aplicación que tenga en cuenta el nuevo archivo de configuración. Para forzar la recarga de la aplicación web, podemos reiniciar Tomcat como hemos hecho, pero es una operación bastante lenta. Es preferible utilizar la herramienta [manager] para la administración de las aplicaciones desplegadas en Tomcat. Para que esto sea posible, es necesario que, dentro de Eclipse, Tomcat se haya configurado tal y como se ha mostrado en el apartado 2.5.

En primer lugar, con el navegador interno de Eclipse, accedamos a la URL [http://localhost:8080] y, a continuación, sigamos el enlace [Tomcat Manager], tal y como se explica al final del apartado 2.5:

Image

Abramos un segundo navegador [clic droit sur le navigateur -> New Editor]:

En este segundo navegador, solicitemos la URL [http://localhost:8080/formulaire]:

Image

Modifiquemos el archivo [web.xml] de la siguiente manera y guardémoslo:


<!--  ServletFormulaire -->
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>YYY</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>

A continuación, volvamos a solicitar la URL [http://localhost:8080/formulaire]. Podemos observar que la modificación no se ha aplicado. Ahora, vayamos al primer navegador y recarguemos la aplicación [personne]:

Image

A continuación, volvamos a solicitar la URL [http://localhost:8080/formulaire] con el segundo navegador:

Image

La modificación de [web.xml] se ha aplicado. En la práctica, resulta útil tener un navegador abierto en la aplicación [manager] de Tomcat para gestionar este tipo de casos.

3.7. Interacción entre servlets y páginas JSP


Lecturas [ref1]: capítulo 2: 2.3.7


Volvamos a las dos arquitecturas estudiadas:

Image

Ninguna de estas dos arquitecturas resulta satisfactoria. Ambas presentan el inconveniente de mezclar dos tecnologías: la de la programación Java, que se encarga de la lógica de la aplicación web, y la de la codificación HTML, que se encarga de la presentación de la información en un navegador.

  • La solución [1] basada en la página JSP tiene el inconveniente de mezclar código HTML y código Java dentro de una misma página. No lo hemos visto en el ejemplo tratado, que era básico. Pero si [formulaire.jsp] tuviera que comprobar la validez de los parámetros [txtNom, txtAge] de la solicitud del cliente, nos habríamos visto obligados a incluir código Java en la página. Esto se vuelve inmanejable muy rápidamente.
  • La solución [2] basada en servlets presenta el mismo problema. Aunque solo haya código Java en la clase, esta debe generar un documento HTML. Una vez más, a menos que el documento HTML sea muy sencillo, su generación se vuelve complicada y casi imposible de mantener.

Vamos a evitar la mezcla de las tecnologías Java y HTML adoptando la siguiente arquitectura:

Image

  • El usuario envía su solicitud al servlet. Este la procesa y construye los valores de los parámetros dinámicos de la página JSP [formulaire.jsp], que se utilizarán para generar la respuesta HTML al cliente. Estos valores conforman lo que se denomina el modelo de la página JSP.
  • Una vez finalizado su trabajo, el servlet solicitará a la página JSP [formulaire.jsp] que genere la respuesta HTML para el cliente. Al mismo tiempo, le proporcionará los elementos que la página JSP necesita para generar dicha respuesta, elementos que conforman el modelo de la página.

Ahora vamos a analizar esta nueva arquitectura.

3.7.1. El servlet [ServletFormulaire2]

En la arquitectura anterior, el servlet se llamará [ServletFormulaire2]. Se creará en el mismo proyecto [personne] que anteriormente, al igual que todos los servlets que vendrán a continuación:

Image

[ServletFormulaire2] se obtiene, en primer lugar, copiando y pegando [ServletFormulaire] en Eclipse:

  • seleccionar [ServletFormulaire.java] -> clic con el botón derecho -> Copiar
  • seleccionar [istia.st.servlets.personne] -> clic con el botón derecho -> Pegar -> cambiar el nombre a [ServletFormulaire2.java]

A continuación, modificamos el código de [ServletFormulaire2] de la siguiente manera:

package istia.st.servlets.personne;

import java.io.IOException;
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 ServletFormulaire2 extends HttpServlet {

    // parámetros de instancia
    private String defaultNom = null;

    private String defaultAge = null;

    // inicialización
    public void init() {
        // se recuperan los parámetros de inicialización del servlet
        ServletConfig config = getServletConfig();
        defaultNom = config.getInitParameter("defaultNom");
        if (defaultNom == null)
            defaultNom = "NNNNNNNNNNNNNNN";
        defaultAge = config.getInitParameter("defaultAge");
        if (defaultAge == null)
            defaultAge = "AAA";
    }

    // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        // se recuperan los parámetros del formulario
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
        // se muestra el formulario
        request.setAttribute("nom", nom);
        request.setAttribute("age", age);
        getServletContext().getRequestDispatcher("/formulaire2.jsp").forward(request, response);
    }

    // POST
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        // se pasa el control a GET
        doGet(request, response);
    }
}

Solo ha cambiado la parte de generación de la respuesta de HTTP (líneas 44-46):

  • línea 46: la generación de la respuesta se delega a la página JSP formulaire2.jsp. Esta página, que aún no se ha analizado, se encargará de mostrar los parámetros recuperados en la solicitud del cliente: un nombre (líneas 35-38) y una edad (líneas 39-42).
  • Estos dos valores se colocan en los atributos de la solicitud [request], asociados a claves. Los atributos de una solicitud se gestionan como un diccionario.
  • Línea 44: el nombre se incluye en la consulta asociado a la clave «nombre»
  • línea 45: la edad se introduce en la consulta asociada a la clave «edad»
  • línea 46: solicita la visualización de la página JSP [formulaire2.jsp]. Se le pasan como parámetros:
  • la solicitud [request] del cliente, lo que permitirá que la página JSP tenga acceso a los atributos de dicha solicitud, que acaban de ser inicializados por el servlet
  • la respuesta [response], lo que permitirá a la página JSP generar la respuesta HTTP para el cliente

Una vez escrita la clase [ServletFormulaire2], su código compilado aparece en [build/classes]:

Image

3.7.2. La página JSP [formulaire2.jsp]

La página JSP formulaire2.jsp se obtiene copiando y pegando la página [formulaire.jsp]

Image

y, a continuación, se transforma de la siguiente manera:


<%@ 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 valores necesarios para la visualización
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");  
%>

<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title>Personne - formulaire2</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire2</h2>
      <hr>
      <form action="" 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>
        </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>
      </form>
    </center>
  </body>
</html>

Solo han cambiado las líneas 4-8 con respecto a [formulaire.jsp]:

  • línea 6: recupera el valor del atributo denominado «nombre» en la consulta [request], atributo creado por el servlet [ServletFormulaire2].
  • línea 7: hace lo mismo con el atributo «edad»

3.7.3. Configuración de la aplicación

El archivo de configuración [web.xml] se modifica de la siguiente manera:


<?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>personne</display-name>
    <!--  ServletFormulaire -->
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXXX</param-value>
        </init-param>
    </servlet>
    <!--  ServletFormulaire 2-->
    <servlet>
        <servlet-name>formulairepersonne2</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire2
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>
    <!--  Asignación ServletFormulaire -->
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
    <!--  Asignación ServletFormulaire 2-->
    <servlet-mapping>
        <servlet-name>formulairepersonne2</servlet-name>
        <url-pattern>/formulaire2</url-pattern>
    </servlet-mapping>
    <!--  archivos de inicio -->
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Hemos conservado lo existente y hemos añadido:

  • líneas 22-36: una sección <servlet> para definir el nuevo servlet ServletFormulaire2
  • líneas 42-46: una sección <servlet-mapping> para asociarle el URL /formulario2

Inicie o reinicie el servidor Tomcat si es necesario. Solicitamos el URL

http://localhost:8080/personne/formulaire2?txtNom=milou&txtAge=10:

Image

Obtenemos el mismo resultado que antes, pero ahora la estructura de nuestra aplicación es más clara: un servlet que contiene la lógica de la aplicación y delega en una página JSP el envío de la respuesta al cliente. A partir de ahora procederemos siempre de esta manera.