Sie sind auf Seite 1von 42

Programación en Java

Parte 5: Java Server Pages


Objetivo General
Exponer la tecnología que ofrece Sun Microsystem para desarrollar
aplicaciones para Internet, con acceso a datos incluido.

Introducción
Los servlets y Java Server Pages (JSPs) son dos métodos de creación de páginas Web
dinámicas en servidor usando el lenguaje Java. En ese sentido son similares a otros métodos o
lenguajes tales como el PHP, los CGIs (Common Gateway Interface), programas que generan
páginas Web en el servidor, o los ASP (Active Server Pages), un método específico de Microsoft.
Sin embargo, se diferencian de ellos en que los JSPs y servlets se ejecutan en una máquina virtual
Java, lo cual permite que, en principio, se puedan usar en cualquier tipo de ordenador, siempre que
exista una máquina virtual Java para él. Cada servlet (o JSP, se pueden usar de forma indistinta)
se ejecuta en su propia hebra, es decir, en su propio contexto; pero no se comienza a ejecutar
cada vez que recibe una petición, sino que persiste de una petición a la siguiente, de forma que no
se pierde tiempo en invocarlo (cargar programa + intérprete). Su persistencia le permite también
hacer una serie de cosas de forma más eficiente: conexión a bases de datos y manejo de
sesiones, por ejemplo.

TEMA 1 Servidores y contenedores de servlets/JSPs


Los JSPs son en realidad servlets: un JSP se compila a un programa en Java la primera vez que
se invoca, y del programa en Java se crea una clase que se empieza a ejecutar en el servidor
como un servlet. La principal diferencia entre los servlets y los JSPs es el enfoque de la
programación: un JSP es una página Web con etiquetas especiales y código Java incrustado,
mientras que un servlet es un programa que recibe peticiones y genera a partir de ellas una página
Web.

Ambos necesitan un programa que los contenga, y sea el que envíe efectivamente páginas Web al
servidor, y reciba las peticiones, las distribuya entre los servlets, y lleve a cabo todas las tareas de
gestión propias de un servidor Web. Mientras que servidores como el Apache están especialmente
pensados para páginas Web estáticas CGIs, y programas ejecutados por el servidor, tales como el
PHP, hay otros servidores específicos para servlets y JSPs llamados contenedores de servlets
(servlet containers) o servlet engines. Los principales son los siguientes:

• Resin, de Caucho Technologies, un motor especialmente enfocado al servicio de páginas


XML, con una licencia libre para desarrolladores. Dice ser bastante rápido. Incluye soporte
para Javascript además de Java. Incluye también un lenguaje de templates llamado XTP.
Es bastante fácil de instalar, y en dos minutos, se pueden empezar a servir páginas JSP.
• BEA Weblogic es un servidor de aplicaciones de alto nivel, y también de alto precio. Está
escrito íntegramente en Java, y se combina con otra serie de productos, tales como
Tuxedo, un servidor de bases de datos para XML.
• JRun, de Macromedia, un servidor de aplicaciones de Java, de precio medio y
probablemente prestaciones medias. Se puede bajar una versión de evaluación gratuita
• Lutris Enhydra, otro servidor gratuito y Open Source, aunque tiene una versión de pago.
También enfocado a servir XML, y para plataformas móviles. Las versiones más
actualizadas son de pago, como es natural
• El más popular, Open Source, y continuamente en desarrollo, es el Jakarta Tomcat, del
consorcio Apache, un contenedor de servlets con muchos desarrollos adicionales
alrededor; por ejemplo, Cocoon para servir páginas XML. Puede servir páginas sólo o bien
como un añadido al servidor Apache. Es Open Source, relativamente rápido, y fácil de
instalar.

Otros muchos se pueden encontrar en la página de Sun


sobre la industria del servlet/JSP y en la página de Contenido de esta sección
contenedores de servlets en servlets.com • Prerrequisitos
para instalar un
Instalando un contenedor de servlets
servidor
• Instalando un
contenedor de
2 •
servlets
Ejecutando los
Vamos a ver cómo se instala un
primeros JSPs
contenedor de servlets. Nos
• Hosting de
fijaremos especialmente en la
versión 4.0 de Tomcat, aunque lo servlets, de
que se cuente valdrá para casi pago y gratuito
todos los otros contenedores Open Source. Los de pago,
probablemente tendrán un interfaz pijo para instalarlos, a base de
botoncitos, o si son los muy caros, vendrá un señor con corbata y
maletín de cuero para hacerlo, así que de esos no nos
preocuparemos demasiado.
Antes siquiera de bajarse el programa en cuestión, hay que
considerar previamente de la máquina virtual Java que vamos a usar
para ejecutarlo. Todos están escritos en Java, así que esto es
esencial. Principalmente, hay dos opciones: las JVM de Sun (que son
las originales) o las de IBM, que son algo más rápidas, pero que no
siempre están actualizadas hasta la última versión. Un contenedor de
servlets necesita el JDK completo, no sólo el runtime environmnt,
principalmente por el compilador de java contenido en un fichero
llamado tools.jar. En cualquier caso, nos podemos bajar la JVM de Sun
en sus versiones para Linux, o para cualquier otra plataforma (en la
versión 1.4), o bien la versión 1.3 de IBM (la más aconsejable). Si no
se consigue una versión de esas, es aconsejable conseguir una que
sea compatible con la versión "2" de Java, es decir, JVMs a partir de
la versión 1.2. Puede que funcionen con versiones anteriores, pero lo
más probable es que no lo hagan.
Igual está ya Java instalado en el sistema; habrá que verificar que java
y tools.jar están también instalados; basta con intentar ejecutarlo, o
bien preguntarle al administrador del sistema, que también es una
criaturita del señó y tiene derecho a que alguien le dirija la palabra,
caray.
Una vez instalada la JVM, nos bajamos el servidor de su sitio
correspondiente ( http://jakarta.apache.org/builds/jakarta-tomcat-
4.0/release/), si puede ser, en versión binaria, ya compilada. Si
disponemos de una distro de Linux que use el RPM para instalación
de paquetes (como Mandrake, RedHat o SuSE), se puede uno bajar
los RPMs e instalarlos directamente. Dependiendo de lo que elijamos,
habrá que bajarse sólo un paquete, o bien varios. En todo caso, habrá
que incluir lo siguiente: Xerces-J, regexp, servletapi, tomcat y tomcat-
Webapps. Si bajamos el fichero .tar.gz, viene todo incluido. Para
instalar el RPM se hace lo siguiente:
[yo@mimaquina]$ rpm -Uvh tomcat4-4.0.2-3.noarch.rpm
(esto después de haber instalado todos los paquetes previos. Si se ha
bajado el tar:
[yo@mimaquina]$ tar xvfz tomcat4-4.0.2.tar.gz
Ya desempaquetado, tendremos el Tomcat listo para funcionar.
Dependiendo de la manera de descargargarlo, tendremos el servidor
en un directorio u otro, pero siempre habrá directorios conf, lib, bin y
Webapps. A continuación, habrá que decirle dónde se encuentra la
máquina virtual Java, editando un fichero tomcat.conf que se encuentra
dentro del directorio conf (que variará de sitio según la distribución;
puede ser en /etc/tomcat4/conf o en directorio_del_tomcat/conf). En otros
sistemas operativos, o con otro tipo de instalación, habrá que definir
una variable de entorno, de esta forma:
[yo@mimaquina]$ export JAVA_HOME=/opt/IBMJava2-13
o bien
[yo@mimaquina]$ setenv JAVA_HOME /opt/IBMJava2-13
, dependiendo de si se trata del intérprete de comandos bash (el
primero) o *csh (el segundo). En WinXX habrá que dar una orden
similar. Finalmente para ejecutar el servidor, fijándonos en el caso de
haberlo instalado usando el RPM, hacemos:
[yo@mimaquina yo]$ /etc/rc.d/init.d/tomcat4 start
En otros casos, habrá que ir al directorio bin de la distribución y
ejecutar ./startup.sh o startup si se trata de Windows. Si todo falla,
siempre se puede mirar el manual. Por defecto, el servidor viene
configurado para lanzarse en el puerto 8080 u 8180 (dependiendo de
las versiones). Si todo ha ido bien, tendremos funcionando en nuestro
ordenador al Tomcat, y al introducir una dirección tal como
http://localhost:8080 o http://localhost:8180 (si quieres usar direcciones por
debajo de 1000 tendrás que ser superusuario).
Si no te sale lo anterior, puede ser por miles de razones diferentes. La
primera es comprobar que efectivamente el servidor está
funcionando. El principal problema de Tomcat es que falla
silenciosamente: ejecuta cosas, y parece que ha arrancado, pero, sin
embargo, no lo ha hecho. Para ver si está funcionando tienes
diferentes opciones: usar netstat para ver si el puerto está ocupado y
alguien está escuchando en él (y si es el Tomcat, mejor; si no lo es,
ha fallado por eso, porque no ha podido ocupar el puerto), escuchar
atentamente el disco duro a ver si al arrancar el tomcat le ha dado
vidilla, lo cual indica que efectivamente está funcionando; mirar a ver
si hay algo en el directorio Webapps , porque si no lo hay, va a dar un
fallo de contexto o algo por el estilo, con lo fácil que es decir, joer, que
no hay una puñetera página, ¡caray!. También es interesante tratar de
ejecutar los ejemplos: si fallan los JSPs pero no los servlets, es que
no se ha encontrado el fichero tools.jar, que, a pesar de su nombre, es
el que compila los JSPs. Por último, hay que mirar en el registro de
catalina, en log/catalina_log.[fecha].txt; si se ha arrancado correctamente,
aparecerá algo así:

2002-03-11 08:33:13 HttpConnector Abriendo sockets de


