Estructura de las Páginas JSP
- Etiquetas Personalizadas

Finalmente llegamos al tercer grupo de etiquetas, las Etiquetas Personalizadas.


1. Conceptos Generales

Haciendo un breve repaso, sabemos que en un lenguaje basado en etiquetas (HTML, XML), cualquier cosa entre los símbolos < y >, es una etiqueta, por ejemplo: <title> es una etiqueta de título.

Las etiquetas HTML son utilizadas por el navegador (del lado del cliente) para formatear los datos a ser desplegados. Así mismo, en JSP tenemos etiquetas entre los símbolos < y >, y uno puede hacer con ellas prácticamente cualquier cosa que uno desee (del lado del servidor), por ejemplo: <xgms:mitag1 />.

Una diferencia entre las etiquetas HTML y JSP, es que todas las etiquetas JSP deben seguir las reglas de las etiquetas XML. Esto quiere decir que todas las etiquetas deben tener tanto la etiqueta de apertura como la etiqueta de cierre:

<xgms:mitag1>   <!-- etiqueta de apertura -->
  ...
</xgms:mitag1>  <!-- etiqueta de cierre   -->

Un ejemplo de una etiqueta HTML sin etiqueta de cierre sería: <br>. Esto definitivamente no está permitido para las etiquetas JSP. Para el caso de que una etiqueta JSP no tuviera etiqueta de cierre, uno debe colocar el símbolo / antes del carácter >: <xgms:mitag1 />.

Se conoce como contenido del cuerpo de una etiqueta al código que está contenido entre las etiquetas de apertura y de cierre:

<xgms:mitag1>
  código        <!-- contenido del cuerpo (body) de la etiqueta -->
</xgms:mitag1>

Otra característica a notar, es que todas las etiquetas JSP llevan un prefijo, por ejemplo: xgms en la etiqueta: <xgms:mitag1 />.

Una característica más, es que todas las etiquetas JSP van siempre en minúsculas, por ejemplo: <xgms:mitag1 />.

Por último, al igual que las etiquetas HTML y XML, las etiquetas JSP también pueden manejar atributos, por ejemplo: <xgms:mitag1 atrib1="valor1" atrib2="valor2" />, tiene dos atributos.

Existen varias razones para usar etiquetas JSP:

2. Etiquetas Personalizadas

Además de las acciones estándard, la Especificación JSP incluye un API Java que puede ser utilizada para desarrollar acciones personalizadas con el fin de extender el lenguaje JSP.

Construir una etiqueta (o acción) JSP es tan sencillo como crear una clase Java normal. Lo único adicional que se requiere, es:

Posteriormente uno tiene que construir un archivo de texto sencillo para el Descriptor de la Biblioteca de Etiquetas (Tag Library Descriptor -TLD), en el cual se coloca la información de una o todas las etiquetas, y hacerlo disponible al servidor de aplicaciones.

La etiqueta que vamos a construir es una etiqueta sencilla llamada mitag1, la cual va a tener un solo atributo llamado nombre. El archivo clase se va a llamar p121_TagSimple.

2.a. Construcción Paso a Paso

Lo primero es definir el paquete al que va a pertencer nuestra clase p121_TagSimple:

package pkgs.pq03;

Lo siguiente es importar las clases requeridas:

import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

Al igual que en la construcción de un JavaBean, la implementación del interface Serializable es opcional. Este interface va a servir para que nuestra clase p121_TagSimple pueda ser salvada en disco o serializada sobre la red. Entonces, aunque la serialización no es un requerimiento en la construcción de etiquetas JSP, por conveniencia la vamos a implementar. Lo que sí es obligatorio implementar para un clase etiqueta JSP, es uno de los dos siguientes interfaces:

Estos interfaces se encuentran en el paquete javax.servlet.jsp.tagext. El interface Tag es un interface más sencillo, con unos seis métodos a implementar, mientras que el interface BodyTag extiende al interface Tag para agregar tres métodos más y muchas otras características (implementaremos este interface más adelante).

