Zona HTML Zona Java Zona PHP Zona ASP Zona Bases de datos
Inicio > Tutoriales > Lenguajes orientados a objeto > Java > J2EE > JSTL 1.0. Estandarizando JSP.
-Tutoriales

JSTL 1.0. Estandarizando JSP.


Introducción a JSTL

JSTL responde a la demanda de los desarrolladores de un conjunto de acciones JSP personalizadas para manejar las tareas que necesitan casi todas las páginas JSP, incluyendo procesamiento condicional, internacionalización, acceso a bases de datos y procesamiento XML. Esto acelarará el desarrollo de JSPs más o menos eliminando la necesidad de elementos de scripting y los inevitables y difíciles de encontrar errores de sintaxis, y liberando el tiempo anteriormente gastado en desarrollar y aprender trillones de acciones personalizadas específicas del proyecto para estas tareas comunes.

Este tutorial nos enseña cómo JSTL puede simplificar nuestra vida cuando usamos JSP, en grandes y pequeñas aplicaciones. En este tutorial se ofrecerá una introducción a JSTL y mostrará como usar las acctiones JSTL más comunes.

. Introducción a las Librerías JSTL

JSTL 1.0 especifica un conjunto de librerías de etiquetas basadas en el API JSP 1.2. Hay cuatro librerías de etiquetas independientes, cada una contiene acciones personalizadas dirigidas a un área funcional específica. Esta tabla lista cada librería con su prefijo de etiqueta recomendado y la URI por defecto:

Descripción Prefijo URI por Defecto
Core c http://java.sun.com/jstl/core
XML Processing x http://java.sun.com/jstl/xml
I18N & Formatting fmt http://java.sun.com/jstl/fmt
Database Access sql http://java.sun.com/jstl/sql

La Librería Core contiene acciones para las tareas rutinarias, como incluir o excluir una parte de una página dependiendo de una condición en tiempo de ejecución, hacer un bucle sobre una colección de ítems, manipular URLs para seguimiento de sesión, y la correcta interpretación del recurso objetivo, así como acciones para importar contenido de otros recursos y redireccionar la respuesta a una URL diferente.

La Librería XML contiene acciones -- como puedes imaginar -- para procesamiento XML, incluído validar un documento XML y transformarlo usando XSLT. También proporciona acciones para extraer parte de un documento XML validado, hacer bucles sobre un conjunto de nodos, y procesamiendo condicional basado en valores de nodos.

La Internationalización (i18n) y el formateo general están soportados por las acciones de la Librería I18N & Formatting. Podemos leer y modificar información almacenada en una base de datos con las acciones proporcionadas por la Librería Database Access.

Más adelante, podemos esperar que todos los contenedores Web incluyan una implementación de las librerías JSTL, así no tendremos que instalar ningún código adicional. Hasta que esto suceda, podemos descargar e instalar la implementación de referencia (RI) de JSTL. Se ha desarrollado dentro del proyecto Apache Taglibs como una librería llamada Standard. Puedes bajarla desde aquí:The JSTL RI: the Standard Library at Apache Taglibs.

Instalar RI es fácil, sólo hay que copiar los ficheros JAR del directorio lib de la distribución al directorio WEB-INF/lib de nuestra aplicación. Observa que JSTL 1.0 requiere un contenedor JSP 1.2, debemos asegurarnos de tener un contenedor compatible con JSP 1.2 antes de probar esto.

Para usar una librería JSTL, tanto si la implementación está incluida con el contenedor o con el RI, debemos declarar la librería usando una directiva taglib, como lo haríamos con una librería de etiquetas personalizadas normal:

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

Observa que siempre deberíamos usar la URI por defecto, incluso aunque la especificación JSP nos permita sobreescribirla. Un contenedor puede generar código optimizado para la acción JSTL en la clase correspondiente a una página JSP. Esto puede resultar en un mejor rendimiento que cuando el código generado llama a los manejadores de etiquetas a través del API estándar. Sin embargo, sólo cuando se usa la URI por defecto, es cuando el contenedor puede utilizar una implementación optimizada.

. El Lenguaje de Expresión JSTL

Además de las librerías de etiquetas, JSTL 1.0 define un llamado Lenguaje de Expresiones (EL). EL es un luenguaje para acceder a datos de varias fuentes en tiempo de ejecución. Su sintaxis es considerablemente más amigable que la de Java, que es el único lenguaje soportado directamente por la especificación JSP 1.2. Todas las acciones JSTL reconocen expresiones EL en sus valores de atributos, y se podrían desarrollar acciones personalizadas para que hicieran lo mismo. Se espera que EL sea incorporado dentro de la próxima versión de la especificación JSP para mejorar su uso para acceder a datos sobre el lenguaje Java. Si es así, podremos usar expresiones EL en un valor de atributo de una acción, o incluso en una plantilla de texto.

Si has usado JavaScript deberías sentirte como en casa con EL. EL toma prestada de JavaScript la sintaxis para acceder a estructuras de datos tanto como propiedades de un objeto (con el operador .) como con elementos con nombres de un array (con el operador ["nombre"]). Las propiedades de los componentes JavaBeans y las entradas java.util.Map, que usan la clave como nombre de propiedad, pueden ser accedidas de esta forma. Aquí tenemos algunos ejemplos:


${myObj.myProperty}$
${myObj["myProperty"]}$
${myObj[varWithTheName]}$

Como se ve aquí, una expreión EL siempre debe estar encerrada entre los caracteres ${ y }$. Las dos primera expresiones acceden a una propiedad llamada myProperty en un objeto representado por una variable llamada myObj. La tercera expresión acceder a una propiedad con un nombre contenido en un variable, esta sintaxis se puede utilizar con cualquier expresión que evalúe el nombre de la propiedad.

El operador de acceso a array también se usa para datos representados como una colección de elementos indexados, como un array Java o una java.util.List:


${myList[2]}$
${myList[aVar + 1]}$

Además de los operadores de propiedad y elemento array y los operadores aritméticos, relacionales, y lógicos, hay un operador especial para comprobar si un objeto está "vacío" o no puede ser usado en una expresión EL. La siguiente tabla lista todos los operadores:

OperadorDescription
.Accede a una propiedad
[]Accede a un elemento de un array/lista
()Agrupa una subexpression
+Suma
-Resta o negación de un número
/ o divDivisión
% o modMódulo (resto)
== o eqComprueba Igualdad
!= o neComprueba desigualdad
< o ltComprueba menor que
> o gtComprueba mayor que
<= o leComprueba menor o igual que
>= o gtComprueba mayor o igual que
&& o andComrpueba AND lógico
|| o orComprueba OR lógico
! o notComplemento binario booleano
emptyComprueba un valor vacío (null, string vacío, o una collección vacía)

Lo que no encontraremos en EL son sentencias como asignaciones, if/else, o while. Para este tipo de funcionalidades en JSP se usan los elementos Action, y EL no está pensado para utilizarse como un lenguaje de programación de propósito generar, sólo un lenguaje de acceso a datos.

Por supuesto, los literales y las variables, también son parte del lenguaje. EL proporciona los siguientes literales, similares a los que proporcionan JavaScript, Java, y otros lenguajes similares:

Tipo de Literal Descripción
String Encerrado con comillas simples o dobles. Una comilla del mismo tipo dentro del string puede ser escapada con una barra invertida: (\' en un string encerrado con comillas simples; \" en un string encerrado con comillas dobles). El caracter de barra invertida debe se escapado como \\ en ambos casos.
Integer Un signo opcional (+ o -) seguido por digitos entre 0 y 9.
Coma Floating Lo mismo que un literal entero, excepto que usa un punto como separador de la parte fraccional y que se puede especificar un exponente con e o E, seguido por un literal entero.
Boolean true o false.
Null null.

Cualquier objeto en uno de los ámbitos de JSP (página, solicitud, sesión o aplicación) se puede utilizar como una variable en una expresión EL. Por ejemplo, si tenemos un bean con una propiedad firstName en el ámbito de la solicitud bajo el nombre customer, esta expresión EL representa el valor de la propiedad firstName del bean.

${customer.firstName}

Pero no se para aquí. EL también hace que la información de la solicitud y la información general del contenedor esté disponible como un conjunto de variables implícitas:

Variable Descripción
param Una collection de todos de los parámetros de la solicitud como un sólo valor string para cada parámetro.
paramValues Una collection de todos los valores de los parámetros de la solicitud como un array de valores string por cada parámetro.
header Una collection de todas las cabeceras de solicitud como un sólo valor string por cada cabecera.
headerValues Una collection de todos los valores de cabecera de la solicitud como un array de valores string por cada cabecera.
cookie Una collection con todas las cookies de la solicitud en un sólo ejemplar de javax.servlet.http.Cookie por cada cokkie.
initParams Una collection de todos los parámetros de inicialización de la aplicación en un sólo valor string por cada parámetro.
pageContext Un ejemplar de la clase javax.servlet.jspPageContext.
pageScope Una collection de todos los objetos en el ámbito de la página.
requestScope Una collection de todos los objetos en el ámbito de la solicitud.
sessionScope Una collection de todos los objetos en el ámbito de la sesión.
applicationScope Una collection de todos los objetos en el ámbito de la aplicación.

Las cinco primeras variables implícitas de la tabla nos ofrecen acceso a los valores de parámetros, cabeceras y cookies de la solicitud actual. Aquí hay un ejemplo de cómo acceder a un parámetro de solicitud llamado listType y a la cabecera User-Agent:


${param.listType}
${header['User-Agent']}

Observa como debemos usar la sintaxis de array para la cabecera, porque el nombre incluye un guión; con la sintaxis de propiedad, sería interpretado como la expresión vairable header.User menos el valor de una variable llamada Agent.

La variable initParameter proporciona acceso a los parámetros de inicialización que se definen en el fichero web.xml de la aplicación. La variable pageContext tiene varias propiedades que proporcionan acceso al objeto servlet que representa la solicitud, la respuesta, la sesión y la aplicación, etc.

Las cuatro últimas variables son colecciones que contienen todos los objetos de cada ámbito específico. Podemos usarlas para limitar la búsqueda de un objeto en sólo un ámbito en lugar de buscar en todos ellos, lo que está por defecto si no se especifica ningún ámbito. En otras palabras, si hay un objeto llamado customer en el ámbito de sesión, estas dos primeras expresiones encuentran el mismo objeto, pero la tercera vuelve vacía:


${customer}
${sessionScope.customer}
${requestScope.customer}

Todas las acciones JSTL aceptan expresiones EL como valores de atributo, para todos los atributos excepto para var y scope, porque estos valores de atributo podrían usarse para chequear el tipo en el momento de la traducción en una futura versión. Hay un atributo de una acción JSTL adicional que no toma un valor de expresión EL, pero sólo se usa en la librería XML, por eso lo ignoraremos por ahora. Se pueden usan una o más expresiones EL en el mismo valor de atributo, y el texto fijo y las expresiones EL se pueden mezclar en el mismo valor de atributo:


First name: &lt;c:out value="${customer.firstName}" /&gt;
&lt;c:out value="First name: ${customer.firstName}" /&gt;

Antes de saltar a ver ejemplos de utilización de las acciones Core, dejáme cualificar algo que dijimos anteriormente: todas las acciones JSTL de la librería EL aceptan expresiones EL. Realmente hay un conjunto parelelo de librerías JSTL, llamado conjunto de librería RT. que sólo acepta expresiones Java del viejo estilo:

First name: <c_rt:out value="<%= customer.getFirstName() %>" /> 

. Procesamiento Condicional y Bucles

Veamos algunos ejemplos de cómo podemos usar el JSTL condicional y las acciones de iteracción: <c:if>; <c:choose>, <c:when>, y un triple <c:otherwise>; y <c:forEach>. Por el camino, también usaremos acciones de salida básica y de selección de variables: <c:out> y <c:set>.

<c:if> nos permite incluir, o procesar, condicionalmente una parte de una página, dependiendo de la información durante la ejecución. Este ejemplo incluye un saludo personal si el usuario es un visitante repetitivo, según lo indica la presencia de una cokkie con el nombre del usuario:

<c:if test="${!empty cookie.userName}">
    Welcome back <c:out value="${cookie.userName.value}" />
</c:if> 

El valor del atributo test es una expresión EL que chequea si la cookie existe. El operador empty combinado con el operador "not" (!) significa que evalúa a true si el cookie no existe, haciendo que el cuerpo del elemento sea procesado. Dentro del cuerpo, la acción <c:out> añade el valor de la cookie a la respuesta. Así de sencillo.

Pasar a través de una colección de datos es casi tan sencillo. Este fragmento itera sobre una colección de filas de una base de datos con información del tiempo de diferentes ciudades:

<c:forEach items="${forecasts.rows}" var="${city}">
   City: <c:out value="${city.name}" />
   Tomorrow's high: <c:out value="${city.high}" />
   Tomorrow's low: <c:out value="${city.low}" />
</c:forEach>

La expresión EL para el valor items obtiene el valor de la propiedad rows desde un objeto representado por la variable forecasts. Como aprenderemos más adelante, la acciones de bases de datos de JSTL representan un resultado de consulta como un ejemplar de una clase llamada javax.servlet.jsp.jstl.sql.Result. Esta clase se puede utilizar como un bean con varias propiedades. La propiedad rows contiene un array de ejemplares java.util.SortedMap, donde cada uno representa una fila con valores de columnas. La acción <c:forEach> procesa su cuerpo una vez por cada elemento de la colección especificado por el atributo items. Además de con arrays, la acción funciona con cualquier otro tipo de dato que represente una colección, como ejemplares de las clases java.util.Collection o java.util.Map.

Si se especifica el atributo var, el elemento actual de la colección se hace disponible para las acciones del cuerpo como una variable con el nombre especificado. Aquí se llamaba city y, como la colección es un array de maps, esta variable contiene un nuevo map con valores de columnas cada vez que se procesa el cuerpo. Los valores de las columnas se añaden a la respuesta por el mismo tipo de acciones <c:out> que hemos visto en ejemplos anteriores.

Para ilustrar el uso del resto de las acciones condicionales, extendamos el ejemplo de iteracción para procesar sólo un conjunto fijo de filas por cada página solicitada, añadamos enlaces "Previous" y "Next" a la misma página. El usuario puede entonces pasar sobre los resultados de la base de datos, mirando unas pocas fila cada vez, asumiendo que el objeto Result se ha grabado en el ámbito de la sesión. Aquí está cómo procesar sólo algunas filas:

<c:set var="noOfRows" value="10" />

<c:forEach items="${forecasts.rows}" var="${city}"
    begin="${param.first}" end="${param.first + noOfRows - 1}">
    City: <c:out value="${city.name}" />
    Tomorrow's high: <c:out value="${city.high}" />
    Tomorrow's low: <c:out value="${city.low}" />
 </c:forEach>

La acción <c:set> selecciona una variable con el valor especificado por el atributo value; que puede ser un valor estático, como en este ejemplo, o una expresión EL. También podemos especificar el ámbito de la variable con el atributo scope (page, request, session o application). En este ejemplo, hemos seleccionado una variable llamada noOfRows a 10 en el ámbito de la página (por defecto). Este es el número de filas que mostraremos en cada solicitud.

El <c:forEach> en este ejemplo toma los mismos valores para los atributos items y var como antes, pero hemos añadido dos nuevos atributos:

  • El atributo begin toma el índice (base 0) del primer elemento de la colección a procesar. Aquí se selecciona al valor de un parámetro de solicitud llamado first. Para la primera solicitud, este parámetro no está disponible, por eso la expresión se evalúa a 0; en otras palabtas, la primea fila.
  • El atributo end especifica el índice del último elemento de la colección a procesar. Aquí lo hemos seleccionado al valor del parámetro first más noOfRows menos uno. Para la primera solicitud, cuando no existe el parámetro de la solicitud, este resultado es 9, por eso la acción itera sobre los índices del 0 al 9.

Luego añadimos los enlaces "Previous" y "Next":

<c:choose>
  <c:when test="${param.first > 0}">
     <a href="foreach.jsp?first=<c:out value="${param.first - noOfRows}"/>">
                Previous Page</a>
  </c:when>
  <c:otherwise>
     Previous Page
  </c:otherwise>
</c:choose>
<c:choose>
  <c:when test="${param.first + noOfRows < forecasts.rowsCount}">
     <a href="foreach.jsp?first=<c:out value="${param.first + noOfRows}"/>">
                Next Page</a>
  </c:when>
  <c:otherwise>
     Next Page
  </c:otherwise>
</c:choose>

El <c:choose> agrupa una o más acciones <c:when>, cada una especificando una condición booleana diferente. La acción <c:choose> chequea cada condición en orden y sólo permite la primera acción <c:choose> con una condición que se evalúe a true para procesar su cuerpo. El cuerpo <c:choose> también podría contener un <c:otherwise>. Su cuerpo sólo se procesa si ninguna de las condiciones de los <c:when> es true.

En este ejemplo, la primera acción <c:when> comprueba si el parámetro first es mayor que cero, es decir, si la página muestra un subconjunto de filas distinto del primero. Si esto es cierto, el cuerpo de la acción <c:when> añade un enlace a la misma página con un parámetro first seleccionado al índice del subconjunto anterior. Si no es true, se procesa el cuerpo de la acción <c:otherwise>, añadiendo sólo el texto "Previous Page". El segundo bloque <c:choose> proporciona lógica similar para añadir el enlace "Next Page".

. Procesar URLs

Los ejemplos anteriores funcionan bien mientras se utilicen las cookies para seguimiento de sesión. No está todo dado; el navegador podría tener desactivadas las cookies, o no soportarlas. Por lo tanto es una buena idea activar el contenedor para usar la reescritura de URL como backup de los cookies. La reescritura de URL, como podrías conocer, significa poner el ID de la sesión en todas las URLs usadas en los enlaces y formularios de la página. Una URL reescrita se parece a algo como esto:

myPage.jsp;jspsessionid=ah3bf5e317xmw5

Cuando el usuario pulsa en una línea como esta, el identificador de sesión ID se envía al contenedor como parte de la URL. La librería corazón de JSTL incluye la acción <c:url>, que tiene cuidado de la reescritura de URL por nosotros. Aquí está como podemos usarla para mejorar la generación del enlace "Previous Page" del ejemplo anterior:

<c:url var="previous" value="foreach.jsp">
  <c:param name="first" value="${param.first - noOfRows}" />
</c:url>
<a href="<c:out value="${previous}"/>">Previous Page</a>

<c:url> soporta un atributo var, usado para especificar una variable para contener la URL codificada, y un atributo value para contener la URL a codificar. Se pueden especificar parámetros string para solicitar la URL usando acciones <c:param>. Los caracteres especiales en los parámetros especificados por elementos anidados son codificados (si es necesario) y luego añadidos a la URL como parámetros string de la consulta. El resultado final se pasa a través del proceso de reescritura de URL, añadiendo un ID de sesión si está desactivado el seguimiento de sesión usando cookies. En este ejemplo, se utiliza la URL codificada como un valor de atributo href en un elemento de enlace HTML.

<c:url> también realiza otro buen servicio. Como podría preocuparte, las URLs relativas en elementos HTML también deben ser relativas a la página que los contiene o al directorio raíz del servidor (si empiezan con una barra inclinada). La primera parte del path de una URL de una página JSP se llama path de contexto, y podría variar de instalación a instalación. Por lo tanto deberíamos evitar codificar el path de contexto en las páginas JSP. Pero algunas veces realmente querremos utilizar un path de URL relativo al servidor en elemento HTML; por ejemplo cuando necesitamos referirnos a un fichero de imagen localizado en el directorio /images compartido por todas las páginas JSP. Las buenas noticias es que si especificamos una URL con un barra inclinada como el valor <c:url>, lo convierte en un path relativo al servidor. Por ejemplo, en una aplicación con el path de contexto /myApp, la acción <c:url> convierte el path a /myApp/images/logo.gif:

<c:url value="/images/logo.gif" />

Hay unas cuantas acciones más relacionadas con las URLs en la librería corazón. La acción <c:import> es una acción más flexible que la acción estándar <jsp:include>. Podemos usarla para incluir contenido desde los recursos dentro de la misma aplicación Web, desde otras aplicaciones Web en el mismo contenedor, o desde otros servidores, usando protocolos como HTTP y FTP. La accion <c:redirect> nos permite redirigir a otro recurso en la misma aplicación Web, en otra aplicación Web o en un servidor diferente. Ambas acciones son fáciles de usar, por eso te dejamos como ejercicio que las práctiques.

 
Patrocinados
 

Copyright © 1999-2006 Programación en castellano. Todos los derechos reservados.
Formulario de Contacto - Datos legales - Publicidad

Hospedaje web y servidores dedicados linux por Ferca Network