servidor en todas las direcciones IP disponibles
2002-03-11 08:33:15 HttpConnector[10001] Iniciando
thread de posterior
2002-03-11 08:33:15 HttpProcessor[10001][0] Iniciando
thread de posterior
Si solamente pone el primer mensaje, chungo; no ha iniciado ninguna
hebra, que son las que efectivamente sirven los JSPs. Si no es nada
de eso, mira los mensajes de error en el subdirectorio log, a veces
indican que falta algun fichero, o bien que hay un problema de
versiones de la máquina virtual Java.
Una vez que se ha instalado, y se ha comprobado que funciona
correctamente, se puede intentar cambiar la configuración, sobre todo
teniendo en cuenta el número de visitas esperadas. La mayoría de los
cambios de configuración se hacen sobre el fichero conf/server.xml.
Para cambiar el puerto en el que se escucha y el número de
servidores disponibles mínimo y máximo, hay que cambiar la
siguiente orden:
<Connector
className="org.apache.catalina.connector.http.HttpCon
nector"
port="10001"minProcessors="2"
maxProcessors=" 5"
enableLookups="true" redirectPort="8543"
acceptCount="10" debug="0"
connectionTimeout="60000"/>
La configuración de Tomcat se hace sobre un fichero que usa el
lenguaje XML. Con él, se definen una serie de elementos: servidores,
conectores y contenedores; la configuración se ha simplificado mucho
desde la versión anterior, aunque introduce nuevos elementos: las
válvulas y los motores. Tomcat define para cada servidor una serie de
conectores, mediante los cuales diferentes clases responden a
diferentes puertos, y se encargan de servirlos; los contenedores o
motores se encuentran dentro de los conectores, y se encargan de
manejar todas las peticiones para un servicio. Salvo que se vayan a
usar aplicaciones particulares (tales como Cocoon), no hay que
preocuparse mucho del tema. En nuestor caso, sólo habrá que
cambiar el número mínimo de procesadores (o hebras que sirven
peticiones) y el máximo, para no sobrecargar demasiado el sistema
en caso de que se cuente con poca memoria principal. El mínimo
aceptable es 2, y el máximo es hasta 65535 o hasta que la memoria
aguante (que no aguantará mucho). En cuanto al puerto, se puede
usar cualquiera, siempre que no esté ya usado, y siempre que se
ejecute desde superusuario; si no se es superusuario, hay que usar
los puertos por encima del mil. Una vez hecho esto, hay que
rearrancar el servidor para que tome los nuevos cambios:
[yo@mimaquina yo]$ /etc/rc.d/init.d/tomcat4 restart
Para ahorrar recursos, se pueden eliminar cosas de ese fichero. Por
ejemplo, si se trata de un servidor de desarrollo, no necesitamos
conectores para el apache ni conexiones que usen SSL. Se puede
eliminar la el servicio Tomcat-Apache, eliminando todo lo comprendido
entre la etiqueta Service y su contraetiqueta. También se pueden
eliminar los conectores AJP, SSL, "proxied", y de test, indicados con
un comentario, justo debajo del conector normal (el non-SSL
HTTP/1.1 ). Se pueden ahorrar unos pocos más recursos iniciando la
JVM de forma que se limite el tamaño del heap y de la pila, pero no se
ahorra demasiado espacio. Un Tomcat funcionando no ocupará nunca
menos de 90 megas (lo que se puede ver ejecutando el top o gtop o
bien, desde la línea de comandos, ps -exfua.
También se puede añadir un nuevo contexto al servidor; sobre todo si
queremos que nuestras aplicaciones no se mezclen con el resto de
las aplicaciones en el contexto raíz (las contenidas en el directorio
ROOT. Para ello, se puede añadir, justo después de la línea donde se
define tal contexto, lo siguiente:
<Context path="/micontexto" docBase="micontexto" debug="0"/>
(substituyendo micontexto por el valor adecuado; ambos nombres no
tienen porqué ser iguales). El path indica el URI que se va a utilizar
para referirse a él cuando lo llamen desde algún navegador, es decir,
http://miservidor/micontexto, y el segundo nombre es el subdirectorio del
directorio Webapps al que se refiere
Una vez realizada la aplicación, se puede alojar en un servidor que
ofrezca este servicio. Por ejemplo, Verio ofrece soluciones basadas
en el sistema operativo Solaris (el precio hay que consultarlo). Un
revendedor de este servicio, SoyDigital, menciona precios a partir de
210 €.
También hay alternativas gratuitas, aunque no son eternas como en el
caso de GeoCities. Una de ellas es iSavvix DevSpace, que permite
alojamiento gratuito de JSPs, con librerías de tags e incluso XSLT; lo
que no permite, es que uno suba sus propias clases, aunque se
pueden usar diversas librerías de clases presentes en el sitio. Otra
alternativa, WebAppCabaret, que da diversos contenedores de
servlets como alternativa: Tomcat y NGASI, Enterprise Java Beans,
bases de datos con MySQL, pero todo ello por solamente 15 días;
más allá de eso, hay que contratar el servicio Premium, a partir de 3$.
Por último, MyCGIserver también permite alojamiento gratuito; hay
que responder a una pregunta relacionada con los servlets, pero es
usualmente fácil de encontrar la respuesta.
Ejercicios 1
1. Seguir los pasos anteriores e
instalar un contenedor de servlets en
el ordenador. Probar con el Tomcat, y
si todo va bien, probar también con el
Caucho Resin. El proceso es
bastante similar. Cambiar la
configuración de Tomcat de forma
que cada conector use sólo 2 hebras
mínimo, y 5 máximo. Cambiar al
puerto al 10001; rearrancar el
servidor. Definir un nuevo contexto
para los ficheros propios.
2. Darse de alta en algún servidor
gratuito, y subir alguno de los Contenido de esta
ejemplos de Resin o de Tomcat sección
para probarlo. • Cómo
crear y
3 Nuestra primera página dónde
JSP poner la
Si todo va bien, y los ejemplos se página
ejecutan correctamente, ya está uno listo • hola.jsp
para crear su primer programa, o página,
en JSP (depende de como uno lo mire). Como las páginas JSP son
básicamente páginas HTML con un poco de Java por medio, sirven,
en principio, cualquier editor que comprenda la sintaxis HTML y/o
XML; por ejemplo, el XEmacs. Algunos otros entornos, tales como el
Sun ONE, una plataforma de desarrollo completa (que consume un
montón de recursos), el Visual Age for Java; estos dos están escritos
en Java y pueden ejecutarse en cualquier plataforma. El Dreanweaver
Ultradev, sin embargo, existe sólo en versión Windows. Forté es
gratuito, y los otros dos son de pago, aunque hay versiones de prueba
de tiempo limitado que se pueden bajar.
Con cualquier editor de texto se puede crear la primera página JSP
(hola.jsp; en acción en iSavvix):
<!-- (c) JJ -->
<%@ page language='java' contentType="text/html" %>
<%! int count=0; %>
<html>
<head><title>Hola y números. Intro to
JSP</title></head>
<body bgcolor="white">
Hola, mundo. Te lo repito <%= count++ %>
<% if (count == 1) { %>
vez
<% } else { %>
veces
<% } %>
</body></html>
Tras editar esa página, habrá que ponerla en algún sitio. La estructura
de directorios de Tomcat (y de otros contenedores de servlets) es un
poco más compleja que la de los servidores Web normales. Todos los
ficheros cuelgan del directorio Webapps, pero no se pueden colocar
directamente ahí. De ese directorio descienden otros subdirectorios,
que es donde efectivamente se colocan las aplicaciones. Cada
directorio corresponde a un contexto; hay un contexto raíz ROOT y
tantos otros contextos como queramos definir. Dentro de cada
contexto, la estructura de directorios es también siempre la misma;
directamente descendiendo del directorio se pueden poner los JSPs,
y hay también un directorio WEB-INF donde hay una serie de ficheros
de configuración y propiedades, y además otros directorios: classes y
lib (que no aparece en esta imagen). En esos directorios se pondrán
más adelante los ficheros .class y .jar, respectivamente. Por tanto, el
fichero anterior, irá a parar al directorio ROOT (o bien al directorio del
contexto propio que hayamos definido en el ejercicio anterior).
También se puede colocar en cualquiera de los subdirectorios del
directorio Webapps, pero no en el principal
El fichero contiene la mayoría de los elementos de un JSP. Para
empezar, la línea 2 <%@ page language='java' contentType="text/html" %>
incluye una directiva, que son órdenes que se ejecutan antes de que
se comience a procesar el JSP, y modifican de alguna forma el
resultado del mismo. Todas las directivas en JSP se indican con una
@ después del comienzo de la orden JSP (<%). En este caso, le
indicamos que la página que se va a ejecutar está en lenguaje Java, y
que el contenido que va a generar es de tipo text/html; el estándar JSP,
a pesar de su nombre, no está limitado a un solo lenguaje, aunque en
la práctica se usa casi siempre Java, y en algunos casos JavaScript.
En cuanto al contenido, JSP trabaja, por defecto, con HTML, pero se
podrían generar páginas en otros estándares tales como el WML que
se usa en los móviles WAP, o XML.
La directiva page puede incluir otros atributos:
<%@ page language='java'
contentType="text/html"
info='Mi primera página en JSP"
import='java.util.*'
errorPage='errorQueTeCagas.jsp' %>
info es una especie de comentario, que usa el contenedor para
describir la clase en su interfaz de administración; import permite
especificar una serie de paquetes en Java para importar, y errorPage
indica la página a la que habría que saltar en caso de que se genere
una excepción. Ahora mismo, ninguno de estos atributos son
necesarios, y, de hecho, la página funciona perfectamente bien sin
ellos; en ese caso, tomaría los valores por defecto, es decir, lenguaje
HTML para la página y Java para los scriptlets.
Justo a continuación, la línea <%! int count=1; %> es una declaración; la
admiración (!) se usa para indicar declaraciones de variables globales,
es decir, variables persistentes de una llamada a otra del JSP; y es
compartida por todas las llamadas a una página. La declaración se
ejecutará la primera vez que se llame a la página, y se volverá a
ejecutar cada vez que se recompile la página (o se rearranque el
servidor); el efecto que tendrá esta declaració será un contador de
visitas, que se incrementará cada vez que se visite. Por lo demás, la
declaración es una declaración normal en Java; se pueden incluir
tantas declaraciones como se quieran, no necesariamente al principio
de la página.
A continuación vienen una serie de elementos HTML, hasta la línea 7,
donde se encuentra la orden <%= count++ %>. Todo lo que comience
por <%= es una expresión JSP; el efecto que tiene es la evaluación de
la expresión y la impresión del resultado. En este caso, se ejecuta la
expresión y luego se imprime el valor, que es lo que hace el operador
post-incremento ++. Las expresiones en JSP pueden contener sólo
expresiones Java que devuelvan un valor, y no hace falta que se
terminen con ;, como en el caso de las declaraciones.
A continuación se encuentra una combinación de código Java y
elementos de texto que se suele denominar scriptlet. Los scriptlets
usan la sintaxis JSP normal, <% y %>; y dentro, se puede incluir
cualquier cacho de programa en Java que se quiera. En este caso es
una sentencia if, y lo único relevante es que el código Java está
mezclado con el texto; en este caso, se incluiría condicionalmente un
texto u otro en la página de salida. Se podría hacer usando sólo Java,
de esta forma
<% if (count == 2)
System.out.println('vez')
} else {
System.out.println('veces')
} %>
Sin embargo, de esta forma, se pueden incluir más fácilmente todo
tipo de estructuras HTML, sin necesidad de meter montones de
System.out. Lo del count == 2 es porque, cuando llega ahí el programa la
primera vez que se ejecuta, el contador ya vale dos, porque se ha
incrementado en la línea anterior.
Si no queremos tomarnos toda la molestia de meterlo en el contnedor
de servlets, podemos intentar compilarlo antes, para ver si hay algún
errorcillo que se nos hubiera saltado, por ejemplo de sintaxis. Se
puede usar para ello el compilador de JSPs offline; Tomcat incluye
jasper, que se puede usar de la forma siguiente (versión 4):
djasper4 jspc hola.jsp
(aunque en el RPM de la versión 4.0.2 no funciona correctamente,
creo...). Si todo va bien, se genera un fichero hola.java que, sería el
que, compilado, daría el servlet; de hecho, este fichero se podría
compilar y ponerse como servlet. Esta compilación no es necesaria,
pero si estamos trabajando con un fichero grande y no tenemos muy
claro si la sintaxis es correcta, se puede usar; aunque en la mayor
parte de los casos, se lo tragará todo y dejará al engine el coger los
errores. De hecho, no he conseguido que dé un error, por muchas
cosas que le he he hecho...
Si nos hemos equivocado en alguna cosa, el contenedor de servlets
dará los errores correspondientes. Por ejemplo, si alguna etiqueta de
JSP no la hemos puesto bien (< } %>), saldrá algo así:
org.apache.jasper.JasperException: No se puede
compilar la clase para JSP
/var/tomcat4/work/localhost/jmerelo/hola$jsp.java:90:
'catch' without 'try'.
} catch (Throwable t) {
^
/var/tomcat4/work/localhost/jmerelo/hola$jsp.java:98: 'try'
without 'catch' or 'finally'.
}
^
/var/tomcat4/work/localhost/jmerelo/hola$jsp.java:98: '}'
expected.
}
^
3 errors
tras explicar el tipo, el mensaje y la descripción. En realidad, este
mensaje no tiene nada que ver con el error, pero es lo más que se
puede pedir, teniendo en cuenta que tenemos varias fases de
compilación. A lo que hay que prestarle atención es a la última línea,
la que dice que se esperaba un }; como el cierre de llave está fuera de
una etiqueta JSP, el intérprete no lo entiende. Sin embargo, si
cometemos un error de sintaxis Java, la cosa estará un poco más
clara:
org.apache.jasper.JasperException: No se puede
compilar la clase para JSP
An error occurred at line: 10 in the jsp file: /hola.jsp
Generated servlet error:
/var/tomcat4/work/localhost/jmerelo/hola$jsp.java:83:
Invalid expression statement.
} ese {
^

An error occurred at line: 10 in the jsp file: /hola.jsp


Generated servlet error:
/var/tomcat4/work/localhost/jmerelo/hola$jsp.java:83: ';'
expected.
} ese {
Como los errores no son muy informativos, muchas veces no queda
otro remedio que leer bien leido el código de error, y mirar las fuentes,
a ver qué es lo que le ha molestado. En estas cosas, como en otras
muchas, la experiencia es un grado.
Ejercicios 2
1. Usando la clase java.util.Date,
hacer un JSP que imprima la hora y
los minutos, y probarlo en algún
servidor gratuito o en un Contenido de esta
servidor propio sección
• Etiquetas
4 Elementos adicionales jsp
• Clases en
del JSP. Beans. Java.
A partir de este momento, vamos a Beans
intentar montar paso a paso una
quiniela en Internet, que la gente pueda rellenar, votar los resultados,
y, finalmente, sacar un resumen de todos para que en la oficina se
rellene la quiniela común de acuerdo con ello (aunque siempre hay un
asaúra que está en desacuerdo, y que quiere ponerle un 2 al Depor-
Recre).
Para empezar, vamos a montar simplemente un JSP que presente el
resultado de un partido, un resultado que incluiremos también dentro
de la página (resultado0.jsp; y en acción en iSavvix)
.

<%! public class Partido {


String juegaEnCasa;
String juegaFuera;
boolean[] pronostico = new boolean[3];
public String getJuegaEnCasa() {
return this.juegaEnCasa;
}
public void setJuegaEnCasa( String _newVal) {
this.juegaEnCasa = _newVal ;
}
public String getJuegaFuera() {
return this.juegaFuera;
}
public void setJuegaFuera( String _newVal) {
this.juegaFuera = _newVal ;
}
public boolean[] getPronostico() {
return this.pronostico;
}
public void setPronostico(boolean[] _newVal) {
for ( int i = 0; i < 3; i ++ ) {
pronostico[i] = _newVal[i];
}
}
}%>
<%! Partido estePartido = new Partido(); %>
<html>
<head><title>Resultado de un partido - con
scriptlets</title></head>
<%@ include file='cabecera.jsp' %>
<h1>Ejemplo 2: Resultados de la quiniela</h1>
<table border borderwidth='1'>
<tr><th colspan="2">Partido</th><th
colspan="1">Pronostico</th></tr>
<% estePartido.setJuegaEnCasa( "Madrid" );
estePartido.setJuegaFuera("Barcelona" );
boolean[] pronostico = new boolean[3];
for ( int i = 0; i < 3; i ++ ) {
pronostico[i] = true;
}
estePartido.setPronostico( pronostico ); %>
<td><%= estePartido.getJuegaEnCasa() %> </td><td>
<%= estePartido.getJuegaFuera() %>
<%! boolean[] estePronostico =
estePartido.getPronostico(); %>
<td><% if (estePronostico[0] ){ %>1 <% } %><% if
(estePronostico[1] ){ %>X <% } %>
<% if (estePronostico[2] ){ %>2 <% } %>
</table>
<%@ include file='pie.jsp' %>
El JSP es un poco extenso, sobre todo por el código Java insertado.
Este código crea una clase llama Partido, que consta de los dos
equipos que juegan, en casa y fuera, y del pronóstico. El pronóstico
se define como un array de 3 booleanos, uno para cada resultado
posible; 1, X o 2 (gana el equipo de casa, empate o gana el de fuera).
Los pronósticos se pueden combinar (son las llamadas apuestas
múltiples), de forma que un posible resultado a un partido puede ser
X, 12 o incluso 1X2. La clase se compone de tres pares de métodos,
para establecer el valor (set) de una variable, y para devolver (get) el
valor de la misma.
A continuación, se crea una instancia de la clase llamando a new; el
objeto estePartido contendrá el valor de la variable, y lo compartirán
todas las llamadas al JSP. No es que sirva de mucho la compartición,
pero lo hemos dejado así.
Unas líneas más abajo se usa la etiqueta jsp:include, nuestra primera
etiqueta JSP. Es una orden específica de JSP, que en el servidor,
antes de crearse la respuesta que se envíe al cliente, se ejecutará,
incluyendo, en este caso, un fichero JSP (o uno HTML). Si se trata de
un fichero JSP, este fichero, a su vez, se interpretará y se incluirá el
resultado en la página. Esto se puede hacer también de la forma
siguiente:
<%@ import file='cabecera.jsp' >
con la diferencia de que, en este caso, primero se incluye el contenido
del fichero y luego se interpreta. import es una directiva de tiempo de
compilación, mientras que jsp:include actúa en tiempo de ejecución. En
este caso, se incluye una pequeña cabecera común a todos los
ejercicios, de la misma forma que, al final del fichero, se incluye un
pie, que cierra el fichero HTML y los cambios de fuente.
En el siguiente scriptlet se establecen los valores de las variables
llamando a los métodos set, para después recuperarlos dentro de una
tabla, usando los métodos get; el resultado del array booleano que
devuelve getPronostico se tiene que formatear para convertirse en 1X2
En realidad, para lo que hemos hecho, podíamos habernos ahorrado
tanta clase y tanto JSP y tanta gaita, pero nos sirve para introducir un
concepto que resulta terriblemente útil en el mundo del JSP: las
habichuelas o beans. Los beans están definidos por un estándar de
Sun, y tienen cierta complejidad, pero desde el punto de vista de los
JSPs son simplemente clases en las cuales las variables pueden ser
accedidas mediante métodos set (para cambiar su valor) y get para
recuperar su valor; los métodos set se llaman con un sólo argumento
del mismo tipo que la variable de instancia, y los métodos get
devuelven un objeto del tipo de la variable de instancia, sin tomar
ningún argumento. No todos los métodos set tienen que corresponder
a una variable de instancia, ni tampoco los get; pero todos los
métodos que devuelvan un valor tienen que tener esa estructura, igual
que todos los que alteren un valor. La clase Partido anterior es un
Bean, igual que lo es la siguiente, ligeramente ampliada
(quiniela/Partido.java):

package quiniela;
public class Partido {
String juegaEnCasa;
String juegaFuera;
boolean[] pronostico = new boolean[3];
String unoequisdos="1X2";
public String getJuegaEnCasa() {
return this.juegaEnCasa;
}
public void setJuegaEnCasa( String _newVal) {
this.juegaEnCasa = _newVal ;
}
public String getJuegaFuera() {
return this.juegaEnCasa;
}
public void setJuegaFuera( String _newVal) {
this.juegaFuera = _newVal ;
}
public boolean[] getPronostico() {
return this.pronostico;
}
public void setPronostico(boolean[] _newVal) {
this.pronostico = pronostico;
}
public void setPronosticoAsString(String _newVal) {
for ( int i=0; i < 3; i++ ) {
if
( _newVal.indexOf(this.unoequisdos.charAt(i)) >= 0 ) {
this.pronostico[i] = true;
} else {
this.pronostico[i] = false;
}
}
}
public String getAsString() {
String str=this.juegaEnCasa + "-" +
this.juegaFuera + ": ";
for ( int i = 0; i < 3; i ++ ) {
if ( this.pronostico[i] ) {
str +=
this.unoequisdos.charAt(i);
}
}
return str;
}
public String getFormatted() {
String str= "<tr><td>" + this.juegaEnCasa +
"</td><td>" + this.juegaFuera + "</td>";
for ( int i = 0; i < 3; i ++ ) {
if (this. pronostico[i] ) {
str += "<td>" +
unoequisdos.charAt(i)+ "</td>";
} else {
str += "<td
bgcolor=black> </td>";
}
}
str += "</tr>";
return str;
}
}
Los beans se pueden usar fácilmente desde los JSPs, usando
etiquetas. El JSP anterior se puede poner de la forma siguiente,
usando beans (resultado.jsp; el resultado en acción es prácticamente
igual al caso anterior):

<%@ page import = "quiniela.Partido" %>


<jsp:useBean id="estePartido" class="quiniela.Partido"
/>
<jsp:setProperty name="estePartido"
property="juegaEnCasa" value="Madrid" />
<jsp:setProperty name="estePartido"
property="juegaFuera" value="Barça" />
<jsp:setProperty name="estePartido"
property="pronosticoAsString" value="1X2" />
<html>
<head><title>Resultado de un partido</title></head>
<%@ include file ="cabecera.jsp" %>
<h1>Resultados de la quiniela</h1>
<table border borderwidth='1'>
<tr><th colspan="2">Partido</th><th
colspan="3">Pronostico</th></tr>
<jsp:getProperty name="estePartido"
property="formatted" />
</table>
<%@ include file ="pie.jsp" %>
Antes de que esto funcione, hay que compilar la habichuela y ponerla
en su sitio correspondiente. En este caso, tendremos que colocarla en
el subdirectorio WEB-INF/classes/quiniela; las dos primeras partes
corresponden al camino en el que hay que colocar todos los .class, y
quiniela es el nombre del package en el que hemos metido nuestra
clase Partido. Todas las clases compiladas de este paquete tendrán
que ir a ese directorio. Los JARs irán también dentro de su directorio
correspondiente, así como otros ficheros que no se destinan
directamente a servirse al público.
El JSP usa la orden en tiempo de compilación explicada
anteriormente para importar la habichuela dentro del contexto de la
página. Posteriormente, declara un bean llamado estePartido mediante
la etiqueta jsp:useBean. Esta etiqueta crea un Bean de una clase
determinada; es el equivalente a llamar a new en Java. Las
propiedades de ese bean (las variables accesibles mediante get y set)
se usarán a través de los métodos jsp:getProperty y jsp:getProperty; es
decir, <jsp:setProperty name="estePartido" property="juegaEnCasa"
value="Madrid" /> es equivalente a estePartido.setJuegaEnCasa( "Madrid" ). El
atributo property incluye a la propiedad a la que se va a acceder; a esa
propiedad se pone la primera letra en mayúscula y se le precede con
get o set para hallar el método de la clase al que hay que llamar. Las
líneas siguientes establecen los valores de las tres propiedades del
bean. Posteriormente, se imprimen los valores devueltos por esas
propiedades. Únicamente hay que fijarse un poco en la propiedad
formatted; en realidad, consiste en una llamada a un método sin
correspondencia con ninguna variable de instancia; al JSP le da
exactament igual, y llama al método correspondiente.
Como los errores no son muy informativos, muchas veces no queda
otro remedio que leer bien leido el código de error, y mirar las fuentes,
a ver qué es lo que le ha molestado. En estas cosas, como en otras
muchas, la experiencia es un grado.
Ejercicios 3
1. Crear un bean para una pregunta a
una encuesta y su respuesta
correspondiente, y un JSP que lo
presente en pantalla.
2. Modificar el JSP anterior
para que presente los 14 Contenido de esta sección
• Acceso a
resultados de la quiniela.
objetos
5 Páginas dinámicas. implícitos
Como para hacer páginas estáticas, • Contenido
ya tenemos el HTML propiamente dinámico
dicho, vamos a meter un poco de • Excepciones
dinamismo en las páginas,
permitiendo que se modifique la página según cómo se la llame. Más
adelante veremos cómo hacer que el usuario introduzca esos datos
directamente. Para empezar, haremos que la página varíe
dependiendo de la forma cómo se la invoque, en la pagina siguiente
(resultadoDyn.jsp)

<%@ page import = "quiniela.Partido" %>


<jsp:useBean id="estePartido" class="quiniela.Partido"
/>
<jsp:setProperty name="estePartido" property="*" />
<html>
<head><title>Resultado de un partido
dinámico</title></head>
<-- El resto igual -->
En este caso, usamos, igual
que en los ejemplos
anteriores, jsp:setProperty, pero
ahora le asignamos valores a
todas las propiedades a la vez
tomándolas de los argumentos
con los que se llama el JSP; si
lo llamamos de la forma
siguiente

http://localhost:8080/jmerelo/resultadoDyn.jsp?juegaEnCasa=Osasuna&juegaFuera
=Villareal&pronosticoAsString=X; se llamarán a las tres propiedades
correspondientes, y se les asignará el valor indicado. La sintaxis que
se sigue en esas llamadas es nombredel.jsp?variable=valor&variable=valor, y
así sucesivamente. Es la sintaxis normal para pasar valores a los
programas que se ejecutan en el servidor, tal como los JSPs. El
resultado se puede ver en la imagen
Al usar los parámetros que se pasan al JSP, estamos utilizando en
realidad un objeto implícito del JSP, el objeto request, una instancia de
la clase javax.servlet.http.HttpServletRequest, exactamente igual que se usa
en los servlets (y es que, en realidad, se tratan de la misma cosa).
Podemos acceder a él tal como se hace en el siguiente ejemplo
(resultadoDyn2.jsp), que sólo varía unas líneas con respecto al anterior:
<tr><td colspan='5'><em>Comentario</em><% if
(request.getParameter("pronosticoAsString") == "X" )
{ %>
Empate
<% } else if (request.getParameter("pronosticoAsString")
== "1" ) { %>
Gana el de casa
<% } else { %>
Gana visitante
<% } %> </td></tr>
Aquí estamos usando el objeto implícito request, llamando a su método
getParameter para obtener el valor del parámetro de llamada
pronosticoAsString. Este objeto tiene los mismos métodos que el
equivalente de servlets, así que no nos extendemos más en él. Los
más útiles son el anterior, getParameterNames y getParameterValues; otros,
tales como getCookies, se usarán para obtener las cookies del cliente.
En este caso, se incluirán en la salida diferentes cadenas
dependiendo del valor del pronóstico; si es un resultado múltiple, no
se incluirá nada.
Hay otros objetos implícitos; probablemente los más usados sean
session, que maneja las variables de sesión, y application, con métodos
relativos al contexto dónde se está ejecutando el servlet al que
corresponde el JSP.
¿Qué puede ocurrir si alguno de los parámetros pasados tiene un
valor inválido? Por ejemplo, se podían validar que los equipos
correspondieran a la misma división, o que los pronósticos estén
siempre compuestos de 1, equis o doses; hasta el momento, no se
hace ningún tipo de comprobación. Para ello, tendremos que
modificar ligeramente el bean, haciendo que el método
setPronosticoAsString tire una excepción si se encuentra con un carácter
inválido en la cadena que se le pasa. Después de cambiarle el
nombre a la clase ( quiniela/PartidoValidado.java):
public void setPronosticoAsString(String _newVal) throws
RuntimeException{
if (_newVal.length() > 3)
throw new RuntimeException
( "Pronóstico más largo de la cuenta" );
if (_newVal.length() == 0)
throw new RuntimeException ( "No
hay pronóstico" );
for ( int j = 0; j < _newVal.length(); j ++ ) {
if ( _newVal.charAt(j) != '1' &&
_newVal.charAt(j) != 'X'
&& _newVal.charAt(j) != '2' )
{
throw new RuntimeException
( "Carácter raro en cadena:"+ _newVal.charAt(j) + " en la
posición " + j );
}
}
for ( int i=0; i < 3; i++ ) {
if
( _newVal.indexOf(this.unoequisdos.charAt(i)) >= 0 ) {
this.pronostico[i] = true;
} else {
this.pronostico[i] = false;
}
}
}
Con respecto a la versión anterior, se han añadido una serie de
comprobaciones de longitud excesiva, demasiado pequeña, o si hay
algún carácter que no sea 1X2. Capturar la excepción en un programa
en Java es fácil (con las sentencias try y catch), pero, en un JSP nos
encontraremos algo así:
java.lang.reflect.InvocationTargetException:
java.lang.RuntimeException: Pronóstico más largo de la
cuenta
at

quiniela.PartidoValidado.setPronosticoAsString(PartidoValidado.jav
a:31)
Para ello se usan las páginas de error, que se llaman en caso de que
se haya producido una excepción; es más o menos lógico que no se
traten las excepciones dentro de la misma página, porque, en algunos
casos, pueden producirse antes incluso de que el código haya sido
generado. Para usar la página de error, incluimos al principio del
fichero ( resultadosDynVal.jsp):
<%@ page errorPage="paginaError.jsp?debug=log" %>
<% request.setAttribute("paginaOrigen",
request.getRequestURI()); %>
Con esto se declara una página de error, y se asigna un atributo a la
petición, que almacenará el URI de la peticición, es decir, el camino
con el que se la ha llamado. El código de la página de error es el
siguiente ( paginaError.jsp):
<%@ page isErrorPage="true" %>
<html>
<head><title>Se ha producido un error</title></head>
<%@ include file ="cabecera.jsp" %>
<h1>Se ha producido un error</h1>
<p>Endeluego, que a ver si tenemos cuidaico, que se ha
producido el siguiente error:<br>
<%= exception.getMessage() %> en la página
<%=
request.getAttribute("paginaOrigen") %>
<%@ include file ="pie.jsp" %>
Lo más importante es la primera línea: la página se declara a sí
misma como una página que responde a los errores, lo cual permite
que se cree el objeto implícito exception. Ese objeto se usa más
adelante para imprimir el mensaje que se ha producido (aunque no
siempre funciona). También se recupera un atributo del objeto
implícito request, que había sido puesto por la página que ha producido
el error, para que se sepa de dónde procede el error. Cuando se
produzca alguna entrada errónea, por ejemplo, pronosticoAsString=123,
se producirá una excepción en el objeto PartidoValidado, que se
propagará al JSP que la contiene, que a su vez llamará a esta página
de error
.
Ejercicios 4
1. Cambiar la encuesta para que
tome los resultados de los
parámetros que se le pasen al JSP .
2. Cambiar la EncuestaBean para
que detecte errores (tales como una
respuesta incorrecta), y levante una
excepción; crear una página
de error que capture esa Contenido de esta sección
• Formularios
excepción y la muestre.
• Combinación
6 Procesamiento de de elementos
JSP
formularios • Ámbitos
Ya está bien de tanto objeto •Taglibs
implícito y tanta gaita, vamos a ir
directamente al turrón de procesar formularios como Dios manda.
Vamos a tratar de hacer una página JSP que cree y a la vez procese
el formulario; de esta forma es más fácil de mantener. El formulario
nos permitirá rellenar la quiniela sin hacer nada en concreto con ella,
sólo presentarla. En la práctica, habría probablemente que almacenar
los resultados en una base de datos, o por lo menos un fichero, pero
por lo pronto, lo dejaremos así. El formulario se implementa en el
código siguiente:(quiniela.jsp, que usa la clase Quiniela:)

<%@ page import = "quiniela.*" %>


<jsp:useBean id='estaQuiniela' class="quiniela.Quiniela"
scope='request'/>
<jsp:setProperty name='estaQuiniela'
property='inputFile' value=
"/home/jmerelo/public_html/JSP/quiniela.dat" />
<html>
<head>
<title>Rellena tu quiniela</title>
</head>
<%@ include file ="cabecera.jsp" %>
<h1>Rellena tu quiniela</h1>
<form action='quiniela.jsp' method='get' >
<% for ( int i = 0; i < estaQuiniela.getNumPartidos(); i
++ ) {
String proStr = "pronostico"+i;
try { %>
<jsp:setProperty name='estaQuiniela'
property='numPartido' value="<%= i %>" />
<% if ( request.getParameter("pronostico0") != null ) {
%>
<jsp:setProperty name='estaQuiniela'
property='pronosticoAsString' value="<%=
request.getParameter( proStr) %>" />
<% } else { %>
<jsp:setProperty name='estaQuiniela'
property='pronosticoAsString' value="1X2" />
<% }
} catch (Exception _e ) {
System.err.println( "Esto no debiera pasar: "
+ _e.getMessage() );
}
}%>
<table border>
<tr><th> </th><th>Partido</th><th>Pronóstico</th><th>P
ronóstico Anterior</th>
</tr>
<% for ( int i = 0; i < estaQuiniela.getNumPartidos(); i ++ )
{
String proStr = "pronostico"+i; %>
<tr><td><%= i %></td>
<jsp:setProperty name='estaQuiniela'
property='numPartido' value="<%= i %>" />
<td><jsp:getProperty name='estaQuiniela'
property='juegaEnCasa' />-
<jsp:getProperty name='estaQuiniela'
property='juegaFuera' /></td>
<td><input type='text'
name='pronostico<%= i %>' value='<jsp:getProperty
name='estaQuiniela' property='pronostico' />' ></td>
<td><jsp:getProperty
name='estaQuiniela' property='pronostico' /> </td>
</tr>
<% } %>
<tr><td colspan="4" align="center"><input type='submit'
></td>
</tr>
</table>
</form>
<%@ include file ="pie.jsp" %>
Para empezar, hemos creado un nuevo bean que contiene un vector
de partidos, llamado Quiniela; este bean
Para quien no haya
será el que usemos en la página; en
trabajado con formularios
general, es una buena idea reflejar la
(ver por ejemplo este
estructura de una página en un bean, o
tutorial de formularios o
viceversa. En el caso anterior usábamos
bien este tutorial de HTML,
los beans Partido y PartidoValidado, y en
que incluye también
este caso usamos esta. La única
formularios)
peculiaridad de esta clase es que,
debido a su estructura como Bean, no se puede llamar a ningún
método con dos argumentos, por lo que tenemos que establecer un
cursor de partido que indique sobre qué partido van a actuar los
métodos que ponen o extraen valores de la clase
El objeto que va a contener la quiniela se declara en las primeras
líneas, mediante el tag <jsp:useBean>. A continuación se le pasa el
fichero quiniela.dat, que contiene los datos de una quiniela (de primera
división universal especial, como se puede comprobar). A
continuación, después de abrir el formulario, se detecta si se ha
usado uno de los datos del mismo (pronostico0), en cuyo caso se
empieza a procesarlo: se crea una cadena con el nombre del
parámetro (pronostico + el índice), se usa esa cadena para colocar el
cursor (%lt;jsp:setProperty name='estaQuiniela' property='numPartido' value="<%=
i %>" />) y se asigna el pronóstico al partido correspondiente de la
quiniela. Como se ve, este formulario sirve para las dos cosas: para
recibir las entradas, y para procesarlas.
En las siguientes líneas se presentan los resultados que se han
introducido lado a lado con una serie de cuadros de texto que
permiten cambiar el pronóstico.
Este código se puede mejorar un tanto, evitando errores en origen
poniendo checkboxes (es decir, cuadraditos sobre los cuales se
puede pinchar) en vez de introducirlo mediante el teclado. Eso no
quiere decir que se tenga que eliminar el código de corrección de
errores, porque siempre se puede modificar a mano la petición al
servidor. Simplemente, se le evitan problemas al usuario. Eso se hace
en la siguiente versión quinielaBoton.jsp:

<!-- El principio es similar >


<% for ( int i = 0; i < estaQuiniela.getNumPartidos(); i
++ ) {
String proStr = "pronostico"+i;
String strPronostico ="";
String[] params = request.getParameterValues(
proStr );%>
<jsp:setProperty name='estaQuiniela'
property='numPartido' value="<%= i %>" />
<% if ( request.getParameter("submit") != null ) {
for ( int j = 0; j < params.length; j ++ ) { strPronostico
+= params[ j ]; }
%>
<jsp:setProperty name='estaQuiniela'
property='pronosticoAsString' value="<%= strPronostico
% >" />
<% } else { %>
<jsp:setProperty name='estaQuiniela'
property='pronosticoAsString' value="1X2" />
<% }
}%>
<table border>
<tr><th rowspan='2'> </th><th
rowspan='2'>Partido</th><th
colspan='3'>Pronóstico</th><th rowspan='2'>Pronóstico
Anterior</th>
</tr>
<tr><td>1</td><td>X</td><td>2</td>
</tr>
<% for ( int i = 0; i < estaQuiniela.getNumPartidos(); i ++ )
{
String proStr = "pronostico"+i;
%>
<tr><td><%= i %></td>
<jsp:setProperty name='estaQuiniela'
property='numPartido' value="<%= i %>" />
<td><jsp:getProperty name='estaQuiniela'
property='juegaEnCasa' />-
<jsp:getProperty name='estaQuiniela'
property='juegaFuera' /></td>
<% boolean[] pronosticos =
estaQuiniela.getPronostico();
for ( int j = 0; j < 3; j ++ ) { %>
<td><input type='checkbox'
name='pronostico<%= i %>' value='<%=
quiniela.PartidoValidado.get1X2( j ) %>' <%=
pronosticos[j]==true?"checked":"" %>' ></td>
<% } %>
<td><jsp:getProperty
name='estaQuiniela' property='pronosticoAsString' />
</td>
</tr>
<% } %>
<tr><td colspan="4" align="center"><input type='submit'
name='submit' value='Enviar'></td>
</tr>
</table>
</form>
El truqui del asunto está al principio: en vez de usar getParameter
para coger un solo parámetro, se usa getParameterValues, que
devuelve un array con todos los valores que tiene un parámetro; en
este caso, cada grupo de 3 botones usa el mismo nombre de
elemento del formulario, por eso cada parámetro tendrá tantos
elementos como botoncitos se hayan rellenado. En todo caso, se
pegan los parámetros en una sola cadena, que se usa para asignarle
un valor al pronóstico.
En cuanto al formulario, en este caso tenemos que usar el pronóstico
como un array de valores booleanos (en vez de una cadena como
hacíamos anteriormente), porque nos conviene más a la hora de
poner el valor por defecto a los botones. Usamos también un método
de clase de Java, para pasar de un índice de 0 a 2 al símbolo
correspondiente (1, X o 2).
Pero claro, lo interesante no es sólo presentar los datos del
formulario, sino agregarlos en unas estadísticas para toda la oficina (y
de camino, fastidiar al asaúra mostrándole que su pronóstico no lo
comparte nadie) y presentarlos en un gráfico chuli. Eso lo haremos en
el siguiente programa (stats.jsp):

<%@ page import="quiniela.*" %>


<jsp:useBean id='stats' class='quiniela.Stats'
scope='application' />
<jsp:useBean id='estePartido'
class="quiniela.PartidoValidado" scope='request' />
<jsp:setProperty name='estePartido'
property='juegaEnCasa' value= "Valencia" />
<jsp:setProperty name='estePartido'
property='juegaFuera' value= "Inter" />
<-- El resto similar a los anteriores -->
<%@ include file ="pie.jsp" %>
Este fichero es similar a los anteriores que se han tratado, pero en
este caso se usa un bean que tiene ámbito de aplicación, indicándolo
con scope='application' . Eso significa que va a poder ser "visto" por
todos los demás servlets y JSPs del servidor; sería algo así como una
variable del servidor. Esto lo vamos a usar para poder compartir
información entre diferentes invocaciones y diferentes JSPs.
Hay cuatro ámbitos diferentes en las variables usadas en JSPs y
servlets:
• el ámbito de página: objetos que sólo están
accesibles durante la ejecución del código de una
página
• petición: objetos compartidos entre las diferentes
páginas que manejan una petición, por ejemplo,
una página y la que maneje errores de la primera,
o una página y otra a la que se pasa control con la
orden jsp:forward
• sesión; objetos compartidos entre las diferentes
páginas que se llamen a través de una sesión, y,
por último
• aplicación, compartidos por todos los objetos
dentro del servidor
.
Este último ámbito es el que usamos precisamente en esta
página. Para entendernos, serían como una especie de objetos
persistentes, que estarán ahí hasta que rearranquemos el
servidor. Y precisamente eso es lo que vamos a hacer, usarlos
para ver esas estadísticas en plan chuli (viewstats.jsp).
<%@ taglib uri="bartag.jar" prefix="bar" %>
<%@ page import="quiniela.*" %>
<jsp:useBean id='stats' class='quiniela.Stats'
scope='application' />
<html>
<head>
<title>Ver Estadísticas de la quiniela</title>
</head>
<%@ include file ="cabecera.jsp" %>
<h1>Ver Estadísticas de la quiniela</h1>
<table border>
<tr><th>Partido</th><th
colspan='2'>Estadísticas</th>
</tr>
<tr>
<td>Alcorcón - Vitigudino</td>
<td><bar:Hbar values="<%=
stats.getAsString() %>" fgcolor="#FF0000"
width="220" labels="1,X,2" bgcolor="#0000FF" />
</td>
<td><%= stats.getAsString() %></td>
</tr>
</table>
<%@ include file ="pie.jsp" %>

Las novedades de este nuevo fichero empiezan pronto: en la


primera línea. Los gráficos no es algo que se pueda hacer con
JSPs así, a pelo, así que usamos una librería de etiquetas, una
tag library. En este caso se trata de la librería barchart, una
taglib para hacer gráficos de barras horizontales y verticales.
Instalarla es fácil: hacen falta dos ficheros: el archivo de clases
de java, .jar, y una descripción de las etiquetas y su
correspondencia con métodos y clases, .tld. Cada uno de estos
ficheros suele ir a un sitio diferente: el primero a WEB-INF/lib y el
segundo a WEB-INF/tlds. También pueden ir al mismo directorio
donde esté el fichero correspondiente, pero será más
complicado de usar desde otros JSPs. La taglib esta también
está disponible en iSavvix, entre otras muchas
Las taglibs son simplemente un cambio de interface con
respecto al código Java normal; te ahorran insertar código
dentro de las páginas, y son, en general, más fáciles de
mantener, porque, en el más puro estilo OO, encapsulan su
lógica y el que las usa no tiene que preocuparse por cómo
hacen lo que hacen, sólo por acceder a ellas. Hay muchas
gratuitas, y hay colecciones tales como esta de JSPin. Sin
embargo, la que usamos aquí no lo es, y sólo permite cinco
datos simultáneos, así que tendremos que hacer un gráfico
chiquitito.
En este caso no nos hemos complicado la vida y hemos puesto
directamente el fichero en el mismo directorio que el fichero
JSP correspondiente; eso lo indicamos con uri="bartag.jar" ;
además, tenemos que definir el prefijo (en realidad, el espacio
de nombres) que vamos a usar para referirnos a esa taglib: en
este caso prefix="bar" indica que el prefijo va a ser bar (barra).
Con esta taglib se pueden hacer barras horizontales y
verticales; nosotro susamos las barras horizontales bar:Hbar, a
las que hay que pasarle los valores que se quieren representar
separados por comas, y otra serie de atributos que establecen
los colores, la anchura y las etiquetas de cada uno de los
valores que se le han pasado. El resultado es el que se
muestra en la figura.
Ejercicios 5
1. Hacer un formulario con una
encuesta que guarde
estadísticas sobre las
respuestas contestadas
2. Usar una librería de etiquetas
que incluya bucles, y convertir
algún JSP anterior que use
bucles java a uno que use los
bucles de la taglib.
3. Hacer un JSP que contenga
un carrito de la compra usando
beans con ámbito de sesión.
7 Bibliografía y enlaces relacionados con
JSP

Convenciones de Programación Java para Páginas JSP


1 . Introducción
1.1 . ¿Por qué tener Convenciones de Codificación?
2 . Nombres de Ficheros y sus Localizaciones
3 . Organización de Ficheros
3.1 . Ficheros JSP / Ficheros de Fragmento JSP
3.1.1 . Comentarios Iniciales
3.1.2 . Directiva(s) JSP Page
3.1.3 . Directiva(s) Tag Library Opcionales
3.1.4 . Declaraciones JSP Opcionales
3.1.5 . Código HTML y JSP
3.1.6 . Descriptor de Librería de Etiquetas
4 . Identación
4.1 . Identación de Elementos de Script
4.2 . Identación Compuesta con JSP, HTML y Java
5 . comentarios
5.1 . Comentarios
5.2 . Comentarios del Lado del Cliente
5.3 . Bloques de Comentarios Multi-línea
6 . Declaraciones JSP
7 . Scriptlets JSP
8 . Expresiones JSP
9 . Espacios en Blanco
9.1 . Líneas en Blanco
9.2 . Espacios en Blanco
10 . Convenciones de Nombres
10.1 . Nombres JSP
10.2 . Nombres de Etiquetas
10.3 . Nombres de Prefijos de Etiquetas
11 . Páginas JSP con Sintaxis XML
11.1 . Estructura de un Documento JSP
11.2 . Comentarios XML
11.3 . Código Java en Documentos JSP
12 . Prácticas de Programación
12.1 . Inicialización de JavaBeans
12.2 . Objetos Implícitos de JSP
12.3 . Entrecomillado
12.4 . Usar Etiquetas Personalizadas
12.5 . Uso de TagExtraInfo y TagLibraryValidator
12.6 . Usar JavaScript
12.7 . Hojas de Estilo en Cascada (CSS)
12.8 . Usar Patrones de Vistas Compuestos
12.9 . Otras Recomendaciones

Introducción
A medida que se han ido adoptando las JavaServer Pages (JSP) en la aplicaciones basadas en la
Web, muchos programadores y desarrolladores embarcados en el desarrollo y mantenimiento de
estas aplicaciones se encuentran con un dilema igual que el de muchos programadores Java,
"¿Cómo estructuramos el código JSP para que sea fácil de leer, de escribir y de mantener?

En este artículo, se propone un conjunto de convenciones estándar para escribir JSPs (versiones
1.1 y 1.2) que se deberían seguir en un proyecto típico de desarrollo de software que utiliza
componentes Web. Utiliza Code Conventions for the Java Programming Language (de las que
puedes encontrar una traducción en esta misma site, en
http://programacion.com/java/tutorial/convenciones/) como plantilla para identificar varios
elementos importantes que se deberían corregir en una especificación de convenciones de
codificación (relevante para JSP). En particular, corrige los nombres y la organización de los
ficheros, la identación, los comentarios, las directivas, las declaraciones, los scriptlets, las
expresiones, los espacios en blanco, las convenciones de nombres y las prácticas de
programación. Como este es el primer intento de de presentar un conjunto de convenciones de
codificación JSP, están muy interesados en recibir cualquier feedbak sobre estas
recomendaciones. Puedes escribirles a jsp-codeconv-comments@sun.com.

La especificación JavaServer Pages 2.0, aunque es totalmente compatible con la versión 1.2,
permite un estilo de programación libre de scripts (sin declaraciones, scriptles y expresiones) y
tiene varias nuevas características que esperamos que hagan evolucionar estas convenciones.
Siempre que ha sido posible este artículo ha elegido convenciones que permanecerán con las
nuevas características de JSP 2.0.
Finalmente, asumen que estás familiarizado con JSP, Java y las convenciones de codificación
Java.
¿Por qué tener Convenciones de Codificación?
Las convenciones de codificación son importantes y los desarrolladores de contenido Web por
varias razones:
1. Mejoran la legibilidad de los artefactos software.
2. Reducen el tiempo y el esfuerzo del entrenamiento
3. Lideran hacia la estandarización del comité de organización.
Nombres de Ficheros y sus Localizaciones
El nombrado de ficheros le da a los vendedores de herramientas y a los contenedores Web una
forma para determinar los tipos de ficheros e interpretarlos de la forma adecuada. La siguiente
tabla lista los sufijos de ficheros recomendados y sus localizaciones:
Tipo de Fichero Extensión Localización Recomendada
JSP .jsp <context root>/<subsystem path>/
Fragmento JSP .jsp <context root>/<subsystem path>/
Fragmento JSP .jspf <context root>/WEB-INF/jspf/<subsystem path>/
Cascading Style Sheet .css <context root>/css/
javascript .js <context root>/js/
página HTML .html <context root>/<subsystem path>/
fuente Web .gif, .jpg, etc. <context root>/images/
Tag Library Descriptor .tld <context root>/WEB-INF/tld/
Hay algunas cosas a observar en la tabla de arriba. Primero, <context root> es la raíz del contexto
de la aplicación Web (el directorio raíz dentro de un fichero .war). Segundo, se utiliza <subsystem
path> para proporcionar agrupación lógica refinada de contenidos estáticos y dinámicos de la
página Web. Para una pequeña aplicación Web, podría ser un string vacío.
Tercero, usamos el término fragmento JSP para referirnos a una JSP que se puede incluir en otra
JSP. Observa que en JSP 2.0, se utiliza el término "segmento JSP" en lugar de "fragmento JSP".
Los fragmento JSP pueden utiliza la extensión .jsp o .jspf, y deberían situarse en /WEB-INF/jspf o
con el resto del contenido estático, respectivamente. Los fragmentos JSP que no son páginas
completas siempre deberían utilizan la extensión .jspf y situarse en /WEB-INF/jspf. Cuatro, aunque
la especificación JSP recomienda .jspf y .jsp como extensiones posibles para fragmentos JSP,
recomendamos usar .jspf mientas .jsf se podría utilizar por la especificación JavaServer Faces_.
Finalmente, en general es una buena práctica situar los ficheros descriptores de librerías de
etiquetas y cualquier otro contenido no público bajo WEB-INF/ o un subdirectorio bajo éste. De esta
forma, el contenido será inaccesible e invisible para los clientes ya que el contenedor Web no
servirá ningún fichero bajo el directorio WEB-INF/.
Un nombre de fichero de bienvenida opcional, según se declara en el elemento welcome-file del
descriptor de despliegue (Web.xml), debería ser index.jsp si se va a producir contenidos dinámico,
o index.html si la página de bienvenida es opcional.
Cuando se internacionalizan ficheros JSP, recomendamos que agrupes las páginas en directorios
por su localidad. Por ejemplo, la versión US English de index.jsp aparecería bajo /en_US/index.jsp
mientras que la versión japonesa estará bajo /ja_JP/index.jsp.
Organización de Ficheros
Un fichero de código fuente bien estructurado no sólo es fácil de leer, también hace que la
información se pueda localizar más rápido dentro del fichero. En esta sección presentaremos las
estructuras para ficheros JSP y descriptores de librerías de etiquetas.
Ficheros JSP / Ficheros de Fragmento JSP
Un fichero JSP consta de las siguientes secciones en este orden:
1. Comentarios Iniciales
2. Directiva(s) JSP page
3. Directiva(s) tag library opcionales
4. Declaración(es) JSP opcionales
5. Código HTML y JSP
Comentarios Iniciales
Un fichero JSP o un fragmento de fichero empieza con un comentario del lado del servidor:
<%--
- Author(s):
- Date:
- Copyright Notice:
- @(#)
- Description:
--%>
Este comentario sólo es visible en el lado del servidor porque se elimina durante la traducción JSP.
Dentro de este comentario están los autores, la fecha, la nota de copyright de la revisión, un
identificador y una descripción sobre el JSP para los desarrolladores Web. La combinación de
caracteres "@(#) " es reconocida por ciertos programas para indicar el inicio de un identificador.
Aunque dichos programas se utilizan muy raramente, el uso de estos strings no hace nado.
Además, esta combinación algunas veces se le añade "$Id$" para que la información de
identificación se inserte automáticamente en el JSP por algunas versiones de programas de
control. La parte Description proporciona información concisa sobre los propósitos del JSP. No
debe ser mayor de un párrafo.
En algunas situaciones, se necesita retener los comentarios de inicio y propagarlos al lado del
cliente (visibles para los navegadores) para propósitos legales y de autenticidad. Esto se puede
conseguir dividiendo el bloque de comentarios en dos partes, primero el comentario del lado del
cliente:
<!--
- Author(s):
- Date:
- Copyright Notice:
-->
y luego un breve comentario del lado del servidor:
<%--
- @(#)
- Description:
--%>
Directiva(s) JSP Page
Una directiva page define atributos asociados con la página JSP en tiempo de traducción. La
especificación JSP no impone ninguna obligación sobre cuántas directivas page se pueden definir
en la misma página. Por eso los dos siguientes fragmentos de código son equivalentes (excepto en
que el primero de ello introduce dos líneas en blanco extras en la salida):
<%@ page session="false" %>
<%@ page import="java.util.*" %>
<%@ page errorPage="/common/errorPage.jsp" %>
Si la longitud de cualquier directiva, como una directiva page, excede de la anchura normal de una
página JSP (80 caracteres), se debe dividir en varias líneas:
<%@ page session="false"
import="java.util.*"
errorPage="/common/errorPage.jsp"
%>
En general, el segundo ejemplo es la opción preferida para definir la directiva page. Hay una
excepción cuando necesitamos importar varios paquetes Java en la página JSP, dejando un
atributo import muy largo:
<%@ page session="false"
import="java.util.*,java.text.*,
com.mycorp.myapp.taglib.*,
com.mycorp.myapp.sql.*, ..."
...
%>
En este escenario, se prefiere dividir la directiva page de esta forma:
<%-- all attributes except import ones --%>
<%@ page
...
%>
<%-- import attributes start here --%>
<%@ page import="java.util.*" %>
<%@ page import="java.text.*" %>
...
Observa que en general las sentencias import siguen las convenciones de codificación Java. Por
ejemplo, generalmente se podría aceptar que cuando se utilicen hasta tres clases del mismo
paquete, la sentencia import debería especificar las clases individualmente, en vez de su paquete.
Si son más de tres clases, es el desarrollador Web el que tiene que decidir si listar todas las clases
individualmente o utilizar la notación ".*". El primer caso, hace más fácil identificar una clase
externa, especialmente cuando intentamos localizar una clase o entender cómo el JSP interactúa
con el código Java. Por ejemplo, sin conocer los paquetes Java importados como se muestra
abajo, un desarrollador Web tendría que buscar en todos esos paquetes para localizar una clase
Customer:
<%@ page import="com.mycorp.bank.savings.*" %>
<%@ page import="com.thirdpartycorp.cashmanagement.*" %>
<%@ page import="com.mycorp.bank.foreignexchange.*" %>
...
En el último caso, es más difícil localizar las clases. En general, si una JSP tiene demasiada
sentencias import, es que contiene demasiado código Java. Una mejor opción sería usar más
etiquetas JSP.
Directiva(s) Tag Library Opcionales
Una directiva taglib declara las librerías de etiquetas usadas por el JSP. Un directiva corta se
declara en una sola línea. Si tenemos varias directivas taglib se deben almacenar juntas en la
misma localización dentro del cuerpo JSP:
<%@ taglib uri="URI1" prefix="tagPrefix1" %>
<%@ taglib uri="URI2" prefix="tagPrefix2" %>
...
Al igual que la directiva page, si la longitud de una directiva taglib excede la anchura de 80
caracteres, debemos dividirla en varias líneas
<%@ taglib
uri="URI2"
prefix="tagPrefix2"
%>
Sólo deberíamos importar librerías de etiquetas que realmente se van a utilizar en la página JSP.
Desde JSP 1.2, esta altamente recomendado utilizar la JSP Standard Tag Library en nuestra
aplicación Web para reducir la necesidad de scriptlets JSP en nuestras páginas. Las páginas que
usan JSTL son, en general, más fáciles de leer y de mantener.
Declaraciones JSP Opcionales
Las declaraciones JSP declaran métodos y variables pertenecientes a la JSP. Estos métodos y
variables no se diferencian de los declarados en el lenguaje Java, y por lo tanto se deberían seguir
las convenciones de codificación más importantes. Es preferible que las declaraciones estén n un
sólo bloque de declaración JSP <%! ... %>, para centralizar las declaraciones dentro de un área del
cuerpo JSP. Aquí tenemos un ejemplo:
Bloque de Declaraciones Disparatadas Bloque de Declaraciones Preferidas
<%!
<%! private int hitCount; %>
private int hitCount;
<%! private Date today; %>
private Date today;
...
<%! public int getHitCount() {
public int getHitCount() {
return hitCount;
return hitCount;
}
}
%>
%>
Código HTML y JSP
Esta sección contiene el cuerpo HTML del JSP y el propio código JSP, como expresiones JSP,
scriptlets e instrucciones Javabeans.
Descriptor de Librería de Etiquetas
Un descriptor de librería de etiquetas (TLD) debe empezar con la declaración XML apropiada y el
sentencia DTD correcta. Por ejemplo, un TLD JSP 1.2 debe empezar con:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/Web-jsptaglibrary_1_2.dtd">
Y debe ser inmediatamente seguido por un comentario del lado del servidor que liste el autor, la
fecha, el copyright, la información de identificación, y una breve descripción de la librería:
<!--
- Author(s):
- Date:
- Copyright Notice:
- @(#)
- Description:
-->
Las reglas y guías que rigen el uso de estos elementos son las las mismas que las definidas para
los ficheros JSP y los ficheros de fragmentos JSP.
El resto del fichero de la librería de etiquetas consta de los siguientes elementos y en este orden:
• Declaración opcional de un validador de la librería de etiquetas.
• Declaración opcional de los oyentes de eventos.
• Declaración de una o más etiquetas disponibles.
Se recomienda que siempre se añadan los siguientes sub-elementos opcionales para los
elementos de un TLD. Estos sub-elementos proporcionan espacio para que los diseñadores de
etiquetas documenten el comportamiento e información adicional sobre un TLD, y acercarlos a los
desarrolladores de componentes Web.
Sub-elemento Sub-elemento
Elemento TLD
JSP 1.2 Recomendado JSP 1.1 Recomendado
attribute (JSP 1.2) description
init-param (JSP 1.2) description
tag display-name, description, example name, info
taglib uri, display-name, description uri, info
validator (JSP 1.2) description
variable (JSP 1.2) description
Identación
Las identaciones se deberían rellenar con espacios en banco. Los "tabs" causan diferentes
interpretaciones en el espaciado de caracteres en diferentes editores y no se deberían utilizar para
identación dentro de una JSP. A menos que esté restringido por las herramientas IDE particulares,
una unidad de identación corresponde a 4 espacios. Aquí tenemos un ejemplo:
<myTagLib:forEach var="client" items="${clients}">
<myTagLib:mail value="${client}" />
</myTagLib:forEach>
Un continuación de identación alinea las líneas siguientes de un bloque con un punto apropiado de
la línea anterior. La continuación de identación es un múltiplo de las unidades normales de
identación (múltiples bloques de 4 espacios en blanco:
<%@ page attribute1="value1"
attribute2="value2"
...
attributeN="valueN"
%>
Identación de Elementos de Script
Cuando un elemento de Script JSP (como una declaración, un scriptlet o una expresión) no entran
en una sola línea, se aplican las convenciones de identación adoptadas del lenguaje de Script. el
cuerpo empieza en la misma línea de que el símbolo de apertura del elemento <%=, y desde una
nueva línea del símbolo de apertura <%=. Entonces el cuerpo se termina con un símbolo de cierre
del elemento (%>) en una línea separada. Por ejemplo:
<%= (Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
= Calendar.SUNDAY) ?
"Sleep in" :
"Go to work"
%>
Las líneas dentro del cuerpo que no contienen ningún símbolo de apertura o de cierre se preceden
con una unidad de identación normal. Para hacer que el cuerpo se identificable del resto del JSP.
Identación Compuesta con JSP, HTML y Java
La identación compuesta, para elemento JSP mezclados con código Java y plantillas de texto
(HTML), es necesaria para reducir el esfuerzo para comprender una fichero fuente JSP. Este es
porque la identación normal podría hacer que visualizar un fichero fuente JSP fuera una tarea
ardua. Como regla general, se aplica una unidad extra de identación normal a todo elemento
introducido dentro d otro. Observa que esto altera las identaciones de la salida final producida por
el lado del cliente. Sin embargo el navegador normalmente ignora las identaciones adicionales y no
tienen efecto sobre la salida renderizada. Por ejemplo, añadir más de un espacio en blanco antes
de una etiqueta <TABLE> no cambia la posición de la tabla. Por eso, aplicar esta convención para
identación la hace parecer más bonita:
<table>
<% if ( tableHeaderRequired ) { %>
<tr>
<th>Last Name</th>
<th>First Name</th>
</tr>
<% } %>
<c:forEach var="customer" items="${customers}">
<tr>
<td><c:out value="${customer.lastName}"/></td>
<td><c:out value="${customer.firstName}"/></td>
</tr>
</c:forEach>
</table>
que esta:
<table>
<% if ( tableHeaderRequired ) { %>
<tr>
<th>Last Name</th>
<th>First Name</th>
</tr>
<% } %>
<c:forEach var="customer" items="${customers}">
<tr>
<td><c:out value="${customer.lastName}"/></td>
<td><c:out value="${customer.firstName}"/></td>
</tr>
</c:forEach>
</table>
comentarios
Los comentarios se utilizan para describir información adicional o los propósitos del código
cercano. Aquí tenemos dos tipos para los ficheros JSP: uno para JSP y otro para comentarios del
lado del cliente.
Comentarios
Los comentarios JSP (también conocidos como comentarios del lado del servidor) sólo son visibles
en el lado del servidor (es decir, no se propagan al lado del cliente. Se prefieren los comentarios
puros JSP sobre los comentarios JSP con comentarios de scripts, ya que los primeros son menos
dependientes del lenguaje de script subyacente, y será más fácil evolucionarlos a JSP 2.0. La
siguiente tabla ilustra esto:
Línea Scriptlet JSP con comentario del lenguaje de scripting Comentario JSP puro
<% /** ... */ %>
single <% /* ... */ %> <%-- ... --%>
<% // ... %>
múltiple <% <%--
/* -
*
... ...
* -
*/ -- %>
%>
<%
//
//
...
//
%>
Comentarios del Lado del Cliente
Los comentarios del lado del cliente (<!-- ... -->) se pueden utilizar para anotar respuestas enviadas
al cliente con información adicional sobre las respuestas. No deberían contener información sobre
el comportamiento y al estructura interna de la aplicación en el servidor o del código generado en
las respuestas.
Normalmente se desaconseja el uso de comentarios del lado del cliente, ya que el cliente/usuario
no necesita leer este tipo de comentarios directamente para poder interpretar las respuestas
recibidas. Hay una excepción para autentificación y propósitos legales como una información de
copyright. Otra excepción es para que los autores de HTML utilicen una pequeña cantidad de
comentarios HTML para guiar la estructura del documento HTML, por ejemplo:
<!-- toolbar section -->
...
<!-- left-hand side navigation bar -->
...
<!-- main body -->
...
<!-- footer -->
...
Bloques de Comentarios Multi-línea
Un bloque de comentario multi-línea, tanto JSP como del lado del cliente, se decora con el carácter
guión "-". En la especificación XML, el string doble-guión "--" no está permitido dentro de un bloque
de comentarios XML. Así, por compatibilidad y consistencia con esta especificación, no debemos
utilizar dobles-guiones para decorar líneas de comentarios dentro de un bloque de comentarios de
varias líneas. La siguiente tabla ilustra esta preferencia usando un bloque de comentarios del lado
del servidor:
Preferido No-Compatible con XML
<!-- <!--
- line 1 -- line 1
- line 2 -- line 2
... ...
--> -->
Declaraciones JSP
Al igual que en las convenciones de código Java, las declaraciones de variables de los mismos
tipos deberían ir en línea separadas:
No recomendado Recomendado
<%! private int x; %>
<%! private int x, y; %>
<%! private int y; %>
Los JavaBeans no se deberían declarar ni ejemplarizar usando declaraciones JSP, sino que se
debería utilizar la etiqueta <jsp:useBean>.
En general, se desaconsejan las declaraciones JSP para variables, ya que usan el lenguaje de
script para mezclar la lógica de negocio y el código Java en un JSP que está diseñado para
propósitos de presentación, y debido a la sobrecarga del manejo del ámbito de las variables.
Scriptlets JSP
Siempre que sea posible, debemos evitar usar scriptlets JSP mientras que las librerías de etiquetas
proporcionen una funcionalidad similar. Esto hace que las páginas JSP sean más fáciles de leer y
de mantener, ayuda a separar la lógica de negocios de la lógica de presentación, y hará que
nuestras páginas evoluciones más fácilmente al estilo JSP 2.0. (JSP 2,0 soporta, pero no favorece
el uso de scriptlets). En los siguientes ejemplos, por cada representación de tipo de datos del
cliente se debe escribir un scriptlet:
customers como un array de Customers:
<table>
<% for ( int i=0; i<customers.length; i++ ) { %>
<tr>
<td><%= customers[i].getLastName() %></td>
<td><%= customers[i].getFirstName() %></td>
</tr>
<% } %>
</table>
customers como una Enumeration:
<table>
<% for ( Enumeration e = customers.elements();
e.hasMoreElements(); ) {
Customer customer = (Customer)e.nextElement();
%>
<tr>
<td><%= customer.getLastName() %></td>
<td><%= customer.getFirstName() %></td>
</tr>
<% } %>
</table>
Sin embargo, si se utilizara una librería común, hay una alta flexibilidad al utilizar los distintos tipos
de customers. Por ejemplo, en la Librería de Etiquetas Estándar de JSO, el siguiente fragmento de
código JSP soportará las representaciones de array y de Enumeration de customers:
<table>
<c:forEach var="customer" items="${customers}">
<tr>
<td><c:out value="${customer.lastName}"/></td>
<td><c:out value="${customer.firstName}"/></td>
</tr>
</c:forEach>
</table>
En el espíritu de adoptar el modelo del patrón de diseño Modelo-Vista-Controlador (MVC) para
reducir el acoplamiento entre la capa de presentación de la lógica de negocio, no se debería usan
scriptlets JSP para escribir lógica de negocio. En vez de eso, usaremos los scriptlets si necesario
transformar datos (también llamados "objeto valor") devueltos desde el procesamiento de las
solicitudes del cliente en un formato listo para el cliente apropiado. Incluso entonces, esto se podría
hacer mejor desde un servlet controlador o desde una etiqueta personalizada. Por ejemplo, el
siguiente ejemplo recoge los nombres de los clientes desde una base de datos y los muestra
directamente en el cliente:
<%
// NOT RECOMMENDED TO BE DONE AS A SCRIPTLET!

Connection conn = null;


try {
// Get connection
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("customerDS");
conn = ds.getConnection();
// Get customer names
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT name FROM customer");
// Display names
while ( rs.next() ) {
out.println( rs.getString("name") + "<br>");
}
} catch (SQLException e) {
out.println("Could not retrieve customer names:" + e);
} finally {
if ( conn != null )
conn.close();
}
%>
El siguiente fragmento de código JSP es mejor ya que delga la interacción con la base de datos en
una etiqueta personalizada myTags:dataSource que encapsula y oculta la dependencia del código
de la base de datos en su implementación:
<myTags:dataSource
name="customerDS"
table="customer"
columns="name"
var="result" />
<c:forEach var="row" items="${result.rows}">
<c:out value="${row.name}" />
<br />
</c:forEach>
result es una variable de scripting introducida por la etiqueta personalizada myTags:dataSource
para contener el resultado de recuperar los nombres de los clientes desde la base de datos. El
código JSP también se puede mejorar para generar distintos tipos de salidas (HTML, XML, WML)
basándose dinámicamente en las necesidades del cliente, sin impactar en el código final (para la
etiqueta dataSource). Una mejor opción es delegar esto en un servlet controlador que realice la
recuperación de los datos y proporcione el resultado al JSP a través de un atributo del ámbito de la
solicitud.
En Suma:
• Idealmente los scriptles JSP no deberían existir en un JSP para que el JSP sea independiente del
lenguaje de script, y se evite la implementación de la lógica de negocio dentro del JSP.
• Si no es posible, usaremos objetos valor (JavaBeans) para llevar información desde y hacia el lado
del servidor, y usaremos scriptles JSP para transformar estos objetos en salidas para el cliente.
• Utilizaremos etiquetas personalizadas siempre que sea posible para procesar la información en el
lado del servidor.
Expresiones JSP
Las expresiones JSO se deberían utilizar casi tan espartanamente como los scriptlets. Para ilustrar
esto, vemos los tres siguientes ejemplos que realizan tareas.
Ejemplo1 (con código Java explícito):
<%= myBean.getName()
%>

Ejemplo 2 (con etiqueta JSP):


<jsp:getProperty name="myBean"
property="name" />
Ejemplo 3 (con etiqueta JSTL):
<c:out value="${myBean.name}"
/>;
El ejemplo 1 asume que se declara una variable de script llamada myBean. Los otros dos ejemplos
asumen que myBean es un atributo que se puede encontrar usando PageContext.findAttribute(). El
segundo ejemplo también asume que myBean se introdujo en la página usando <jsp:useBean>.
De los tres ejemplos, el preferido es el de la etiqueta JSTL. Es casi tan corto como la expresión
JSP, casi tan fácil de leer y de mantener, y no trata con scriptlets Java (lo que requeriría que el
desarrollador Web estuviera familiarizado con el lenguaje y las llamadas al API). Además, hace que
la página se puede transportar fácilmente al estilo de programación JSP 2.0, donde esto se podría
conseguir simplemente escribiendo ${myBean.name} en la plantilla de texto. Independientemente
de la elección adoptada, debería hacerse de acuerdo con los desarrolladores Web y de forma
consistente en todos los JSPs producidos en el mismo proyecto. Deberíamos observar que el
ejemplo JSTL realmente es algo diferente en que obtiene el valor de myBean desde el contexto de
la página en lugar de desde una variable de script local.
Finalmente, las expresiones JSP tienen preferencia sobre los scriptlets JSP equivalentes lo que
tiene que ver con la sintaxis del lenguaje de script subyacente. Por ejemplo:
<%= x %>
Tiene preferencia sobre :
<% out.print( x ); %>
Espacios en Blanco
Los espacios en blanco mejoran la identación embelleciendo el código JSP para reducir el esfuerzo
de comprensión y mantenimiento. En particular se deberían insertar líneas y espacios en blanco en
varias localizaciones de un fichero JSP siempre que sea necesario.
Líneas en Blanco
Las líneas en blanco se utilizar para mejorar la legibilidad del JSP, aprovechando que no producen
efectos secundarios sobre la salida. En el ejemplo de abajo, se inserta una línea en blanco entre
dos expresiones JSP dentro de un bloque <PRE> HTML hace que se inserte una línea en blanco
extra en la salida HTML visible en el navegador del cliente. Sin embargo, si la línea en blanco no
está dentro de un bloque <PRE>, el efecto no es visible en la salida del navegador.
Sentencias JSP Salida HTML en el cliente
<pre>
Joe
<%= customer.getFirstName() %>
Block
<%= customer.getLastName() %>
</pre>
<pre>
<%= customer.getFirstName() %> Joe

<%= customer.getLastName() %> Block


</pre>
<%= customer.getFirstName() %>
Joe Block
<%= customer.getLastName() %>
Espacios en Blanco
Se debería insertar un espacio en blanco entre una etiqueta JSP y su cuerpo. Por ejemplo:
<%= customer.getName() %>
Es mejor que:
<%=customer.getName()%>
También debería haber espacios en blanco separando las etiquetas de comentario de los propios
comentarios:
<%--
- a multi-line comment broken into pieces, each of which
- occupying a single line.
--%>
<%-- a short comment --%>
Convenciones de Nombres
Aplicar convenciones de nombrado hace que los elementos de nuestros componentes Web sean
más fáciles de identificar, clasificar y coordinar. En esta sección, veremos estas convenciones
específicas para JSP.
Nombres JSP
Un nombre (fichero) JSP siempre debería empezar con una letra minúscula. El nombre podría
constar de varias palabras, en cuyo caso las palabras se situarán juntas y cada palabra comenzará
con una letra mayúscula. Un nombre JSP puede ser un simple nombre o una sentencia corta. Se
debe evitar un nombre JSP que sea sólo un verbo, ya que no proporciona suficiente información a
los desarrolladores. Por ejemplo:
perform.jsp
no es tan claro como
performLogin.jsp
En el caso de que un verbo forme parte de un nombre JSP, se debe utilizar su forma presente
como una acción:
showAccountDetails.jsp
se prefiere a :
showingAccountDetails.jsp
Nombres de Etiquetas
Abajo podemos ver las convenciones de manejadores de etiquetas y sus clases asociadas:
Nombre de
Descripción
Clase
XXX tag extra info (descendiente de javax.servlet.jsp.tagext.TagExtraInfo) XXXTEI
XXX tag library validator (descendiente de
XXXTLV
javax.servlet.jsp.tagext.TagLibraryValidator)
XXX tag handler interface (descendiente de
XXXTag
javax.servlet.jsp.tagext.Tag/IterationTag/BodyTag)
XXX tag handler implementation XXXTag
Además, los nombres de etiquetas no deben violar las convenciones de nombres de clases e
interfaces que se especifican en la convención de codificación de código Java.
Para distinguir una clase de una etiqueta importante de otras clases, se puede aplicar un sufijo de
paquete, de etiqueta o de librería de etiquetas al nombre de paquete de la clase, por ejemplo:
com.mycorp.myapp.tags.XXXTag
Nombres de Prefijos de Etiquetas
Un prefijo de etiqueta debería ser un nombre corto pero significativo, y el primer carácter debería
ser en minúsculas. Un prefijo de etiqueta no debería contener caracteres no-alfabéticos. Aquí
tenemos algunos ejemplo:
Ejemplo OK?
mytaglib no
myTagLib si
MyTagLib no
MyTagLib1 no
My_Tag_Lib no
My$Tag$Lib no
Páginas JSP con Sintaxis XML
JSP proporciona dos sintaxis distintas: una 'sintaxis estándar' para escribir páginas JSP y una
'sintaxis XML' para escribir JSP como un documento XML. Las JSPs que se escriben usando la
sintaxis estándar son conocidas como 'Páginas JSP'; y las que se escriben usando la sintaxis XML
son conocidas como "Documentos JSP'. Este artículo se dirige principalmente a las páginas JSP,
pero muchos de los conceptos se pueden aplicar también a los documentos JSP. Se espera que el
uso de documentos JSP se incremente según vaya creciendo la utilización de XML, y para corregir
esto la especificación JSP 2.0 presentará una sintaxis XML mucho más amigable.
Se debería observar que la sintaxis XML usada por el autor de JSPs es distinta y normalmente se
confunde con la vista XML de una página JSP. El autor de la página usa la sintaxis estándar o XML
para crear el JSP. Pero el contenedor la traduce a su vista XML, que se expone en la Tag Library
Validators.
Estructura de un Documento JSP
Los documentos JSP tienen las siguiente estructura básica:
<? xml version="1.0" ?>
<!--
- Author(s):
- Date:
- Copyright Notice:
- @(#)
- Description:
-->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:prefix1="URI-for-taglib1"
xmlns:prefix2="URI-for-taglib2"
version="1.2">
JSP Document ...
</jsp:root>
La primera línea es un Prólogo XML opcional que define la página como un documento XML.
Después del prólogo opcional vienen los comentarios del documento. El elemento <jsp:root> define
este como un Documento JSP y debe aparecer como el elemento raíz. Se debe importar el espacio
de nombres jsp, y todas las librerías de etiquetas se deben importar utilizando este elemento raíz.
El atributo version es obligatorio y especifica qué versión de JSP se está utilizando. El contenido
real del documento JSP aparece como sub-elementos del elemento <jsp:root>. Se deberían aplicar
las reglas de identación estándar de XML en todo el documento, usando 4 espacios en blanco
como una simple unidad de identación.
Un Documento JSP debe ser un documento XML bien-formateado, por eso algunos elementos,
como <% %> deben ser reemplazados por sus equivalentes XML, como <jsp:scriptlet />.
Comentarios XML
La especificación JSP no es muy clara sobre como se ponen en la salida los comentarios del estilo
XML, por eso para estar seguros de si se pretende que un comentario llegue al cliente, debería
encerrarse en un nodo <jsp:text>, de esta forma:
...
<jsp:text><![CDATA[
<!--
- Multiline comment
- to be sent to client.
-->
]]></jsp:text>
...
Código Java en Documentos JSP
Cuando se escribe código Java dentro de declaraciones, scriptlets, y expresiones, se debería
utilizar un elemento CDATA siempre que sea necesario para asegurar que nuestro código no
nombre la estructura del documento.
...
<jsp:scriptlet>
for( int level = 0; level < 3; level++ ) {
</jsp:scriptlet>
<tr>
<td>
<jsp:expression><![CDATA[
"<h" + level + ">Text</h" + level + ">"
]]></jsp:expression>
</td>
</tr>
<jsp:scriptlet>
}
</jsp:scriptlet>
...
Al contrario que los de la sintaxis estándar, se debe seguir las reglas de identación XML sin
importar los contenidos de un elemento.
Prácticas de Programación
En general, debemos evitar escribir código Java (declaraciones, scriptlets e expresiones) en
nuestras páginas JSP, por estas razones:
• Los errores de sintaxis en el código Java de un página JSP no se detectan hasta que la página se ha
desplegado. Por otro lado, los errores de sintaxis en librerías de etiquetas y servlets se detectan con
anterioridad.
• El código Java en páginas JSP es difícil de depurar.
• El código Java en páginas JSP es difícil de mantener, especialmente para los autores de la página
que podrían no ser expertos en Java.
• Es una práctica generalmente aceptada no mezclar lógicas de negocio complejas con la lógica de
presentación. Las páginas JSP se crearon principalmente para la lógica de presentación.
• El código que contenga código Jaba, HTML y otras instrucciones de script puede ser muy difícil de
leer.
• JSP 2.0 desaconseja los scriptlets en favor de un lenguaje de expresiones más simple. Será más
fácil evolucionar nuestras páginas hacia el estilo de programación JSP 2.0 si no usamos código Java
en nuestras páginas.
Inicialización de JavaBeans
JSP proporciona un elemento conveniente para inicializar todas las propiedades identificadas por
un PropertyDescriptor de un JavaBean, por ejemplo:
<jsp:setProperty name="bankClient" property="*"/>
Sin embargo, esto se debería utilizar con cuidado. Primero, si el bean tiene una propiedad,
digamos amount, y no existe dicho parámetro (amount) en el objeto ServletRequest actual o el
valor del parámetro es "", no se hace nada: la página JSP ni siquiera usará null para seleccionar
esa propiedad particular del bean. Pero, si el valor ya está asignado a amount en el bean
bankClient, no le afecta. Segundo, las propiedades no elementales que no tienen definidos
PropertyEditors podrían ni ser inicializadas implícitamente desde un valor String del objeto
ServletRequest y se podría necesitar una conversión explícita. Tercero. usuarios malintencionados
pueden añadir parámetros adicionales a la solicitud, y seleccionar propiedades no deseadas en el
bean, si la aplicación no está cuidadosamente diseñada.
Si aún así preferimos usar property="*" en la etiqueta jsp:setProperty para producir el código
anterior, recomendamos que añadas un comentario precediendo a la etiqueta jsp:setProperty
indicando los parámetros que deben estar presentes en el objeto ServletRequest para inicializar el
bean. Por eso, en el siguiente ejemplo, a través del comentario, sabemos que necesitamos los
parámetros firstName y lastName para inicializar el bean bankClient:
<%--
- requires firstName and lastName from the ServletRequest
--%>
<jsp:setProperty name="bankClient" property="*" />
Objetos Implícitos de JSP
Es preferible el uso de objetos implícitos JSP para obtener referencias a estos objetos en vez de
utiliza llamadas al API. Por eso, en lugar de utilizar:
getServletConfig().getServletContext().getInitParameter("param")
para acceder al parámetro de inicialización proporcionado por el ejemplar ServletContext, podemos
hacer uso del objeto implícito disponible:
application.getInitParameter("param")
En el caso de que sólo se saque el valor de un parámetro de inicialización, sería incluso mejor
utilizar JSTL para acceder a dicho parámetro:
<c:out value="${initParam['param']}" />
Entrecomillado
Se adopta el uso de entrecomillado uniforma. Se deberían utilizar comillas dobles (") en lugar de
dos caracteres apóstrofe (').
Entrecomillado No-Uniforme Entrecomillado Preferido
<%@ page import='javabeans.*'%> <%@ page import="javabeans.*" %>
<%@ page import="java.util.*" %> <%@ page import="java.util.*" %>
Hay una excepción en la que se necesitan los apóstrofes, por ejemplo, cuando se necesitan las
dobles comillas dentro del lenguaje de script:
<jsp:include page='<%= getFoodMenuBar("Monday") %>' />
Usar Etiquetas Personalizadas
Si una etiqueta personalizada no tiene contenido en el cuerpo, el contenido debería declararse
explícitamente como vacío (en vez del valor por defecto "JSP"), como en este descriptor de librería
de etiquetas
<tag>
<name>hello</name>
<tag-class>com.mycorp.util.taglib.HelloTagSupport</tag-class>
<body-content>empty</body-content>
...
</tag>
Esto le dice al contenedor JSP que el contenido del cuerpo debe estar vacío en vez de contener
cualquier sintaxis JSP. El efecto es eliminar la asignación innecesaria de recursos para analizar los
contenidos vacíos de un cuerpo.
Las etiquetas vacías se deberían escribir como elementos cortos de XML, en vez de usar
elementos XML de apertura y de cierre, para así mejorar la legibilidad, por eso es preferible
<myTag:hello /> que <myTag:hello></myTag:hello>.
Uso de TagExtraInfo y TagLibraryValidator
Algunas veces, las formas válidas para usar una librería de etiquetas no se pueden expresar
usando sólo TLD. Entonces, se debería escribir una clase TagExtraInfo o una clase
TagLibraryValidator y deberíamos registrarlas en el TLD para que poder capturar en tiempo de
traducción los errores en la librería de etiquetas.
Usar JavaScript
El código JavaScript debería ser independiente de las características particulares de los distintos
tipos de navegadores para poder ejecutar los scripts de la forma apropiada.
Cuando tenga sentido, es una buena idea mantener el código JavaScript en ficheros individuales
separados de los cuerpos JSP, y usar sentencias como esta para importar el código JavaScript en
las páginas JSP:
<script language=javascript src="/js/main.js">
Esto mejora la oportunidad de reutilización del código JavaScript, mantiene el comportamiento
consistentes del código JavaScript entre varios JSPs, y reduce la complejidad de las páginas JSP.
Hojas de Estilo en Cascada (CSS)
Debemos usar hojas de estilo en cascada para centralizar las características comunes de
cabeceras, tablas, etc. Esto mejorará la consistencia de la presentación para los usuarios y reduce
el mantenimiento y el tamaño del código de las páginas JSP. Por eso en lugar de embeber la
información de estilo en las etiquetas HTML como estas:
<H1><FONT color="blue">Chapter 1</FONT></H1>
...
<H1><FONT color="blue">Chapter 2</FONT></H1>
...
Definimos información de estilo en una sola hoja de estilo myJspStyle.css que contiene:
H1 { color: blue }
Y aplicamos la hoja de estilo a la página JSP:
<link rel="stylesheet" href="css/myJspStyle.css" type="text/css">
...
<H1>Chapter 1</H1>
...
<H1>Chapter 2</H1>
...
Usar Patrones de Vistas Compuestos
Cuando un JSP requiere una estructura compleja que también podría repetirse en otras JSPs, una
forma de manejar esto es dividirla en partes, usando el patrón Composite View. Por ejemplo,
algunas veces una JSP tiene la siguiente representación:
header
main body

menu bar

footnote
footer
De esta forma, este JSP compuesto se puede dividir en diferentes módulos, cada uno realizado en
un JSP separado. Los JSPs constituyente se puede situar en sus localizaciones apropiadas en el
JSP compuesto, usando etiquetas JSP include en tiempo de compilación o tiempo de solicitud. En
general, cuando se utiliza la directiva include estática para incluir una página que no va a ser
solicitada por sí misma, debemos recordar la utilización de la extensión .jspf y situar el fichero en el
directorio /WEB-INF/jspf/ de la aplicación Web. Por ejemplo:
<%@ include file="/WEB-INF/jspf/header.jspf" %>
...
<%@ include file="/WEB-INF/jspf/menuBar.jspf" %>
...
<jsp:include page="<%= currentBody %>" />
...
<%@ include file="/WEB-INF/jspf/footnote.jspf" %>
...
<%@ include file="/WEB-INF/jspf/footer.jspf" %>
...
Otras Recomendaciones
En este artículo se han presentado un conjunto de convenciones de codificación para producir
código JSP y artefactos Web más fáciles de mantener y más consistentes. Hay otras buenas
prácticas que podemos utilizar para conseguir mejorar este objetivo. Por ejemplo, la especificación
JSP 1.2 recomienda:
• Definir Nuevos Objetos Implícitos
• Acceder a Información Específica-de-Vendedor
• Personalizar una Librería de Etiquetas
Además, Java BluePrints ofrece mejores prácticas a mayor escala, como usar el patrón Model-
View-Controller

TEMA 4 Un ejemplo de actualización de base de datos.

TEMA 5 Ejercicios de Aplicación

Con base en el siguiente modelo relacional:

1.Elabore una ventana en Java que liste los autores con sus respectivos países.
2.Elabore una ventana en Java que liste los libros con su respectiva editorial. Incluya un menú
con una opción que permita abrir otra ventana que liste los autores del libro escogido.

Das könnte Ihnen auch gefallen