El paquete javax.servlet.jsp.tagext incluye dos clases que proveen una implementación por omisión para los interfaces mencionados anteriormente. Estas dos clases son:

Si se deseara, se podría extender una de estas clases y sobreescribir los métodos que se requirieran.

Dado que la etiqueta que estamos desarrollando es una etiqueta sencilla, por ahora implementaremos el interface Tag directamente, además de que esto ayudará en el aprendizaje de cómo se utilizan sus diferentes métodos.

Hacemos entonces la declaración de la clase p121_TagSimple con la implementación de los interfaces: Tag y Serializable:

public class p121_TagSimple implements Tag, Serializable {

Los seis métodos que proporciona el interface Tag y que tendremos que implementar (ya que son obligatorios), son:

  1. setPageContext( PageContext pc )
  2. setParent( Tag parent )
  3. getParent()
  4. doStartTag()
  5. doEndTag()
  6. release()

Si la etiqueta a ser creada tiene o maneja algún atributo (como en nuestro ejemplo), entonces también se tienen que agregar los métodos accesores (get y set) para ese atributo (tal como en el caso de las propiedades JavaBean):

  1. setNombre( String s )
  2. getNombre()

Nuestra clase p121_TagSimple, utilizará tres variables privadas. Dos para salvar referencias a objetos PageContext y Tag (que serán provistos por los métodos setPageContext() y setParent()), y la otra para el atributo "nombre" (que es de tipo String):

  private PageContext pc      = null;
  private Tag         parent  = null;
  private String      sNombre = null;

En el método setPageContext() se va a salvar (en una variable privada) la referencia al objeto PageContext:

public void setPageContext( PageContext p )
{
  pc = p;
}

En el método setParent() se va a salvar (en una variable privada) la referencia al objeto Tag padre:

public void setParent( Tag t )
{
  parent = t;
}

De igual forma se codifica el método getParent():

public Tag getParent()
{
  return parent;
}

Y se codifican los métodos accesores get y set para el atributo "nombre" que va a usar nuestra etiqueta:

public void setNombre( String s )
{
  sNombre = s;
}

public String getNombre()
{
  return sNombre;
}

El siguiente método a implementar, doStartTag(), será llamado al inicio de la etiqueta JSP. En este método usamos el objeto PageContext para regresar al usuario el valor del atributo "nombre". Si el usuario dejó vacío el atributo "nombre" de la etiqueta, entonces se desplegará un mensaje diferente.

Puesto que esta etiqueta no va a tener ningún contenido en su cuerpo, el método doStartTag() regresa SKIP_BODY (ésta, junto con otras variables estáticas, está provista por el interface Tag):

public int doStartTag() throws JspException
{
  try
  {
    if( sNombre == null )
    {
      pc.getOut().write( "Parámetro vacío!" );
    }
    else
    {
      pc.getOut().write( "Hola " + sNombre + "!" );
    }
  }
  catch( IOException e )
  {
    throw new JspTagException( "Excepción de IO." );
  }
  return SKIP_BODY;
}

El siguiente método a implementar, doEndTag(), será llamado al cierre de la etiqueta JSP. Este método regresa EVAL_PAGE para que el resto de la página sea leida por el servidor:

public int doEndTag() throws JspException
{
  return EVAL_PAGE;
}

Y por último implementamos el método release(). Este método será llamado por la página JSP cuando todos los métodos de la clase tag hayan sido llamados y sea momento de liberar recursos. En este método uno debe liberar los recursos que se hayan acumulado durante la ejecución de otros métodos de la clase:

public void release()
{
  pc      = null;
  parent  = null;
  sNombre = null;
}

Para este ejercicio vamos a crear un nuevo paquete. Bajo dir_code/src/pkgs creamos el directorio pq03:


  D:\Dev
     |
     +-- curso_jsp
         |
         +-- src
             |
             +-- pkgs
                 :
                 |
                 +-- pq03

El código completo es el siguiente:

package pkgs.pq03;

import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

public class p121_TagSimple implements Tag, Serializable
{
  private PageContext pc      = null;
  private Tag         parent  = null;
  private String      sNombre = null;

  public void setPageContext( PageContext p )
  {
    pc = p;
  }

  public void setParent( Tag t )
  {
    parent = t;
  }

  public Tag getParent()
  {
    return parent;
  }

  public void setNombre( String s )
  {
    sNombre = s;
  }

  public String getNombre()
  {
    return sNombre;
  }

  public int doStartTag() throws JspException
  {
    try
    {
      if( sNombre == null )
      {
        pc.getOut().write( "Parámetro vacío!" );
      }
      else
      {
        pc.getOut().write( "Hola " + sNombre + "!" );
      }
    }
    catch( IOException e )
    {
      throw new JspTagException( "Excepción de IO." );
    }
    return SKIP_BODY;
  }

  public int doEndTag() throws JspException
  {
    return EVAL_PAGE;
  }

  public void release()
  {
    pc      = null;
    parent  = null;
    sNombre = null;
  }
}

• Archivo: p121_TagSimple.java

Por ahora sólo salvamos el código (en dir_code/src/pkgs/pq03).

3. El Descriptor de la Biblioteca de Etiquetas

El Descriptor de la Biblioteca de Etiquetas (TLD) es un archivo XML sencillo que se utiliza para proveer los detalles necesarios sobre las etiquetas JSP personalizadas.

3.a. Construcción Paso a Paso

El TLD comienza con un encabezado.

Nota:  Todos los descriptores de la biblioteca de etiquetas correspondientes a la versión JSP 1.2, deben incluir un DOCTYPE de la siguiente forma:

<!DOCTYPE taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

Para la versión JSP 1.1 el DOCTYPE es como sigue:

<!DOCTYPE taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
  "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

Continuado por la etiqueta de apertura <taglib>, ya que todo el contenido debe estar entre las etiquetas <taglib> y </taglib>:

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

<taglib>

Las primeras cinco sub-etiquetas bajo la etiqueta <taglib> son etiquetas generales para proveer informacion sobre la biblioteca de etiquetas como un todo; no son específicas a ninguna etiqueta.

La etiqueta tlib-version informa sobre la versión actual de la biblioteca de etiquetas. Puesto que estamos comenzando con una nueva, empezamos con 1.0:

<tlib-version>1.0</tlib-version>

La etiqueta jsp-version le indica al servidor de aplicaciones qué versión de JSP utiliza está biblioteca.

Actualmente hay tres versiones del JSP: 1.0, 1.1 y la 1.2 (prácticamente ya está también la 2.0). Puesto que estamos usando la última versión, definimos la versión 1.2:

<jsp-version>1.2</jsp-version>

La etiqueta short-name define un nombre corto para la biblioteca:

<short-name>MisTags</short-name>

La etiqueta uri define un URI público que identifica de forma única esta versión del taglibrary. Se deja vacía si no aplica.

<uri></uri>

La etiqueta description define una breve descripción sobre el uso de esta biblioteca:

<description>Mi Biblioteca de Etiquetas</description>

Finalmente, vienen las descripciones de las etiquetas individuales (las que estamos construyendo) entre las etiquetas <tag> y </tag>, por lo que comenzamos con nuestra etiqueta de apertura:

<tag>

La etiqueta name indica el nombre con el que referenciaremos a la etiqueta en la página JSP. Este es el nombre que aparece inmediatamente después del prefijo, por ejemplo: mitag1 en la etiqueta <xgms:mitag1 />:

<name>mitag1</name>

La etiqueta tag-class define la subclase de javax.serlvet.jsp.tagext.Tag implementada, esto es, debe contener la ruta completa a la clase etiqueta JSP:

<tag-class>pkgs.pq03.p121_TagSimple</tag-class>

La etiqueta body-content provee una indicación en cuanto al contenido del cuerpo de la etiqueta. Debe contener alguno de los siguientes tres valores:

Puesto que el contenido del cuerpo en nuestra etiqueta está vacío, lo definimos como empty:

<body-content>empty</body-content>

La etiqueta description es opcional y sirve para dar una pequeña descripción sobre la etiqueta construida:

<description>Mi primer etiqueta JSP</description>

La etiqueta attribute describe de forma separada cada uno de los atributos (si es que existen) de la etiqueta construída.

El nombre de nuestro atributo es "nombre", y este valor va a ser opcional, por lo que lo definiremos como "false":

<attribute>
  <name>nombre</name>
  <required>false</required>
</attribute>

Terminamos con nuestra etiqueta de cierre:

</tag>

Y la etiqueta de cierre final:

</taglib>

Para guardar la etiqueta vamos a crear un nuevo directorio. Bajo dir_code/web/WEB-INF creamos el directorio tlds:


