Pasar datos entre JSPs y Servlets. Page, Request, Session y Application scope

De ChuWiki

Veamos aquí cómo pasar datos entre las páginas JSP y los Servlets. Aprovechamos para comentar los cuatro tipos posibles de scope (alcance) de las variables.


Page Scope[editar]

Son variables que solo se ven dentro de nuestro JSP o Servlet mientras se está ejecutando. Una vez construída y enviada la respuesta al navegador, desaparecen. Su única utilidad es ayudarnos a construir la página que queremos mostrar en el navegador. Dentro del JSP serían variables normales de JSP

<% int variable = 33; %>
...
<p>La variable vale <%= variable %></p>

y dentro de un Servlet no serían más que variables locales de nuestros métodos doGet() o doPost().

public class UnServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
       int variable = 33;
       ...
       resp.getWriter().print("<p> La variable vale " + variable + "</p>");


Request Scope[editar]

Estas variables son más útiles. Las guardamos en la petición que nuestro JSP/Servlet van a hacer a otro JSP/Servlet de nuestra aplicación, y este segundo JSP/Servlet puede recogerlos para hacer cosas con ellas.

Dentro de un JSP tenemos predefinido un objeto request, y en él podríamos fijar estas variables con setParameter() o con setAttribue(). y obtener los valores con los getParameter() o getAttribute().


request : set y get parameter[editar]

En principio no debemos usar este método. Está reservado para los form de html de nuestras páginas jsp. Cuando pulsemos el botón "submit" del formulario, él se encargará de rellenar los setParameter()

<form action="destino.jsp">
<input type="text" name="variable" />
<input type="submit value="Enviar" />
</form>

En el formulario anterior, al pulsar el submit "Enviar", automáticamente se hará un request.setParameter("variable", valor en la caja de texto) que luego podrá leer nuestra página de destino (destino.jsp en nuestro ejemplo) o el servlet. "variable" es el name del input type="text". Se guardará uno por cada input que tengamos en el form, cada uno con el nombre que diga su atributo "name".

En la página jsp de destino podemos recoger los valores del formulario de esta forma

<% String variable = request.getParameter("variable"); %>
<p>Me han pasado <%= variable %></p>

y en un servlet lo recogeríamos del parámetro HttpRequest que nos pasan

public class UnServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
       String variable = req.getParameter("variable");
       ...
       resp.getWriter().print("<p> La variable vale " + variable + "</p>");

Un detalle a tener en cuenta es que estos "parameter" sólo pueden guardar valores de tipo "String".


request : set y get Attribute[editar]

Dentro de request, los attribute son lo que nosotros como programadores podemos usar a gusto. Podemos guardar y recibir cualquier Object java que queramos sin más que ponerles un nombre. Sin embargo, el request desaparece en cuanto terminamos de procesar la página/Servlet actual, así que la única forma de pasar estos attributes a la siguiente es haciendo un fordward() desde nuestro request. Por ejemplo, en una página jsp podemos poner

<%  request.setAttribute("unEntero", new Integer(22));
    request.getRequestDispatcher("destino.jsp").forward(request, response); %>

y en destino.jsp recibiríamos unEntero de esta forma

<p>Me ha llegado <%= request.getAttribute("unEntero") %></p>

Igualmente, desde un Servlet, poddríamos hacer la siguiente redirección

public class UnServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
       req.setAttribute("unEntero", new Integer(22));
       ...
       resp.getRequestDispatcher("destino.jsp").forward(req, resp);

y en un Servlet recogeríamos estos attribute, vengan de un jsp o de otro servlet, así

public class UnServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
       Integer variable = (Integer)req.getAttribute("unEntero");
       ...
       resp.getWriter().print("<p> La variable vale " + variable + "</p>");

Session scope[editar]

Las variables Session scope se mantienen durante lo que se conoce como una sesión. Cuando un usuario visita nuestra aplicación por primera vez, automáticamente se crea una sesión para ese usuario. Esta sesión suele estar abierta mientras el usuario va navegando por las páginas de nuestra aplicación y desaparece cuando el usuario deja de navegar por nuestra aplicación durante un tiempo predeterminado.

Dicho de otra forma, cualquier valor que guardemos en la sesión del usuario, sólo será visible por las páginas que visite ese usuario y mientras el usuario esté activo. Son las variables típicas donde guardar si un usuario ha entrado en sesión con un usuario y password, su nombre, su carrito de la compra si nuestra aplicación es de comercio electrónico, etc.

En una página JSP guardaríamos los objetos java que queramos por medio de la variable session ya predefinida

<% session.setAttribute("variable", new Integer(22));

y en otra página JSP lo obtendríamos con

<p>Me ha llegado <%= session.getAttribute("variable") %></p>

Y en un Servlet, igual de fácil obteniendo la session del request que nos llega como parámetro

public class UnServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
       req.getSession().setAttribute("variable", new Integer(22));
       ...

y para leer

public class UnServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
       Integer variable = (Integer)req.getSession().getAttribute("variable");
       ...
       resp.getWriter().print("<p> La variable vale " + variable + "</p>");

Application scope[editar]

Estas variables son válidas para la aplicación. Permanecen hasta que repleguemos nuestra aplicación del servidor o echemos el servidor abajo. Son compartidas para todos los usuarios que visiten nuestra página web.

Dentro de un JSP podemos fijarlas o leerlas con la variable application que viene predefinida en cualquier JSP, usando los conocidos métodos setAttribute() y getAttribute().

<% // Para fijar una variable en un jsp
   application.setAttribute("variable", new Integer(22));

   // Para leerla en otro o el mismo JSP
   Integer valor = (Integer)application.getAttribute("variable");
