Aprendiendo sobre Alcances de variables de Sesión en JSF

(Versión Wiki: http://wiki.netbeans.org/AprendiendoSobreAlcancesJSF)

Introducción

Sabemos que es un dolor de cabeza usar las variables de sesión a través de los objetos HttpSession y HttpRequest. No sabemos si una variable está en nivel de sesión o en nivel de request, simplemente lo ponemos y lo usamos, aunque después nos pueden dar problemas a lo largo de la aplicación Pero al usar JSF esto se hará mucho más sencillo. JSF nos permite utilizar tres tipos de alcances:
  • Aplicación: Una variable guardada en este alcance es visible durante toda la aplicación, hasta que se repliegue la aplicación o hasta que se detenga el servidor.
  • Sesión: Una variable guardada a nivel de sesión, puede ser visible durante el tiempo de vida del usuario en la aplicación, hasta que se invalide la sesión.
  • Request: Una variable en nivel request dura solo hasta la siguiente página, Una página 1, guarda la variable en nivel request y redirecciona la petición a la página 2. La página 2 la utiliza, y el objeto desaparece.
Por tanto, haremos una aplicación que permita hacer votos y mostrar el resultado. Las alternativas y cuenta de votos se guardarán a nivel de la aplicación; el usuario que haya hecho el voto no podrá volver a votar, por tanto la aplicación sabrá que se trata del mismo usuario porque mantiene la sesión; y cuando el usuario quiera ver los resultados, estos se mostrarán en de acuerdo al requerimiento.

Software necesario:

  • Java 6
  • Glassfish V2
  • NetBeans 6.5 con el componente Visual ICE Faces que se puede descargar desde el Centro de Actualización (Herramientas > Complementos)


Creando una aplicación JSF con Visual ICEFaces

Diseñando la aplicación visual

  1. Crearemos una aplicación Web al que llamaremos Scopes
  2. En la Paso "4. Frameworks" activamos el framework Visual Web ICEfaces
  3. Al terminar de crear el proyecto, se mostrará un texto de advertencia. Lo borramos ya que advierte que en este proyecto no funcionarán las paletas Woodstock
  4. Ahora, desde el panel ICEfaces arrastramos y colocamos los siguientes componentes al diseño de Page1.jsp
    • OutputText: Y en el atributo value escribimos '¿Cuál es tu lenguaje de programación favorito?'
    • SelectOneRadio: cuyo atributo id será opcionesRadio
    • Y dos CommandButton: uno con id=votarButton, value='Votar' y el otro id=resultadosButton, value='Ver resultados', action='ver_resultados'
      En general, podemos escribir el código y por cada declaración de clase que vayamos usar, escribimos unos cuantos caracteres del nombre y presionamos Ctrl+Espacio para que el IDE nos sugiera las clase, y al seleccionarla nos hará el import de esas clases de manera automática. O al finalizar de escribir todo el código, presionamos Mayus+Ctrl+I para importar las clases necesarias y borrar las innecesarias.
  5. En el explorador del proyecto, abrimos el nodo de fuentes de clase y abrimos la clase ApplicationBean1.java. Esta clase contendrá todas las variables que se usarán en toda la aplicación. Para nuestro caso, aquí colocaremos las opciones de la encuesta, y el contador por cada opción marcada. Así que, después de la declaración de la clase, justamente después de { escribimos
    private com.sun.webui.jsf.model.Option[] opciones;
    private java.util.HashMap votos;
    Además, crearemos sus métodos set y get. Podemos hacer esto desde la opción Reestructurar > Encapsular campos...
  6. También necesitamos hacer una pequeña lógica de negocio para incrementar los votos a alguna opción seleccionada. Así que crearemos el siguiente método:

    public void votoPara(String votoHecho) {
    Integer cuenta = votos.get(votoHecho);
    if (cuenta == null) {
    cuenta = 0;
    }
    cuenta++;
    votos.put(votoHecho, cuenta);
    }
  7. Ahora, vamos al método init() de la misma clase, y en la última línea del cuerpo del método escribiremos la inicialización de los valores de las propiedades que acabamos de crear:

    opciones = new Option[]{
    new Option("java", "Java Programming Language"),
    new Option("cpp", "C++"),
    new Option("fortran", "Fortran")};
    votos = new HashMap();
    for (Option o : opciones) {
    votos.put(o.getValue().toString(), 0);
    }
  8. Ya tenemos las variables que son visibles desde toda la aplicación. Ahora haremos la variable que durará la sesión del usuario. Así que abrimos la clase SessionBean1.java y agregamos la propiedad boolean haVotado con sus respectivos set/get

    private boolean haVotado;

    public boolean isHaVotado() {
    return haVotado;
    }

    public void setHaVotado(boolean haVotado) {
    this.haVotado = haVotado;
    }
  9. Y la última variable de nivel de requerimiento (request) será la hora en que se accede al resultado de los votos. Así que abriremos la clase RequestBean1.java y agregamos la propiedad java.util.Date hora con su respecto set/get

    private java.util.Date hora;

    public Date getHora() {
    return hora;
    }

    public void setHora(Date hora) {
    this.hora = hora;
    }

Manejando los valores de los controles

  1. Necesitamos colocar los valores de nuestro arreglo de la clase ApplicationBean1 en el formulario. Vayamos al modo diseño visual de Page1.jsp, hagamos clic derecho sobre el objeto opcionesRadio y seleccionamos Bind to data...
  2. Seleccionamos el objeto opciones que se encuentra bajo el objeto ApplicationBean1
    Clic en Aceptar
  3. Al hacer esto, el objeto del diseño se habrá 'desaparecido. No sucede tal cosa, sino que se adecuo al contenido. Como las opciones solo se verán en tiempo de ejecución, no se pueden visualizar en el modo de edición.
  4. Ahora, debemos establecer que cuando el usuari haya hecho clic en el botón "Votar", ya no puede volver a votar. Para ello necesitamos desactivar el botón. Así que el estado de este control depende del valor de la propiedad haVotado que está en la clase SessionBean1. Haremos clic derecho sobre el botón, y seleccionamos Properties binding... y seleccionamos en el panel izquierdo la propiedad disabled y en el panel derecho seleccionamos de SessionBean1.haVotado
    Clic en Close.
  5. Hacemos clic en el botón superior Java para ver el código de la clase Page1.java, y agregamos los siguientes métodos. Estos nos permitirán acceder a los objetos ApplicationBean1, SessionBean1 y RequestBean1

    protected ApplicationBean1 getApplicationBean1() {
    return (ApplicationBean1) getBean("ApplicationBean1");
    }

    protected RequestBean1 getRequestBean1() {
    return (RequestBean1) getBean("RequestBean1");
    }

    protected SessionBean1 getSessionBean1() {
    return (SessionBean1) getBean("SessionBean1");
    }
  6. Hacemos clic en el botón superior Design para ver el modo diseño de Page1.jsp y hacemos doble-clic sobre el botón Votar. Esto creará el método votarButton_action() en la clase Page1.java. Aquí obtendremos el valor seleccionado y lo incrementaremos en el contador de votos:

    public String votarButton_action() {
    if (selectOneRadio1Bean.getSelectedObject() != null) {
    String votoHecho = (String) selectOneRadio1Bean.getSelectedObject();
    getApplicationBean1().votoPara(votoHecho);
    getSessionBean1().setHaVotado(true);
    Date hora = new Date();
    getRequestBean1().setHora(hora);
    }
    return null;
    }
  7. Regresamos al modo diseño de Page1.jsp y hacemos doble clic en el botón resultadosButton y hacemos que devuelva la cadena "mostrar_resultados"


    public String resultadosButton_action() {
    return "mostrar_resultados";
    }

Página de respuesta

  1. Creamos una nueva página de la categoría JavaServer Faces y el tipo ICEfaces Visual Web JSF Page
    al cual lo llamaremos Page2.jsp
  2. Agregaremos los siguientes controles:
    • Un outputText con value="Resultados de los votos"
    • Un commandButton con value="Inicio" y id="inicioButton"
    • Otro commandButton con value="Recargar" y id="cargarButton"
    • Un outputText con id="resultadoText", escape=(desmarcado) y value=""
    • Otro outputText con id="fechaText" y value=""
  3. Tanto para resultadoText como para fechaText hacemos clic derecho sobre el control y seleccionamos "Add Binding Attribute"
  4. Hagamos doble en el botón "Inicio". Se abrirá el editor del código de Page2.java, y se creará el método inicioButton_action(), modificamos el código para que tenga el siguiente contenido:

    public String inicioButton_action() {
    return "inicio";
    }
    Posteriormente programaremos la navegación de las páginas.
  5. Estando en el archivo Page2.java, buscamos el método prederender() y lo editamos con el siguiente código
        public void prerender() {
    //Mostrar los últimos propositos
    ApplicationBean1 appBean = getApplicationBean1();//El Bean de toda la aplicacion
    Option[] opciones = appBean.getOpciones();//las opciones de la aplicacion
    Map cuentasVotos = appBean.getVotos(); //y obtenemos las cuentas de los votos hechos
    StringBuilder sb = new StringBuilder(); //para contatenar las cadenas que vamos a crear.
    sb.append("");//vamos a crear un table para resultados
    for (Option opcion : opciones) { //recorremos todas las opciones de la encuesta
    String idVoto = (String) opcion.getValue(); //obtenemos el id de la opción
    String etiqueta = opcion.getLabel();//obtenemos el valor que se muestra como opciones
    int cuenta = cuentasVotos.get(idVoto); //obtenemos cuantos votos se hizo para la opción actual
    sb.append(""); //nueva fila en el table
    sb.append(""); //agregamos la etiqueta de la opcion de voto
    sb.append("");//agregamos los votos hechos a la opcion de voto actual
    sb.append(""); //fin de la fila en el table
    }
    sb.append("
    " + etiqueta + "" + cuenta + "
    "); //fin del table
    resultadoText.setValue(sb); //mostramos el resultado. Se mostrará como String

    //Ahora, obtendremos la hora y fecha en que se hizo el voto
    RequestBean1 reqBean=getRequestBean1(); //obtenemos el bean del requerimiento
    Date hora=reqBean.getHora();
    if (hora!=null){
    fechaText.setValue("Su voto fue realizado el "
    +(String)DateFormat.getTimeInstance(DateFormat.FULL).format(hora)); //imprimos la fecha en un formato completo
    }
    }


Navegación entre las páginas

  1. Abrimos el archivo faces-config.xml. La manera más rápida de ubicar el archivo es presionando Mayus+Alt+O y escribimos el nombre del archivo.
  2. Hacemos clic en el botón superior que dice "PageFlow" para entrar al modo visual de la navegación de las páginas de JSF. Más o menos se visualizará así:
    Vemos que en cada ícono de página hay un cuadrado de color celeste en la parte derecha. Así que hacemos clic en ese cuadrado del ícono del archivo Page1.jsp, lo arrastramos y lo soltamos en Page2.jsp.
  3. Al soltar la flecha, se habrá creado un vértice dirigido con el nombre "case1" Hacemos doble clic sobre este texto y lo cambiamos con el nombre "mostrar_resultados"
  4. Haremos otro enlace desde la Page2.jsp a Page1.jsp y se llamará "inicio"
Estos textos son los que escribimos como return en los métodos resultadosButton_action() de Page1.jsp y inicioButton_action() de Page2.jsp respectivamente. Hagamos clic en el botón superior "XML" de faces-config.xml. Cuando arrastramos los flechas, el código que generó fue el siguiente:
    <navigation-rule>
<from-view-id>/Page1.jsp</from-view-id>
<navigation-case>
<from-outcome>mostrar_resultados</from-outcome>
<to-view-id>/Page2.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/Page2.jsp</from-view-id>
<navigation-case>
<from-outcome>inicio</from-outcome>
<to-view-id>/Page1.jsp</to-view-id>
</navigation-case>
</navigation-rule>

Ejecutando la aplicación

Ejecutamos el proyecto con la tecla F6.
Hagamos nuestro primer voto: Seleccionamos nuestro voto y hacemos clic en el botón "Votar". Notemos que en ese mismo momento el botón quedó desactivado.
Este botón quedará desactivado mientras duré la sesión o hasta que cerremos nuestro navegador. Hagamos clic en el botón "Ver resultados".
Podemos regresar al inicio haciendo clic en el boton "Inicio" y aún así no se podrá volver a votar. Recordemos que ese botón lo asociamos al objeto "haVotado" que se encuentra en el SessionBean
Ahora probemos entrando desde otro navegador. Entremos nuevamente a la misma dirección http://localhost:8080/Scopes/Page1.iface
Sin hacer ningún voto, hagamos clic en "Ver resultados"
Vemos que se ve el voto que hicimos desde el otro navegador. Pero no se visualiza cuando fue. Claro, eso se calculó al momento del voto desde el otro navegador. En este nuevo navegador hagamos clic en "inicio" y realicemos nuestro voto.
Regresemos a nuestro primer navegador, y hagamos clic en el botón "Recargar"

Conclusiones

Hemos podido ver cómo funcionan los diferentes alcances (scope) en una aplicación JSF. No fue necesario de algún request.setAttribute() o session.setAttribute Solo basta con colocar propiedades en los Bean de acuerdo a nuestro requerimiento. Si queremos que una variable dure en toda la aplicación para todos los usuarios, usamos ApplicationBean1; si queremos que una variable dure durante la sesión del usuario, usamos SessionBean1, y si solo queremos que dure solo en una página, usamos RequestBean1.

Recursos

El proyecto utilizado en este tutorial se puede descargar desde aquí http://diesil-java.googlecode.com/files/scopes.tar.gz

Comentarios

Entradas más populares de este blog

UML en NetBeans

Cambiar ícono a un JFrame

RESTful... la forma más ligera de hacer WebServices (Parte 1)