  D:\Dev
     |
     +-- curso_jsp
         |
         +-- web
             |
             +-- WEB-INF
                 |
                 +-- tlds

El código completo del TLD es el siguiente:

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name>MisTags</short-name>
  <uri></uri>
  <description>Mi Biblioteca de Etiquetas</description>

  <tag>
    <name>mitag1</name>
    <tag-class>pkgs.pq03.p121_TagSimple</tag-class>
    <body-content>empty</body-content>
    <description>Mi primer etiqueta JSP</description>

    <attribute>
      <name>nombre</name>
      <required>false</required>
    </attribute>
  </tag>
</taglib>

• Archivo: MisTags.tld

Lo salvamos en el directorio de TLD‘s (dir_code/web/WEB-INF/tlds).

En este punto tenemos ya los archivos p121_TagSimple.java y MisTags.tld, con lo que concluimos la construcción básica de etiquetas personalizadas.

Solo falta construir la página JSP (que va a utilizar la etiqueta generada), con lo que regresamos al ambiente familiar de páginas JSP.

4. La Página JSP

Finalmente vamos a utilizar la directiva que había quedado pendiente, la directiva taglib. Esta directiva le va a indicar al servidor de aplicaciones que vamos a utilizar una etiqueta JSP en nuestra página JSP. Como se vio anterioremente, esta directiva utiliza dos atributos: uri y prefix.

El atributo uri define la dirección local del archivo TLD (MisTags.tld), y el atributo prefix indica el prefijo a utilizar (xgms):

<%@ taglib uri="WEB-INF/tlds/MisTags.tld" prefix="xgms" %>

Para probar nuestra etiqueta personalizada, vamos a colocarla dos veces dentro de la página JSP, una dejando al atributo "nombre" sin valor, y la otra colocándole un valor:

<p>Atributo sin valor: <xgms:mitag1 /></p>

<p>Atributo con valor: <xgms:mitag1 nombre="Taggy" /></p>

El código completo de la página JSP es el siguiente:

<html>

<head>
<title>
Etiqueta Personalizada
</title>
</head>

<body bgcolor="#ffeada">

<%@ taglib uri="WEB-INF/tlds/MisTags.tld" prefix="xgms" %>

<p>
Atributo sin valor: <xgms:mitag1 />
</p>

<p>
Atributo con valor: <xgms:mitag1 nombre="Taggy" />
</p>

</body>
</html>

• Archivo: p122_TagSimple.jsp

Salvamos la página en dir_code/web, ejecutamos el Ant y la accesamos con el URL: http://localhost/curso/p122_TagSimple.jsp.

El orden en que una página JSP llama los métodos del interface Tag, es como sigue:

  1. setPageContext()
  2. setParent()
  3. setAttribute1( atrib_1 )
  4. setAttribute2( atrib_2 )
  5. doStartTag()
  6. doEndTag()
  7. release()

En resumen, un archivo TLD contiene las descripciones de una o más etiquetas junto con sus atributos.


Ayuda

Para más información sobre las Definiciones de Tipo de Documento: