¿Que es JSP?

JSP no es más que una página html con programación java por en medio.

Para que el motor de java interprete el contenido, debemos indicar que clase de código estamos introduciendo, asi pues

<%@ page language='java' contentType="text/html" %>

indica que vamos a introducir texto html.

A la hora de introducir el lenguaje java, seguimos el mismo ejemplo:

 <%@ import file='cabecera.jsp'%> 

Con esto ya podemos empezar a interpretar una página JSP.

			
<%@ 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
<% } %>

			

Este es un codigo sencillo que muestra en pantalla el numero de veces que accedemos a la página. Como podemos observar, de este modo disponemos de mucha más flexibilidad a la hora de elaborar una pagina web.

¿Cómo funciona?

JSP funciona de forma similar a java, requiere de una maquina virtual java para poder ser interpretado, pero permite tambien ejecutar código HTML o cualquier otro lenguaje de marcas, proporcionando así una gran flexibilidad.

Para que el motor interprete correctamente el lenguaje, se lo indicamos: por ejemplo contentType="text/html" indica que se utiliza texto html. para realizar cualquier comando en java, este se ejecuta siempre comenzando por <% y terminando por %>. A esto se le llama scriptlet

Las directivas son como los scriptlet, con la diferencia de que se cargan antes, para indicar que un fragmento de código es una directiva y no un scriptlet, utilizaremos <@%.

A partir de este momento, vamos a 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.

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.

.

<%! 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:


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 bean 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 el bean 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 el bean 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
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 resultados de la quiniela.

Páginas dinámicas.

Como para hacer páginas estáticas, ya tenemos el HTML propiamente dicho, vamos a meter un poco de 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.


<%@ 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, 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.java: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.

A modo de despedida

Como hemos podido ver, es sencillo dominar JSP si se domina el lenguaje java, simplemente, debemos incluirlo dentro de nuestra pagina web y ejecutarlo dentro de nuestra máquina virtual java.

Espero que esta wiki os pueda ser de ayuda