%>

Y en un Servlet, se puede acceder obteniendo el ServletContext y llamando a sus métodos setAttribute() o getAttribute()

public class UnServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

       // Para fijar la variable
       getServletContext().setAttribute("PI", new Double(3.1416));
       ...
       // Y para leerla en otro o el mismo servlet
       Double pi = (Double)getServletContext().getAttribute("PI");


jsp:useBean[editar]

Ya hemos visto como guardar variables en distintos sitios para pasarlas de un jsp/servlet a otro jsp/servlet y si queremos que esta variable sólo sea válida durante el paso de una página a otra (request), para un usuario en cualquier página (session) o para todos los usuarios mientras el servidor siga levantado (application).

Imagina ahora que estamos haciendo una aplicación que lleva un listado de personas. Esas personas tienen varios atributos como nombre, apellido, teléfono, dirección, etc, etc. Puede ser un poco tedioso y sobre todo poco elegante tener que meter todos esos atributos uno a uno en los sitios (request, session, application) que necesitemos. Una solución más elegante es hacer un bean Persona con esos atributos. Algo como esto (solo un par de atributos para simplificar)

package com.chuidiang.ejemplos;

public class Persona {
   private String nombre;
   private String apellido;
   // setters y getters
}

Tanto en el servlet como en un jsp podemos guardar este bean en cualquiera de los sitios indicados con setAttribute() y obtenerlo con getAttribute(). Por ejemplo, en un jsp

<% Persona p = new Persona();
   p.setNombre("Pedro");
   p.setApellido("Lopez");
   session.setAttribute("unaPersona", p);
   
   // y para obtenerla, en otro jsp o el mismo
   Persona q = (Persona)session.getAttribute("unaPersona");

y en un Servlet de igual manera

public class UnServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
      Persona p = new Persona();
      p.setNombre("Pedro");
      p.setApellido("Lopez");
      req.getSession().setAttribute("unaPersona", p);
       ...
      // y para leer en el mismo Servlet u otro
      Persona q = (Persona)req.getSession().getAttribute("unaPersona");

Sin embargo, en jsp tenemos unos tag especiales que nos permiten trabajar con estos bean más al estilo de una página html, sin meter el código java directamente. Estos tag son <jsp:useBean>, <jsp:getProperty> y <jsp:setProperty>

Para obtener un bean dentro de jsp lo hacemos así

<jsp:useBean id="unaPersona" scope="session" class="com.chuidiang.ejemplos.Persona"></jsp:useBean>

Aquí ponemos en scope dónde queremos guardar o recoger el bean, es decir, "page", "request", "session" o "application". El id es el nombre que usábamos antes como nombre de atributo, es decir "unaPersona". Si ese bean ya existe lo obtenemos, si no existe se crea y se guarda ahí. Finalmente, en class debemos indicar la clase del bean con paquete y todo, en nuestro caso "com.chuidiang.ejemplos.Persona".

Dentro del jsp y una vez obtenido el bean, podemos meter valores en sus propiedades o acceder a ellas

<jsp:setProperty name="unaPersona" property="nombre" value="Pedro"/>
...
<p>El nombre es <jsp:getProperty name="unaPersona" property="nombre"/></p>

Esta vez name es el nombre del bean, que en jsp:useBean era el id. En property se pone el nombre de la propiedad (nombre, apellido, etc) y en value, en el caso del setProperty, lo que queremos que valga. Java es listo y si el atributo de la clase es de tipo boolean, entero, etc, java convertirá automáticament la cadena de texto al tipo adecuado. Por ejemplo, si nombre fuese booelan, podríamos poner value="true" y se haría la conversión automáticamente.

En el caso concreto de formularios, jsp:setProperty nos permite recoger fácilmente en la página jsp de destino los campos del formulario. Imagina el formulario para persona

<form action="salva.jsp">
Nombre : <input type="text" name="nombre"/><br/>
Apellido : <input type="text" name="apellido"/><br/>
<input type="submit" value="Salvar"/>
</form>

Pues bien, en la página salva.jsp que recibe este formulario, podemos crear el bean y rellenar sus valores así

<jsp:useBean id="nuevaPersona" class="com.chuidiang.ejemplos.Persona" scope="page"/>
<jsp:setProperty name="nuevaPersona" property="nombre" param="nombre"/>
<jsp:setProperty name="nuevaPersona" property="apellido" param="apellido"/>

Es decir, en vez de value, indicamos param, siendo param el nombre del campo en el formulario.

Si el nombre del param y del property coinciden, podemos no poner param, que por defecto valdrá lo mismo que property. Al ser el caso anterior, podríamos escribir

<jsp:useBean id="nuevaPersona" class="com.chuidiang.ejemplos.Persona" scope="page"/>
<jsp:setProperty name="nuevaPersona" property="nombre"/>
<jsp:setProperty name="nuevaPersona" property="apellido"/>

y existe aun una facilidad más. Si todos los nombres de los campos coindicen con todos los nombres de los atributos del bean, entonces con un property="*" los rellenamos todos de un plumazo, tal que así

<jsp:useBean id="nuevaPersona" class="com.chuidiang.ejemplos.Persona" scope="page"/>
<jsp:setProperty name="nuevaPersona" property="*"/>

En este ejemplo le hemos puesto scope="page", es decir, esa "nuevaPersona" sólo existirá en nuestra página jsp y posiblemente la salvemos en base de datos o hagamos cualquier otra cosa con ella. Podríamos de igual forma haber cogido/creado esa "nuevaPersona" en request, session o application.