Java Server Pages (JSP) : Servicios de Internet
Java Server Pages (JSP) : Servicios de Internet
Departamento de
Ingeniería Telemática
1.1 Introducción
JSP (Java Server Pages) es una tecnología de Oracle1, con ciertas similitudes con PHP: el origen de las vistas de la
aplicación web que se le presentan al usuario son páginas HTML, que tienen en su interior algunos elementos
propios de la tecnología JSP (por lo que se llaman páginas JSP) que deben ser traducidos a HTML antes de que el
resultado sea enviado al cliente. Es decir, debe haber una entidad que procese la página JSP antes de enviársela
al cliente, y esa entidad suele denominarse JSP Engine2. Por tanto, al igual que PHP, esta tecnología resulta
apropiada para el desarrollo de páginas mayormente estáticas, páginas que serán personalizadas justo antes de
su envío añadiendo los datos apropiados para responder a la consulta, materializándose una separación clara
entre la parte estática (HTML) y la dinámica (JSP).
Por supuesto, JSP puede ser empleado para que el cliente pida las páginas JSP directamente. El servidor web
reconocería una determinada extensión y le pasaría la solicitud al JSP Engine. Sin embargo, lo más habitual es
que JSP sea empleado en una aplicación web siguiendo el modelo MVC, es decir, JSP se emplearía para
implementar las vistas de la aplicación. En este enfoque, cada solicitud sería procesada por un servlet, que
actuaría de controlador, extrayendo los parámetros de la solicitud, identificando el objetivo de la consulta, y
coordinando a los demás componentes para resolverla. Por ejemplo, como se observa en la Figura 1:
1
Con los mismos términos en cuanto a los derechos de uso que los servlets.
2
El TOMCAT también incluye un JSP Engine, por lo que puede gestionar tanto servlets como páginas JSP.
1
• Tras identificar el motivo y los elementos relevantes de la consulta (parámetros, ficheros enviados…), el
controlador instanciaría una bean Java para resolverla, que, en esencia, no es más que un objeto de una
clase Java que tiene una función muy específica, que cumple una serie de requisitos que veremos luego, y
que ofrece una interfaz para interactuar con ella. Esa bean es la que desempeña el papel de Model en
nuestra figura, es el componente software que conoce el modelo de datos de la aplicación, también
conocido como lógica de negocio. Esa bean sería la apropiada para resolver la consulta solicitada, es decir,
para obtener los datos de la respuesta de la consulta dados los parámetros de la solicitud. Habría, por
tanto, un conjunto de beans, cada una resolviendo una consulta específica, para lo cual posiblemente se
tendrían que comunicar con un servidor de aplicaciones a cargo de las bases de datos donde se almacena
toda la información. En todo caso, es importante resaltar que la bean se limitaría a obtener los datos de la
respuesta, nada más, tras lo cual devolvería el control y quedaría a la espera de que alguna otra entidad le
pidiese esos datos.
• Tras instanciar la bean adecuada, el controlador transferiría el control a la página JSP apropiada para
presentar la respuesta dada la información de la solicitud. Es decir, cada página JSP no sólo es una página
específica para esa consulta, sino que también sería la idónea dados otros condicionantes, por ejemplo, el
tamaño de pantalla del dispositivo empleado para la petición. Así pues, habría un repertorio de páginas
JSP, cada una adecuada a un escenario, y el controlador sería el encargado de seleccionar la más
apropiada. Esa página JSP, haciendo uso de los mecanismos que describiremos a continuación, solicitaría
a la bean los datos necesarios para particularizar la plantilla de la página de acuerdo a la solicitud.
Como vemos, este enfoque siguiendo el patrón MVC favorece la reutilización de componentes software, ya que
las beans son piezas de código que se encargan de calcular/almacenar/servir los datos para alimentar la página
JSP, pero son independientes de ésta, y podrían ser fácilmente reutilizados en otras aplicaciones.
Este enfoque de distribución de funcionalidades también tiene la ventaja adicional de favorecer la distribución
de responsabilidades. Es decir, las tres tareas pueden ser completamente separadas y asignadas a equipos
especializados en cada una en particular (comunicaciones web, lógica de negocio, y vistas de los resultados),
trabajando cada uno de los equipos en un conjunto diferente de ficheros con un alto grado de desacoplamiento.
Cada equipo no tendría por qué tener apenas conocimiento de las tecnologías e interioridades de los ficheros
creados por los otros equipos.
• <%= à Se trata una expresión, que se sustituye por el valor resultante de su evaluación. Por ejemplo:
<%= fontSize %>
• <% à Se trata de sentencias Java propiamente dichas, aunque cada una de ellas no tienen que estar
necesariamente contenida dentro de las marcas que la inician. Por ejemplo:
<% fontSize++; %>
2
<%@ page pageEncoding="UTF-8"%>
<%! int fontSize=1; %>
<html>
<head> <title>Ejemplo bucle</title> </head>
<body>
<% while (fontSize <= 3) { %>
<span style=’font-size: <%= fontSize %>px’>
Hola Mundo
</span><br>
<% fontSize++; %>
<% } %>
</body>
</html>
Para comprender de forma sencilla cómo esta página es procesada antes de su envío, y el resultado que
produce este procesado, es bastante útil trasladar todo al dominio de Java y entender que cualquier línea HTML,
es decir, fuera de los scritps, es imprimida como si fuera el contenido de un System.out.println(). Por tanto, la
página JSP de la Figura 3 se traduciría directamente al fragmento Java de la Figura 2.
int fontSize=1;
System.out.println(“<html> “);
System.out.println(“<head> <title>Ejemplo bucle</title> </head>”);
System.out.println(“<body>”);
while (fontSize <= 3) {
System.out.println(“<span style=’font-size: ”+fontSize+"px’>”);
System.out.println(“Hola Mundo”);
System.out.println(“</span><br>”);
fontSize++;
}
System.out.println(“</body>”);
System.out.println(“</html>”);
Figura 2. Código Java generado tras el procesado de la página JSP
Y eso es esencia lo que ocurre. Antes de ser enviada al cliente, una página JSP es traducida a un programa Java.
Si ahora cambiamos el System.out.println() por out.println(), siendo out un objeto de la clase PrintWritter, ya
podemos adivinar a qué clase de programa Java se traduce la página JSP. Exactamente, una página JSP se
traduce a un servlet, cuya ejecución genera la página HTML (u otra página de otro tipo) que se le envía al cliente.
Por tanto, cuando en su momento dijimos que el controlador transfería el control a la página JSP, eso se traduce
en que el servlet del controlador transfiere el control al servlet generado a partir de la página JSP. Por tanto, JSP
es, en esencia, una extensión/abstracción de la tecnología de servlets, los usa por abajo, liberando al creador de
páginas web de la necesidad de conocer la mayor parte de los detalles relacionados con Java.
El servlet resultante (cuyo código sería equivalente al mostrado en la Figura 2) sería generado automáticamente
y compilado la primera vez3 que se solicitara la página JSP, y, a partir de ahí, se ejecutaría cada vez que en una
solicitud se transfiriese el control a la página JSP. El resultado de su ejecución (la salida por pantalla) sería lo que
se le enviaría al cliente (lo que se puede ver en la Figura 4).
Podemos observar, por tanto, que hay 2 fases en la ejecución de una página JSP, compilación y ejecución, que
pueden dar pie a 2 tipos de errores, tanto en tiempo de compilación como en tiempo de ejecución. Esto dificulta
la depuración, ya que las líneas de los mensajes de error hacen referencia a las líneas del servlet generado
automáticamente, no a las de la página JSP.
3
También es posible que el JSP Engine lo compile inicialmente, ahorrándose ese retraso en la primera solicitud.
3
<html>
<head><title>Ejemplo bucle</title></head>
<body>
<span style=’font-size: 1px> Hola Mundo</span><br>
<span style=’font-size: 2px> Hola Mundo</span><br>
<span style=’font-size: 2px> Hola Mundo</span><br>
</body>
</html>
Figura 4. Resultado de la ejecución de la página JSP procesada
Por supuesto, la Figura 3 sería una página JSP sintácticamente válida, pero no es, ni de lejos, lo que estamos
buscando para lograr los objetivos que mencionamos en la anterior sección, ya que obliga al creador de páginas
JSP (el experto en las vistas de la aplicación) a saber Java, y no separa realmente la presentación del procesado.
Pero antes de presentar una página que sí satisfaga nuestro objetivo, presentemos brevemente el concepto de
bean, y crearemos una bean y un controlador para componer junto a nuestra página JSP un sencillo ejemplo.
package Beans;
public class AuxBean implements Serializable {
private String msg;
public AuxBean() {
msg = “hola mundo”;
}
public void setMsg (String m) {
this.msg = m;
}
public String getMsg () {
return msg;
}
}
4
La bean debe ser serializable para que un objeto de su clase pueda ser guardado a disco y luego recuperado, y preservar
así el estado de la bean si se necesitase.
4
En nuestro escenario, la variable msg es el único componente del modelo de datos, y su valor es inicializado en
la propia bean en su constructor, pero podría haber sido leído de un servidor de aplicaciones.
El objetivo de las estrictas reglas de las beans es permitir fácilmente que puedan ser creadas y llamadas por un
código generado automáticamente, situación donde no caben las ambigüedades.
1.4 El controlador
Como dijimos en la introducción, el papel del controlador de la aplicación web es desempeñado por un servlet,
que realiza el control del flujo del servicio, lo cual implica las siguientes tareas:
• Leer los parámetros de la solicitud.
• Identificar la consulta que se solicita al servicio.
• Instanciar la bean (crear un objeto de su clase) que debe obtener y almacenar los datos necesarios para
resolver esa consulta.
• Transferir el control a la página JSP que debe mostrar el resultado.
En la Figura 6 podemos ver un ejemplo de un controlador para nuestro caso. Como vemos, para simplificar, no
hay parámetros, ni necesidad de identificar la consulta. El servlet sólo crea la bean y se la pasa a la página JSP
como un atributo del objeto request, dándole el nombre “sintBean”. Luego transfiere el control a la página JSP.
import Beans.AuxBean;
public class Controlador extends HttpServlet {
protected void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
AuxBean laBean = new AuxBean();
request.setAttribute("sintBean", laBean);
ServletContext sc = request.getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher("/pag.jsp");
rd.forward(request, response);
}
}
5
En esencia, esta primera versión es igual de inapropiada que la de la Figura 3, ya que está plagada de código
Java, y no hace uso de la bean “sintBean” como tal bean, sino que el uso que se hace de ella es el mismo que se
haría de un objeto Java cualquiera, sin aprovechar las ventajas que aporta fruto de su condición de bean.
• <jsp:useBean> à para declarar que se va a usar una bean recibida en el objeto request, asociándola a un
identificador.
<jsp:useBean id=“ident” class="Beans.AuxBean" >
En la Figura 8 puede observarse esta segunda versión de la página JSP que emplea los citados tags para declarar
que va a usar la bean de la Figura 5, y para posteriormente leer el valor de la propiedad “msg” (el código
generado automáticamente al compilar la página JSP hará uso del getter de la citada variable).
Sin entrar a detallar el repertorio de nuevos tags definidos por esta tecnología, que no es el objeto de este
documento, sí es interesante destacar que se trata de un mecanismo extensible. Es decir, JSP define un
procedimiento para que terceras partes creen sus propios tags, asociándole el comportamiento Java al que
debe ser traducido cada nuevo tag allí donde se encuentre éste en el proceso de traducción a su servlet.
6
1.7 La página JSP (tercera y última versión): el lenguaje EL y la librería JSTL
En esta tercera y última versión introducimos el lenguaje EL, un lenguaje de expresiones para acceder de forma
más sencilla a las variables privadas de la bean, tanto para mostrar su valor en la página como para involucrarlas
en expresiones lógicas. Su sintaxis es relativamente simple:
• Las expresiones en las que intervienen las variables privadas de una bean se rodean de unas llaves
precedidas por un ‘$’ ( por ejemplo, ${expresion}).
• Dentro de una expresión, y dada una bean que se recibe en el objeto request, cuyo identificador es
“nombreBean” (el que se le ha asignado al guardarla como atributo del objeto request), y que tiene una
propiedad privada “nombreVariable” accesible mediante un getter, es posible acceder a ella simplemente
con la expresión “nombreBean.nombreVariable”, sin necesidad siquiera de haber incluido antes un tag
<jsp:useBean>. Por tanto:
o ${nombreBean.nombreVariable} à evalúa al valor de la variable
o ${nombreBean.nombreVariable > 0} à evalúa al valor lógico que corresponda según el valor de la
variable nombreVariable. Dentro de las expresiones es posible emplear un conjunto de palabras clave
(como and y or) para construir expresiones más útiles.
Además, como hemos dicho en la sección anterior, en JSP es posible extender el repertorio de tags básico del
lenguaje. Mediante la directiva de compilación taglib se incorporaría a una página ese conjunto de nuevos tags,
y se le asociaría un prefijo, como se puede ver en la siguiente línea, que incorpora una conocida librería creada
por la propia compañía Oracle, la JSP Standard Tag Library, que proporciona una serie de tags que implementan
la funcionalidad de varios constructores típicos de los lenguajes de programación: if, forEach…
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
Añadiendo esta librería (y copiando al WEB-INF/lib del proyecto los ficheros jar correspondientes5), podríamos
incorporar a nuestra página un fragmento de código como el siguiente:
<c:if test ="condicion_logica">
<jsp:forward page= “PaginaDeError” />
</c:if>
Si la condicion_logica (expresada mediante el lenguaje EL) es cierta, se incluye en la página el contenido del tag
<c:if>, en este caso el tag <jsp:forward> que hace que el control se transfiera a “PaginaDeError”. Con todo esto,
la Figura 9 recoge la tercera y última versión de nuestra página JSP, que usa tanto el tag <c:if> de la librería JSTL
(para bifurcar a una página de error si la variable “msg” de la bean no tiene valor) como el lenguaje de
expresiones EL (para mostrar su valor si lo tiene).
5
Los ficheros jakarta.servlet.jsp.jstl-2.0.0.jar y jakarta.servlet.jsp.jstl-api-2.0.0.jar, que pueden ser descargados de la página
https://repo1.maven.org/maven2/jakarta/servlet/jsp/jstl/jakarta.servlet.jsp.jstl-api/2.0.0
7
Sin entrar en una descripción exhaustiva de los distintos tags incorporados en la librería JSTL, sí nos gustaría
presentar otro que permite implementar un comportamiento no posible con los tags básicos. Se trata del tag
<c:forEach>, que permite implementar un bucle for con los distintos valores de una variable privada de tipo lista
de la bean. Es decir, si la variable privada está definida en la bean sintBean, por ejemplo, como:
private List<String> arrayColores = Arrays.asList("rojo", "verde", "azul");
Con este ejemplo cerramos este repaso ilustrativo (que no exhaustivo) de la tecnología JSP, presentando la
Figura 10, que recoge las distintas funcionalidades de una herramienta como el Apache TOMCAT:
• Un servidor web tradicional, capaz de servir páginas HTML estáticas.
• Un Servlet Engine (llamado Catalina), capaz de gestionar la ejecución de servlets.
• Un JSP Engine (llamado Coyote), capaz de traducir las páginas JSP a servlets, para su posterior gestión por
parte del Servlet Engine.
Y simplemente recordar que, si bien nos hemos centrado en páginas JSP que se traducen a páginas HTML
(directiva contentType="text/html” en la primera línea), nada nos impide enviar, por ejemplo JSON (usando la
directiva contentType="application/json”) y entregando en la página contenido JSON (generado, por ejemplo,
usando una bean, el lenguaje EL y la librería JSTL).