Estructura de las Páginas JSP
- Etiquetas JavaBean

Las Etiquetas JavaBean, como se mencionó previamente, forman parte de las las Etiquetas Estándard, aunque por su funcionalidad suelen considerarse como si fueran un grupo aparte. Estas etiquetas fueron diseñadas para utilizar componentes JavaBean dentro de una página JSP.


1. ¿Qué es un JavaBean?

Un JavaBean (o Bean Java), se define como un componente de software reutilizable y que puede ser manipulado visualmente con alguna herramienta diseñada para ello.

Un JavaBean básicamente es una clase Java pero con algunas características adicionales. Existen tanto los beans visuales (que se utilizan primordialmente para fines de presentación -botones, controles, etc.), como los no-visuales (que se utilizan para facilitar la lógica de una aplicación).

Existen varias razones para utilizar beans en las páginas JSP:

Para que una herramienta de manejo de beans pueda saber sobre las propiedades de un bean dado, éste tiene que seguir un patrón de diseño predefinido. Puesto que los IDE's actuales incluyen la capacidad de manejar beans, haremos que los beans que diseñemos cumplan con este patrón de diseño, en lugar de simplemente instanciar al bean como cualquier otro objeto Java.

Como se mencionó previamente, un JavaBean es una clase Java que se conforma a ciertos criterios (o convenciones de codificación):

La arquitectura de los JavaBean utiliza la reflección (o introspección) para inferir los métodos públicos, aunque puede utilizarse una clase BeanInfo llamada BeanName BeanInfo para proveer información explícita.

Un bean también puede ser serializado y salvado para un uso posterior. Ésto lo hace por implementar el interface Serializable. Cuando un componente bean es serializado, éste guarda su estado actual (el estado actual de un bean está definido por los valores actuales de sus propiedades públicas).

Las propiedades siempre se inicializan y obtienen utilizando una nomeclatura predefinida. Para cada propiedad, dos métodos deben existir: Un método getXxx() y un método setXxx(), donde Xxx representa el nombre de la propiedad.

Aparte de lo anterior, un bean es igual que cualquier otra clase Java. Típicamente, un componente bean es importado al programa, sus propiedades son inicializadas y sus métodos son llamados.

2. El JavaBean

Cualquier herramienta de desarrollo (JBuilder, VisualAge) usa la clase del bean (el archivo .class, no el archivo fuente .java) para obtener toda la información (propiedades, métodos y eventos) acerca del bean y así poderla presentar al desarrollador.

Como se mencionó, este proceso lo realiza por medio de la introspección. Esto significa que el IDE puede saber todo lo que requiera sobre un bean, siempre y cuando el desarrollador se apegue a ciertas convenciones en la nomeclatura y codificación del bean.

Sin embargo, si uno no desea seguir o apegarse a esta convención, entonces uno debe implementar el interface BeanInfo. Esto significa escribir un programa Java adicional que el IDE puede utilizar para obtener la información que requiere para reconocer a un bean. Actualmente, muchos IDE's pueden generar automáticamente este interface BeanInfo.

El bean que vamos a construir, se llama p111_BeanSenc, contiene una variable privada (sNombre), una propiedad (nombre), dos métodos accesores y un método expuesto -además de que se va a apegar a las convenciones requeridas.

2.a. Construcción Paso a Paso

Un bean es una clase, tal como un applet o una aplicación, por ello, todas las reglas Java aplican para un bean.

Se requiere que un bean exista en un paquete (package):

package pkgs.pq02;

Después de la declaración del paquete, están las declaraciones import:

import java.io.Serializable;

El interface Serializable no contiene ningún método. El implementarlo simplemente le indica al compilador que pudiéramos serializar los objetos de esa clase.

Como lo requiere la especificación, un bean implementa este interface ya que el bean puede ser fácilmente transferido o salvado -incluso en disco:

public class p111_BeanSenc implements Serializable
{

El valor de una propiedad de un bean se almacena en una variable (o campo) privado dentro del bean. Puesto que esta variable es privada, por un lado ningún objeto externo puede tener un acceso directo a ella, y por otro, implica que puede tener el nombre que uno desee (ya que el nombre de la propiedad se deriva del nombre de los métodos accesores).

Lo siguiente entonces, es declarar un campo para guardar el valor que tenga la propiedad:

private String sNombre = null;

Un bean tiene un constructor vacío (queriendo decir que no acepta argumentos de entrada, no que el método no contenga código), el cual es declarado público. En este caso vamos a instanciar la variable por colocarle un valor por omisión:

public p111_BeanSenc()
{
  sNombre = "Beanny";
}

Todas las variables y métodos usados exclusivamente dentro de la clase, son privados, esto es, están protegidos de cualquier interferencia externa.

La mecánica para crear los métodos accesores es la siguiente:

Un método get siempre es público, y regresa el valor de una propiedad a una fuente externa:

public String getNombre()
{
  return sNombre;
}

Un método set siempre es público, y acepta de una fuente externa el valor que va a tomar la propiedad:

public void setNombre( String psNombre )
{
  this.sNombre = psNombre;
}

Opcionalmente, puede usarse el método is para obtener el valor de una propiedad booleana. Generalmente se usa en sentencias condicionales:

if( isDatosFin() )
{
  hacer algo;
}

Adicionalmente a los métodos get, set e is, cualquier método que requiera proveer propiedades a una fuenta externa, simplemente se declara como pública.

public String hacerFeliz()
{
  sNombre = "Felicidades " + sNombre;
  return sNombre;
}

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


  D:\Dev
     |
     +-- curso_jsp
         |
         +-- src
             |
             +-- pkgs
                 |
                 +-- pq01
                 |
                 +-- pq02

El código completo para el bean es el siguiente:

package pkgs.pq02;

import java.io.Serializable;

public class p111_BeanSenc implements Serializable
{
  private String sNombre = null;

  public p111_BeanSenc()
  {
    sNombre = "Beanny";
  }

  public String getNombre()
  {
    return sNombre;
  }

  public void setNombre( String psNombre )
  {
    this.sNombre = psNombre;
  }

  public String hacerFeliz()
  {
    sNombre = "Felicidades " + sNombre;
    return sNombre;
  }
}

• Archivo: p111_BeanSenc.java

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

En resumen los JavaBean son clases Java que se apegan a una convención de codificación muy sencilla:

Con esto se concluye este breve repaso sobre JavaBeans, y al mismo tiempo, el bean creado servirá como base para la explicación de los elementos action JavaBean.

3. Etiquetas JavaBean

Estas etiquetas fueron diseñadas para funcionar con componentes JavaBean en una página JSP, y su uso dentro de una JSP generalmente es para manejar la parte de la lógica de la aplicación. Así, típicamente los componentes JavaBean se utilizan como contenedores de información que describen entidades dentro de la aplicación (como puede ser un cliente o una orden de compra).

La especificación JSP define tres elementos action JavaBean:

Elemento Descripción
<jsp:useBean> Hace que un JavaBean esté disponible para la página.
<jsp:setProperty> Define el valor de una propiedad (property) de un JavaBean.
<jsp:getProperty> Obtiene el valor de una propiedad (property) de un JavaBean.

• Tabla: Elementos action JavaBean

A continuación se describen cada uno de estos tres elementos action JavaBean.

3.a. useBean

La acción useBean es el punto de entrada para usar un JavaBean, ya que esta etiqueta se utiliza para declarar e instanciar la clase JavaBean.

Sus funciones más importantes son las de proveer un indentificador (de tal forma que uno pueda hacer referencia al bean en la página), y un alcance (ver más adelante), de tal forma que uno pueda controlar el período de vida del bean.

La sintaxis de la acción useBean es como sigue:

<jsp:useBean
  id="identificador"
  scope="page | request | session | application"
  type="TipoDeObjeto"
  class="paquete.bean"
  beanName="NombreDelBean" />

El atributo id define el nombre por el cual se va a identificar el bean mientras exista.

El atributo scope define el alcance del bean (esto es, el tiempo que el objeto va a permanecer en memoria). Delimita tanto el lugar como el tiempo que una JSP tiene acceso al contenido del bean. Este atributo tiene cuatro posibles valores:

Valor Descripción
page El bean se liga al objeto page.
El bean existe durante la vida de la página. Un nuevo objeto se crea y destruye por cada página.
Éste es el valor por omisión.
request El bean se liga al objeto request.
La información interna del bean se guarda en el objeto ServletRequest y el bean sólo está disponible para la petición del cliente en curso.
session El bean se liga al objeto session.
De esta forma el bean está disponible para todas las páginas JSP durante toda la sesión (cada visitante de un sitio tiene definida una sesión para sí).
application El bean se liga al objeto application.
El bean permanece hasta que la aplicación se recargue, o que el servidor se reinicie.

• Tabla: Valores para el Atributo page

El atributo type define el tipo del objeto, el cual puede ser la misma clase, una super-clase o un interface implementado por la clase. Este parámetro es opcional.

En la siguiente línea, String es el tipo al que se refiere este atributo:

String sNombre = "Laura";

El atributo class provee los nombres tanto del paquete como de la clase. Instancia un bean de una clase, utilizando la palabra clave new y el constructor de la clase.

Por ejemplo:

<jsp:useBean id="miBean" scope="page" class="pkgs.pq02.p111_BeanSenc" />

El código anterior definiría la forma de acceder el bean creado en la sección anterior. Éste se va a identificar como miBean, tiene el mismo alcance que la página, la clase se llama p111_BeanSenc y está contenida en el paquete pkgs.pq02.

El atributo beanName también se refiere a la nombre completo de la clase, tal como en el atributo class.

3.b. setProperty

La acción setProperty se utiliza para definir y/o cambiar el valor de la propiedad de un bean.

La sintaxis de la acción setProperty puede ser cualquiera de las dos siguientes:

  1. <jsp:setProperty
      name="identificador"
      property="propiedad"
      value="valor" />
    
  2. <jsp:setProperty
      name="identificador"
      property="propiedad"
      param="parámetro" />
    

El atributo name se refiere al nombre por el cual se está identificando el bean.

El atributo property se refiere al nombre de la propiedad que se va a modificar.

La forma de la etiqueta setProperty a usar dependerá del origen de la información que se desea enviar a la propiedad del bean:

  1. La primer forma se utiliza para enviar un valor a la propiedad:
    <jsp:setProperty
      name="miBean"
      property="nombre"
      value="Beanny" />
    
  2. La segunda forma se utiliza para obtener el valor (a ser enviado) de la URL:
    <jsp:setProperty
      name="miBean"
      property="nombre"
      param="minombre" />
    

    Así, si la URL fuera:

    http://localhost/curso/p112_BeanSenc.jsp?minombre=Claudia,
    

    el argumento param="minombre" de la etiqueta setProperty indicaría al JSP que tiene que pasar la cadena "Claudia" (correspondiente al parámetro minombre) de la URL al método setNombre() del bean.

Aparte de tener dos sintaxis diferentes, esta etiqueta se puede utilizar en dos lugares diferentes:

  1. Entre las etiquetas <jsp:useBean> y </jsp:useBean>.

    De esta forma uno sabe que las propiedades del bean se inicializan junto con la instanciación del mismo. Para ello, uno simplemente escribe la etiqueta <jsp:useBean>, y después, tantas etiquetas <jsp:setProperty> como hagan falta, y finalmente se termina con la etiqueta </jsp:useBean>.

  2. Fuera de las etiquetas <jsp:useBean>.

    De esta forma uno puede cambiar la propiedad en cualquier momento y cuantas veces se requiera.

También es posible cambiar una propiedad haciendo referencia directamente al método set, por ejemplo:

<% miBean.setNombre( "Claudia" ); %>

Independientemente de cómo se cambie la propiedad, el bean tiene que haber sido referenciado previamente.

3.c. getProperty

La acción getProperty se utiliza para obtener el valor de la propiedad de un bean.

La sintaxis de la acción getProperty es como sigue:

<jsp:getProperty
  name="identificador"
  property="propiedad" />

El atributo name se refiere al nombre por el cual se está identificando el bean.

El atributo property se refiere al nombre de la propiedad de la que se va a obtener su valor.

Por ejemplo:

<jsp:getProperty name="miBean" property="nombre" />

Sin embargo, existen otras dos formas de obtener el valor de una propiedad:

  1. A través de los métodos accesores

    Por medio de esta forma:

    <%= miBean.getNombre() %>
    

    regresará una cadena conteniendo el valor de la propiedad nombre.

  2. A través de los métodos expuestos

    Por ejemplo:

    <%= miBean.hacerFeliz() %>
    

    regresará la propiedad después de haber terminado su proceso especial.

4. La Página JSP

El código de la página JSP que va a utilizar el bean construido, es el siguiente:

<html>

<head>
<title>
JavaBeans
</title>
</head>

<body bgcolor="#ffeada">

<div style="font-size:9.5pt;font-family:Courier New;"

<!-- El bean va a ser referido como "miBean" -->

<jsp:useBean id="miBean" scope="page" class="pkgs.pq02.p111_BeanSenc" />

1. Consultamos el valor por omisión de la propiedad: <br><br>

Nombre = <%= miBean.getNombre() %> <br>

Nombre = <jsp:getProperty name="miBean" property="nombre" /> <br>

Nombre = <%= miBean.hacerFeliz() %> <br><br>

2. Cambiamos la propiedad a: "Ana" usando setProperty(),

<jsp:setProperty name="miBean" property="nombre" value="Ana"/>

y consultamos su nuevo valor: <br><br>

Nombre = <%= miBean.getNombre() %> <br>

Nombre = <jsp:getProperty name="miBean" property="nombre" /> <br>

Nombre = <%= miBean.hacerFeliz() %> <br><br>

3. Cambiamos la propiedad a: "Claudia" usando setNombre(),

<% miBean.setNombre( "Claudia" ); %>

y consultamos su nuevo valor: <br><br>

Nombre = <%= miBean.getNombre() %> <br>

Nombre = <jsp:getProperty name="miBean" property="nombre" /> <br>

Nombre = <%= miBean.hacerFeliz() %> <br><br>

4. Cambiamos la propiedad a: "Erika" desde la URL: <br>
 http://localhost/curso/p112_BeanSenc.jsp?minombre=Erika <br>

<jsp:setProperty name="miBean" property="nombre" param="minombre" />

y consultamos su nuevo valor: <br><br>

Nombre = <%= miBean.getNombre() %> <br>

Nombre = <jsp:getProperty name="miBean" property="nombre" /> <br>

Nombre = <%= miBean.hacerFeliz() %> <br><br>
</div>

</body>
</html>

• Archivo: p112_BeanSenc.jsp

Salvamos la página en dir_code/web, ejecutamos el Ant y la accesamos:

  1. Primero con el URL http://localhost/curso/p112_BeanSenc.jsp,
  2. Y luego con el URL http://localhost/curso/p112_BeanSenc.jsp?minombre=Erika.

Con este ejercicio hemos aprendido a encontrar e instanciar un bean dentro de una JSP por medio de la etiqueta <jsp:useBean>, asignarle un valor a una propiedad de un bean por medio de la etiqueta <jsp:setProperty> con el atributo value, y obtener el valor de una propiedad de un bean por medio de la etiqueta <jsp:getProperty>.

5. Alcance de los Objetos

Los objetos en una página JSP, ya sean implícitos o explícitos, siempre están accesibles dentro de un alcance (scope) en particular. Por un lado, uno puede requerir que un objeto dado quede accesible a todos los objetos en una aplicación, o por otro, que su disponibilidad quede restringida a sólo ciertos objetos de la aplicación.

El concepto de alcance en una aplicación Web es diferente del utilizado en aplicaciones tradicionales independientes:

Un alcance se implementa como un objeto Java (en tiempo de ejecución -runtime).

La especificación JSP define cuatro diferentes alcances en los que se puede hacer referencia a un objeto. Los alcances definidos (desde el más limitado al más amplio), son los siguientes:

  1. page
  2. request
  3. session
  4. application

Éstos se describen a continuación.

5.a. page

El objeto request representa a la página JSP actual, es el alcance por omisión de cualquier objeto, y es del tipo javax.servlet.jsp.PageContext.

El objeto es accesible sólo dentro de la página JSP en que fue creado, esto es, este objeto está disponible solo para los elementos JSP en la página actual o en páginas incluidas con la directiva include (mas no para las páginas incluidas con la acción include).

Nota:  La directiva se ejecuta en la fase de traducción, por lo que las páginas incuidas se insertan en la misma clase que la página "padre".

Un objeto con alcance page se almacena en el objeto implícito pageContext. El alcance page termina cuando la página termina de ejecutarse.

Nota:  Si un usuario recarga la página mientras se está ejecutando, nuevas instancias serán creadas para todos los objetos con alcance page.

5.b. request

El objeto request representa a la petición HTTP actual, y es del tipo javax.servlet.ServletRequest

El objeto es accesible desde cualquier página JSP que esté atendiendo la petición HTTP atendida por la página JSP que creó el objeto, esto es, el objeto está disponible sólo para las páginas JSP y servlets ejecutándose en la petición HTTP actual.

Por ejemplo, si uno redirecciona el proceso hacia otra página (con la acción forward), entonces ambas páginas accesan el mismo objeto ServletRequest.

Un objeto con alcance request se almacena en el objeto implícito request. El alcance request termina al concluir la petición HTTP.

5.c. session

El objeto session representa la sesión HTTP del usuario actual.

El objeto es accesible desde cualquier página JSP que esté compariendo la misma sesión HTTP que la de la página que creó el objeto, esto es, el objeto está disponible sólo para las páginas JSP y servlets ejecutando peticiones asociadas con la sesión HTTP del usuario actual.

Un objeto con alcance session se almacena en el objeto implícito session. El alcance session termina cuando se agota el tiempo (times out) de la sesión HTTP, o cuando ésta se invalida.

5.d. application

El objeto application representa el runtime del módulo web, y es del tipo javax.servlet.ServletContext.

El objeto es accesible desde cualquier página que sea utilizada en la misma aplicación Web que la página JSP que creó el objeto, en una sola Máquina Virtual Java (JVM), esto es, el objeto está disponible para todas las páginas JSP y servlets en el módulo Web (el concepto, de hecho, es similar al de una variable Java estática).

Un objeto con alcance application se almacena en el objeto implícito application (del contexto servlet). El alcance application termina cuando la aplicación misma termina, o cuando ya sea, el contenedor JSP o el contenedor servlet se apagan.

Nota:  Los alcances request, session, y application, también aplican para los servlets.

En resumen, el alcance de un objeto permite que uno controle la disponibilidad de ese objeto. Otros objetos pueden hacer referencia al objeto según su alcance. Al colocar un objeto en un alcance dado, éste queda disponible a todos los niveles superiores del alcance elegido. Por ejemplo, los objetos con alcance page están disponibles a los objetos con alcance request, session y application.

En el caso de los objetos explícitos (tales como la instancia de un JavaBean creado en una acción jsp:usebean), uno puede explícitamente definir el alcance con la siguiente sintaxis:

scope="TipoDeAlcance"

Por ejemplo:

<jsp:useBean ... scope="session" ...>

Los alcances y los objetos que representan están implícitamente disponibles para los elementos script de una página. Estos objetos (alcances) utilizan las variables de script que una página instancia automáticamene. Por omisión, las páginas JSP tienen acceso al alcance session. Sin embargo, si una página no está participando de una sesión, entonces no puede utilizar el alcance session. Más aún, no puede referenciar la variable implícita session. Cuando una página no está participando en una sesión, el atributo sessión de la directiva page se define en false. No siempre ni todas las partes de una aplicación requieren datos de la sesión. El considerar esto permite evitar la sobrecarga de crear una sesión de usuario.

Uno puede definir y utilizar objetos delimitados (en su alcance) ya sea desde servlets, manejadores de etiquetas y scriplets. Para definir objetos en alcances, se usa el método addAttribute en el objeto delimitado relevante. Para obtener objetos en alcances, se usa el método getAttribute en el objeto delimitado relevante.