Mostrando entradas con la etiqueta JSF. Mostrar todas las entradas
Mostrando entradas con la etiqueta JSF. Mostrar todas las entradas

jueves, 2 de julio de 2020

Java Server Faces - Facelets Tags

Detrás del manejo de las páginas XHTML que componen la vista existe todo un mecanismo de optimización y administración. En JSF a las páginas que componen la vista se les suele llamar archivos *xhtml, pero en realidad en el desarrollo web las páginas XHTML tienen otro significado en su lugar se les debe de llamar "Facelets" estos mediante las instrucciones del desarrollados en XML y tras pasar por el Framework Web y otras instancias generará el archivo HTML deseado y que visualiza el cliente.

Los Facelets proporcionan etiquetas para crear fácilmente composiciones de plantillas basadas en un único archivo de plantilla, similar a la tecnología de .NET de páginas maestras. La finalidad de este mecanismo es la de reducir la duplicación de código para diversas secciones del sitio web que se repiten en todas las páginas web, como:

  • El encabezado
  • El menú de navegación
  • El pie de página.

El archivo de plantilla maestra debe representar un diseño de página web completo con todas las secciones de todo el sitio y usar etiquetas <ui: insert=""> para representar los lugares donde se pueden insertar las secciones específicas de la página.


Creando la estructura

Para ello , se creará un archivo plantilla, y archivos satélite que contengan el código de la cabecera y pie de página. Además, de diversas páginas para comprobar la navegación. La estructura debe ser la siguiente:


El código de layout.xhtml es:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <h:head>
        <title>#{title}</title>
    </h:head>
    <h:body>
        <header>
            <ui:include src="/WEB-INF/includes/layout/header.xhtml" />
        </header>
        <main>
            <ui:insert name="content" />
        </main>
        <footer>
            <ui:include src="/WEB-INF/includes/layout/footer.xhtml" />
        </footer>
    </h:body>
</html>
</code>


El código de header.xhtml es:
<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <a href="#{request.contextPath}/">        
        INICIO
    </a>
    <nav>
        <ul>
            <li><h:link outcome="/about" value="About" /></li>
            <li><h:link outcome="/help" value="Help" /></li>
            <li><h:link outcome="/contact" value="Contact" /></li>
        </ul>
    </nav>
    <hr/>
</ui:composition>


El código de footer.xhtml es:
<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <hr/>
    <nav>
        <ul>
            <li>Términos de servicio</li>
            <li>Política de privacidad</li>
            <li>Política de cookies</li>
        </ul>
    </nav>
    <small>
        © JavaJhon
    </small>
</ui:composition>


El código de index.xhtml es:
<ui:composition template="/WEB-INF/template/layout.xhtml"
                xmlns="http://www.w3.org/1999/xhtml"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <ui:param name="title" value="Inicio" />
    <ui:define name="content">
        <h1>Pantalla de inicio</h1>
        <p>Lorem ipsum dolor sit amet.</p>
    </ui:define>
</ui:composition>


Tendremos una interacción como se aprecia en la imagen



Fuentes:

  • Schotlz, B. y Tijms, A. (2018). The Definitive Guide to JSF in Java EE 8:Building Web Applications with JavaServer Faces. United States of America: Apress.


miércoles, 1 de julio de 2020

Java Server Faces Resource Bundles

Un "resource bundle" en JAVA es un archivo o colección de ellos del tipo *.properties que contiene datos específicos de la localidad. Esto permite "internacionalizar" un aplicativo de forma que la configuración regional se mantiene de forma independiente a la codificación. Estos emplean una organización similar a los HashMap con clave y valor. Así podemos tener una clave "saludo" con valor "hola" en un archivo, en otro la misma clave con valor "hello" y así sucesivamente, pero estos archivos para relacionarse deben tener algo en común y es el uso del mismo nombre con la terminación "_" seguida de dos letras del código de lenguaje ISO 639-1-Alpha-2 antes de la extensión del archivo. así tendríamos los diversos archivos:
  • dictionary.properties, este sería el archivo por defecto
  • dictionary_es.properties, este sería específicamente para el español

Especificar un país se haría agregando otro "_" seguido de dos letras del código de países ISO 3166-1-Alpha-2 antes de la extensión del archivo
  • dictionary_pt_BR.properties, este sería para el portugués de Brasil.
  • dictionary_en_UK.properties, este sería para el inglés de Reino Unido.

NOTA: Lo ideal es que los nombres de los archivos y las claves se encuentren en un solo idioma y por recomendación el inglés. Aún cuando la aplicación no sea usada por personas que hablen ese idioma.


Creando un diccionario para español e inglés

Dentro de los paquetes del código fuente se creará un paquete con el nombre "bundles", dentro de este se crearán documentos con la extensión *.properties que serán:
  • text.properties
  • text_es.properties

text.properties text_es.properties
title=JSF with resource bundles
greeting=Hello my friend
button=Go to the app
title=JSF con paquetes de recursos
greeting=Hola amigo mío
button=Ve a la aplicación

Dependiendo del IDE empleado se visualizará y editará de diversas formas. Por ejemplo en Netbeans se puede apreciar ambos a la vez, mientras en otros se ven y editan por separado.




Llamar a un recurso desde una página de JSF

Estos recursos se comportan de la misma forma como una colección del tipo MAP, por lo que se les llamará de la misma forma con la siguiente sintaxis #{variable['identificador']}, pero antes de ello se debe definir la forma como se hará referencia a estos recursos. Existen dos formas, una es la llamada local mediante una etiqueta de prefijo "f" y la otra desde el archivo de configuración "faces-config.xml"


Llamado local a un recurso

Supongamos el siguiente archivo *.xhtml

<!DOCTYPE html>
<html lang="#{view.locale.toLanguageTag()}"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <f:loadBundle basename="bundles.text" var="texto" />
        <title>#{texto['title']}</title>
    </h:head>
    <h:body>
        <h2>#{texto['greeting']}</h2>
        <h:button value="#{texto['button']}"/>
    </h:body>
</html>

Observemos la línea 2 #{view.locale.toLanguageTag()}, esta permite que se establezca el lenguaje como el mismo del navegador, además se puede emplear para conocer cuál es el que se tiene.

La línea 7 es la etiqueta que hace el llamado al recurso, para ello dispone de dos atributos que son:

  • basename, este tiene como valor la ubicación del recurso dentro del proyecto.
  • var, este indica el "alias" que empleará dentro de la página xhtml


Así en las líneas 8, 11 y 12 se aprecia como se llama a los recursos como si se tratara de una colección del tipo MAP. En un navegador que tiene al español como predefinido la salida sería en el cuerpo de la página el encabezado "Hola amigo mío" seguido del botón con el texto "Ve a la aplicación"


Llamada al recurso desde faces-config

Para poder realizar el llamado desde cualquier página sin usar "f:loadBundle" se debe agregar la referencia en el archivo faces-config.xml de la siguiente forma
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
              http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
              version="2.2">
    <application>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>es</supported-locale>
        </locale-config> 
        <resource-bundle>
            <base-name>bundles.text</base-name>
            <var>texto</var>
        </resource-bundle>
    </application>
</faces-config>


Ahí indicamos el lenguaje por defecto (en) y los lenguajes soportados, en este caso el español, luego se indica la ubicación y variable que se empleará.

Se debe tener algunas consideraciones como no usar como variable el que emplee un Bean, ya que se puede causar conflicto y resultados no deseados.

viernes, 19 de junio de 2020

BootsFaces

Es un Framework de front-end para JSF que tiene como base a Bootstrap 3 y jQuery-UI que permite crear páginas con Bootstrap de manera simplificada al convertir el código ingresado en HTML con el estilo definido.


Emplear BootsFaces

Existen dos manera de utilizar este Framework, la primera es mediante descarga que genera un archivo *.jar y se debe agregar al proyecto.



La otra forma es emplear un repositorio como Maven o Gradle y agregar las siguientes líneas en los archivos de construcción.
Maven Gradle
<dependency>
    <groupId>net.bootsfaces</groupId>
    <artifactId>bootsfaces</artifactId>
    <version>1.4.2</version>
    <scope>compile</scope>
</dependency>
  
compile 'net.bootsfaces:bootsfaces:1.4.2'
 


Implementar en un XHTML

Se debe agregar el siguiente atributo-valor xmlns:b="http://bootsfaces.net/ui" que como se aprecia emplea el prefijo "b".

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
   xmlns:h="http://xmlns.jcp.org/jsf/html"
   xmlns:b="http://bootsfaces.net/ui">
<h:head>
   <title>Prueba 05 - BootsFaces</title>
</h:head>
<h:body>
   <!--Código de la página-->
</h:body>
</html>


Ejemplo de aplicación

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://xmlns.jcp.org/jsf/html"
 xmlns:b="http://bootsfaces.net/ui">
<h:head>
 <title>Prueba 05 - BootsFaces</title>
</h:head>
<h:body>
 <b:navBar brand="INICIO" brandHref="index.html" inverse="true"
  fixed="top">
  <b:navbarLinks>
   <b:navLink value="JSF" href="#"></b:navLink>
   <b:navLink value="Bootsfaces" href="#"></b:navLink>
   <b:dropMenu value="Pruebas">
    <b:navLink value="Prueba 1" href="#"></b:navLink>
    <b:navLink value="Prueba 2" href="#"></b:navLink>
    <b:navLink value="Prueba 3" href="#"></b:navLink>
    <b:navLink></b:navLink>
    <b:navLink header="Otros"></b:navLink>
    <b:navLink value="Resultados" href="#"></b:navLink>
   </b:dropMenu>
  </b:navbarLinks>
 </b:navBar>
 <b:jumbotron>
  <b:container>
   <h1>Encabezado</h1>
   <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
    do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
    enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
    ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
   <p>
    <a href="https://javajhon.blogspot.com/" class="btn btn-lg btn-info">
     Blog sobre Java </a>
   </p>
  </b:container>
 </b:jumbotron>
 <b:container>
  <b:row styleClass="show-grid">
   <b:column span="4">
    <h2>Botones b:commandbutton</h2><br/>
    <h:form>
    <b:commandButton action="j" value="primary" look="primary"/><br/><br/>
    <b:commandButton action="j" value="success" look="success"/><br/><br/>
    <b:commandButton action="j" value="danger" look="danger"/><br/><br/>
    <b:commandButton action="j" value="info" look="info"/><br/><br/>
    <b:commandButton action="j" value="warning" look="warning"/><br/><br/>
    <b:commandButton action="j" value="default" look="default"/><br/><br/>
    </h:form>       
   </b:column>
   <b:column span="4">
    <h2>Botones class btn-*</h2><br/>
    <a class="btn btn-lg btn-primary">primary</a><br/><br/>
    <a class="btn btn-lg btn-success">success</a><br/><br/>
    <a class="btn btn-lg btn-danger">danger</a><br/><br/>
    <a class="btn btn-lg btn-info">info</a><br/><br/>
    <a class="btn btn-lg btn-warning">warning</a><br/><br/>
    <a class="btn btn-lg btn-default">default</a>    
   </b:column>
   <b:column span="4">    
    <h2>Etiquetas</h2>
    <b:dropButton value="DropButton" look="success">
     <b:navLink value="Prueba 1" href="#"></b:navLink>
     <b:navLink value="Prueba 2" href="#"></b:navLink>
     <b:navLink value="Prueba 3" href="#"></b:navLink>
     <b:navLink></b:navLink>
     <b:navLink header="Otros"></b:navLink>
     <b:navLink value="Resultados" href="#"></b:navLink>
    </b:dropButton>
    <b:panelGrid ></b:panelGrid>
    <b:panel></b:panel>
   </b:column>
  </b:row>
  <hr />
  <footer>
   <p>© JavaJhon 2020</p>
  </footer>
 </b:container>
</h:body>
</html>

Fuentes:

  • BootsFaces. (2018). BootsFaces Showcase. Recuperado de: https://showcase.bootsfaces.net/

Java Server Faces - DataTable

Las tablas de HTML en una aplicación web con Java Server Faces se construye mediante la etiqueta h:dataTable en los Facelets.

Los datos que se pueden mostrar mediante un h:dataTable son:
  • Arrays
  • Instancias del Java Colletion Framework
  • Instancias de java.sql.ResultSet
  • Instancias de javax.servlet.jsp.jstl.sql.Result
  • Instancias de javax.faces.model.DataModel

Supongamos el siguiente bean llamado "LibroBean":
package proyectoJSF.model;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class LibroBean {

 private Integer id = 105;
 private String nombre = "JSF EL";
 private AutorBean autor = new AutorBean();
 private String[] idiomas = { "Español", "Inglés", "italiano" };
 private List<String> paises;
 private Map<String, LocalDate> ediciones;

 public LibroBean() {
  cargarPaises();
  cargarEdiciones();
 }

 public String[] getIdiomas() {
  return idiomas;
 }

 public List<String> getPaises() {
  return paises;
 }

 public Map<String, LocalDate> getEdiciones() {
  return ediciones;
 }

 private void cargarPaises() {
  paises = new ArrayList<>();
  paises.add("Perú");
  paises.add("Canadá");
  paises.add("Japón");
 }

 private void cargarEdiciones() {
  ediciones = new TreeMap<>();
  ediciones.put("Primera", LocalDate.of(2012, 12, 30));
  ediciones.put("Segunda", LocalDate.of(2015, 2, 12));
  ediciones.put("Tercera", LocalDate.of(2020, 6, 7));
 }

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getNombre() {
  return nombre;
 }

 public void setNombre(String nombre) {
  this.nombre = nombre;
 }

 public AutorBean getAutor() {
  return autor;
 }

 public void setAutor(AutorBean autor) {
  this.autor = autor;
 }

}


Se aprecia que contiene diversas estructuras de datos, vamos a mostrar la estructura MAP mediante un h:dataTable de la siguiente manera:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://xmlns.jcp.org/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core">
<h:head>
 <title>Prueba 04 - DataTable</title>
</h:head>
<h:body>
 <h1>Ediciones de los libros</h1>
 <h:dataTable value="#{libroBean.ediciones}" var="edicion" border="1">
  <h:column>
   <f:facet name="header">
    Edición
   </f:facet>
   <h:outputText value="#{edicion.key}" />
  </h:column>
  <h:column>
   <f:facet name="header">
    Fecha de publicación (aaaa/mm/dd)
   </f:facet>
   <h:outputText value="#{edicion.value}" />
  </h:column>
 </h:dataTable>
</h:body>
</html>


Tenemos las siguientes etiqeutas y sus atributos:
  • h:dataTable, se convierte posteriormente en una tabla HTML
    • value, es el atributo cuyo valor es el que se itera dentro de la tabla
    • var, es el nombre de la variable que usaremos dentro de la estructura
    • border, similar a la propiedad "border" de una tabla HTML
  • h:column, en contraste con HTML no es necesario definir las filas, se hacen directamente las columnas. Dentro tendremos:
    • f:facet name="header", dentro de esta etiqueta con este "name" se coloca el texto que irá en dicha columna.
    • h:outputText value="#{edicion.key}", tendremos una etiqueta de texto que mostrará la clave de cada elemento del MAP
    • h:outputText value="#{edicion.value}", tendremos una etiqueta de texto que mostrará el valor de cada elemento del MAP

El resultado visual sería:
Edición Fecha de publicación (aaaa/mm/dd)
Primera 2012-12-30
Segunda 2015-02-12
Tercera 2020-06-07


Java Server Faces Expression Language (JSF EL)

Los Facelets no soportan las secuencias de comandos de Java Server Pages. Por ello, se requiere de una forma de indirectamente invocar al código Java. Así JSP y Facelets son dos tecnologías diferentes.

JSF permite la utilización de ambas incluso conjuntamente. A ello se debe acotar que Facelets es más reciente y específica para JSF ofreciendo más posibilidades al desarrollador. Se recomenda el uso de los Facelets en JSF.

El lenguaje de expresión de JSF fue inspirado en la tecnología JSTL mediante el uso de prefijos en sus bibliotecas estándar. Este se encuentra entre las capas de modelo y vista mediante la aplicación de las propiedades Setter y Getter.

Formatos

Emplear minúsculas al hacer referencia a un Bean. 
Tipo de bean EL
Atributo de un Bean Simple
#{nombre.atributo}
Ejemplo: Supongamos un Bean llamado "Mascota" que tiene un atributo llamado "peso", para llamarlo usaríamos
#{mascota.peso}
Método de un Bean Simple con retorno
#{nombre.metodo()}
Ejemplo: Supongamos un Bean llamado "Mascota" que tiene un método llamado "ladrido" que devuelve un valor String, para llamarlo usaríamos
#{mascota.ladrido()}
Atributo o método de un atributo tipo objeto de un Bean Simple
#{nombre.atrib1.atrib2}
Ejemplo: Supongamos un Bean llamado "Mascota" que tiene un atributo que es del tipo "Propietario" llamado "propietario" que devuelve un objeto y este objeto en su declaración tiene "id" y "nombre", para llamar al nombre del propietario usaríamos
#{mascota.propietario.nombre}


Aplicación

Nota: Para este caso se usa la versión JSF 2.3 y Java EE 8 con un servidor Payara

Supongamos que tenemos el siguiente "bean" llamado "AutorBeans"
package proyectoJSF.model;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class AutorBean {

 private Integer idAutor = 1;
 private String nombre = "Jhon";

 public AutorBean() {
 }
 
 public Integer getIdAutor() {
  return idAutor;
 }

 public void setIdAutor(Integer idAutor) {
  this.idAutor = idAutor;
 }

 public String getNombre() {
  return nombre;
 }

 public void setNombre(String nombre) {
  this.nombre = nombre;
 }

}


A partir de la versión 2.0 de JSF se puede emplear las EL desde cualquier parte del Facelet, ya no es necesario hacerlo dentro de sus etiquetas JSF. Para invocar a sus métodos Getter y Setter desde un Facelet debemos colocar lo siguiente:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
 <title>Prueba 03</title>
</h:head>
<h:body>
  <h1>Autor - Método GET</h1>
  <ul>
    <li>Id del autor: #{autorBean.idAutor}</li>
    <li>Nombre: #{autorBean.nombre}</li>
  </ul>
  <hr/>
  <h1>Autor - Método SET</h1>
  <h:form>
    <h:outputLabel value="Ingrese ID: "/>
    <h:inputText value="#{autorBean.idAutor}"/>
    <br/><br/>
    <h:outputLabel value="Ingrese nombre: "/>
    <h:inputText value="#{autorBean.nombre}"/>
    <br/><br/>
    <h:commandButton type="submit" value="Cambiar"/> 
  </h:form>
</h:body>
</html>


Se observa los siguiente, en este caso se modifico las cajas de texto con "10001" y "Jhon Paul" que originalmente tenían los mismos valores "1" y "Jhon":

La expresión #{autorBean.idAutor} invoca automáticamente al método GET del atributo "idAutor" y lo mismo en el caso de "nombre". Si se hace clic en el botón "Cambiar" se obtendrá el siguiente resultado:

En este caso la expresión #{autorBean.idAutor} dentro de los "h:inputText" invoca automáticamente al método SET del atributo "idAutor" y lo mismo en el caso de "nombre", que luego se ve reflejado en la primera sección del Facelet. Esto permite mucha simplicidad para el manejo de los atributos.



Manejando estructuras de datos con EL

Podemos visualizar Array y colecciones. Supongamos la siguiente clase "LibroBean" que emplea la anterior
package proyectoJSF.model;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class LibroBean {

 private Integer id = 105;
 private String nombre = "JSF EL";
 private AutorBean autor = new AutorBean();
 private String[] idiomas = { "Español", "Inglés", "italiano" };
 private List<String> paises;
 private Map<String, LocalDate> ediciones;

 public LibroBean() {
  cargarPaises();
  cargarEdiciones();
 }

 public String[] getIdiomas() {
  return idiomas;
 }

 public List<String> getPaises() {
  return paises;
 }

 public Map<String, LocalDate> getEdiciones() {
  return ediciones;
 }

 private void cargarPaises() {
  paises = new ArrayList<>();
  paises.add("Perú");
  paises.add("Canadá");
  paises.add("Japón");
 }

 private void cargarEdiciones() {
  ediciones = new TreeMap<>();
  ediciones.put("Primera", LocalDate.of(2012, 12, 30));
  ediciones.put("Segunda", LocalDate.of(2015, 2, 12));
  ediciones.put("Tercera", LocalDate.of(2020, 6, 7));
 }

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getNombre() {
  return nombre;
 }

 public void setNombre(String nombre) {
  this.nombre = nombre;
 }

 public AutorBean getAutor() {
  return autor;
 }

 public void setAutor(AutorBean autor) {
  this.autor = autor;
 }

}

Si deseamos mostrar el Array "idiomas", usaremos el siguiente código:
<h1>Libro - Idiomas disponibles</h1>
<ul>
 <li>#{libroBean.idiomas[0]}</li>
 <li>#{libroBean.idiomas[1]}</li>
 <li>#{libroBean.idiomas[2]}</li>
</ul>

Si deseamos mostrar la colección List "paises", usaremos el siguiente código:

<h1>Libro - Países de venta disponibles</h1>
<ul>
 <li>#{libroBean.paises[0]}</li>
 <li>#{libroBean.paises[1]}</li>
 <li>#{libroBean.paises[2]}</li>
</ul>

Si deseamos mostrar la colección Map "ediciones", usaremos el siguiente código:

<h1>Libro - Ediciones y fechas</h1>
<ul>
 <li>#{libroBean.ediciones["Primera"]}</li>
 <li>#{libroBean.ediciones["Segunda"]}</li>
 <li>#{libroBean.ediciones["Tercera"]}</li>
</ul>


Obteniendo el siguiente resultado:


Operaciones con EL

Podemos emplear operaciones de comparación, aritméticas, lógicas y el operador "empty".

Operaciones aritméticas
Expresión Resultado
Suma (+) #{2+2} 4
Resta (-) #{2-12} -10
Producto (*) #{7*5} 35
División ("div" o "/") #{4/5} 0.8
Residuo ("mod" o "%") #{12 mod 5} 2
Operación combinada #{(5 % 3)*2-1} 3

Operaciones de comparación
Expresión Resultado
Igual ("==" o "eq") #{"hola" eq "hola"} true
Diferente ("!=" o "ne") #{20 ne 20} false
Mayor ("gt") #{30 gt 20} true
Menor ("lt") #{10 lt 20} true
Mayor o igual ("ge") #{11 ge 22} false
Menor o igual ("le") #{12 le 12} true

Nota evitar el uso de los símbolos < y > para las comparaciones por las reglas de XML

Operaciones lógicas
Expresión Resultado
Disyunción ("or") #{(1 ne 1) or (5 ne 6)} true
Conjunción ("and") #{(1 ne 1) and (5 ne 6)} false
Negación ("!") #{!(1 eq 2)} true

El operador "empty" verifica si un contenido es vacío o nulo y retornará verdadero o falso según sea el caso. Se puede ejemplificar mediante
  • #{empty ""}
  • #{empty null}
Ambos ejemplos devolverán "true", si tenemos un valor capturado que es nulo entonces la siguiente expresión también devolverá "true"
  • #{empty clase.atributo}


Condicionales en EL

Para hacer uso de estos se emplea el operador ternario con la sintaxis:
  • #{ condición ? valorTrue : valorFalse}

Ejemplo:

<p class=" #{clase.atributo eq 5 ? 'class5' : 'class10'} ">
 
Del ejemplo se comprueba si el atributo recuperado es 5, de ser el caso la clase será "class5", sino será "class10". Tener mucha atención en el uso de comillas simples y dobles.

Otra manera de emplear los condicionales es el atributo "rendered", si este tiene como valor una condición verdadera, el elemento que posee este atributo se hará visible, de lo contrario tendrá visibilidad oculta.

Ejemplo:
<!--  Elemento invisible, porque 11 no es igual a 10 -->
<h:outputText value="Primer saludo" rendered="#{11 eq 10}"/>
<br/>
<!--  Elemento visible porque 10 es igual a 10 -->
<h:outputText value="Segundo saludo" rendered="#{10 eq 10}"/>


Resultado visual:
  • Segundo saludo




miércoles, 10 de junio de 2020

Java Server Faces Page Navigation

Antes de la versión 2.0 de JSF se debía crear reglas de navegación en el archivo faces-config.xml y declarar el destino en el método, pero desde esta versión se puede reemplazar ambos simplemente declarando un valor de retorno String como se muestra en el siguiente "Bean"

package proyectoJSF.view;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class NavigationView {

   private String mensaje;

   public String viaje1() {
      mensaje = "Llego al destino #1";
      return "destino1"; // return "destino.xhtml"
   }
 
   public String viaje2() {
      mensaje = "Llego al destino #2";
      return "destino2?faces-redirect=true";
   }
 
   public void viaje3() {
      mensaje = "Llego al destino #3";
      //retorno vacío o "null"
   }

   /* Métodos Setter y Getter*/
   public String getMensaje() {
      return mensaje;
   }

   public void setMensaje(String mensaje) {
      this.mensaje = mensaje;
   } 

}

Y tendríamos la siguiente estructura de archivos html y xhtml

Donde los códigos son:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Proyecto Demo de JSF</title>
</head>
<body>
   <h1>Probando JSF</h1>
   <hr />
   <a href="prueba1.xhtml">Prueba #1</a>
   <br/><br/>
   <a href="prueba2.xhtml">Prueba #2</a>
</body>
</html>

prueba2.xhtml
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:f="http://xmlns.jcp.org/jsf/core"
 xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
   <title>Prueba 02</title>
</h:head>
<h:body>
   <h1>Navegación</h1>
   <h:form>
      <h:commandButton value="Viaje 1" action="#{navigationView.viaje1()}">
      </h:commandButton>
      <br/><br/>
      <h:commandButton value="Viaje 2" action="#{navigationView.viaje2()}">   
      </h:commandButton>
      <br/><br/>
      <h:commandButton value="Viaje 3" action="#{navigationView.viaje3()}">
         <f:ajax execute="@form" render=":salida" />
      </h:commandButton>
   </h:form>
   <h:outputText id="salida" value="#{navigationView.mensaje}" />
</h:body>
</html>

destino1.xhtml y destino2.xhtml tienen un código similar
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
   <title>Destino 01</title>
</h:head>
<h:body>
   <h1>Bienvenido al destino 01</h1>
   <h:outputText id="output" value="#{navigationView.mensaje}" />
</h:body>
</html>

Con el siguiente resultado visual en prueba2.xhtml:

Clic en la miniatura para ver la imagen completa


Y los resultados de cada uno de los botones, mostrando la navegación entre páginas.


Clic en la miniatura para ver la imagen completa

Java Server Faces Tag Library

Componentes estándar de HTML 

JSF proporciona un conjunto de componentes para crear HTML con la ayuda de la tecnología de visualización Facelets.

Esos componentes HTML están disponibles en el URI (Uniform Resource Identifier) http://xmlns.jcp.org/jsf/html que debe asignarse al prefijo "h" del espacio de nombres XML como se muestra en el siguiente código en la línea 4:
<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Título</title>
    </h:head>
    <h:body>
        <!--Cuerpo de la página-->
    </h:body>
</html>

Los elementos más importantes para una página JSF deben ser los de <h:head> y <h:body> para luego incluir dentro los demás componentes HTML, sin estos la tecnología JSF no podrá incluir a los recursos de JS u hojas de estilo que se asocian con determinados componentes.

El código anterior generaría una página HTML como la siguiente:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Título</title>
    </head>
    <body>
        <!--Cuerpo de la página-->
    </body>
</html>

Tabla de componentes HTML de JSF
Component tag (Etiqueta del componente) Superclase del componente Salida en HTML
U<h:column> UIColumn <td>
U<h:commandButton> UICommand <input type="submit">
U<h:commandLink> UICommand <a onclick="form.submit()">
U<h:commandScript> UICommand <script>
U<h:dataTable> UIData <table>
U<h:form> UIForm <form method="post">
U<h:graphicImage> UIGraphic <img>
U<h:inputFile> UIInput <input type="file">
U<h:inputHidden> UIInput <input type="hidden">
U<h:inputSecret> UIInput <input type="password">
U<h:inputText> UIInput <input type="text">
U<h:inputTextarea> UIInput <textarea>
U<h:selectBooleanCheckbox> UIInput <input type="checkbox">
U<h:selectManyCheckbox> UIInput <table><input type="checkbox">
U<h:selectManyListbox> UIInput <select multiple size="n"><option>
U<h:selectManyMenu> UIInput <select multiple size="1"><option>
U<h:selectOneListbox> UIInput <select size="n"><option>
U<h:selectOneMenu> UIInput <select size="1"><option>
U<h:selectOneRadio> UIInput <table><input type="radio">
U<h:selectOneRadio group> UIInput <input type="radio" name="group">
U<h:message> UIMessage <span>
U<h:messages> UIMessages <ul>
U<h:messages layout=table> UIMessages <table>
U<h:button> UIOutcomeTarget <button onclick="window.location">
U<h:link> UIOutcomeTarget <a>
U<h:body> UIOutput <body>
U<h:doctype> UIOutput <!DOCTYPE>
U<h:head> UIOutput <head>
U<h:outputFormat> UIOutput <span>
U<h:outputLabel> UIOutput <label>
U<h:outputText> UIOutput <span>
U<h:outputScript> UIOutput <script>
U<h:outputStylesheet> UIOutput <link rel="stylesheet">
U<h:panelGrid> UIPanel <table>
U<h:panelGroup> UIPanel <span>
U<h:panelGroup layout=block> UIPanel <div>


Componentes estándar del Core

JSF proporciona un conjunto de componentes "Core" que dan soporte a configurar declarativamente uno o más componentes de destino HTML.

Esos componentes HTML están disponibles en el URI (Uniform Resource Identifier) http://xmlns.jcp.org/jsf/core que debe asignarse al prefijo "f" del espacio de nombres XML como se muestra en el siguiente código en la línea 5:
<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Título</title>
    </h:head>
    <h:body>
        <!--Cuerpo de la página-->
    </h:body>
</html>

Dentro del tenemos:
Core tag Constructores o manejadores Componente destino
<f:actionListener> javax.faces.event.ActionListener ActionSource
<f:ajax> javax.faces.component.behavior.AjaxBehavior ClientBehaviorHolder(s)
<f:attribute> UIComponent#getAttributes() UIComponent
<f:attributes> UIComponent#getAttributes() UIComponent
<f:convertDateTime> javax.faces.convert.DateTimeConverter (Editable)ValueHolder
<f:convertNumber> javax.faces.convert.NumberConverter (Editable)ValueHolder
<f:converter> javax.faces.convert.Converter (Editable)ValueHolder
<f:event> javax.faces.event.ComponentSystemEvent UIComponent
<f:facet> UIComponent#getFacets() UIComponent
<f:importConstants> javax.faces.component.UIImportConstants UIViewRoot
<f:loadBundle> java.util.ResourceBundle UIViewRoot
<f:metadata> javax.faces.view.ViewMetadata UIViewRoot
<f:param> javax.faces.component.UIParameter UIComponent
<f:passthroughAttribute> UIComponent#getPassthroughAttributes() UIComponent
<f:passthroughAttributes> UIComponent#getPassthroughAttributes() UIComponent
<f:phaseListener> javax.faces.event.PhaseListener UIViewRoot
<f:selectItem> javax.faces.component.UISelectItem UISelectOne/UISelectMany
<f:selectItems> javax.faces.component.UISelectItems UISelectOne/UISelectMany
<f:setPropertyActionListener> javax.faces.event.ActionListener ActionSource
<f:subview> javax.faces.component.NamingContainer UIComponents
<f:validateBean> javax.faces.validator.BeanValidator UIForm
<f:validateDoubleRange> javax.faces.validator.DoubleRangeValidator EditableValueHolder
<f:validateLength> javax.faces.validator.LengthValidator EditableValueHolder
<f:validateLongRange> javax.faces.validator.LongRangeValidator EditableValueHolder
<f:validateRegex> javax.faces.validator.RegexValidator EditableValueHolder
<f:validateRequired> javax.faces.validator.RequiredValidator EditableValueHolder
<f:validateWholeBean> javax.faces.validator.BeanValidator UIForm
<f:validator> javax.faces.validator.Validator EditableValueHolder
<f:valueChangeListener> javax.faces.event.ValueChangeListener EditableValueHolder
<f:view> javax.faces.component.UIViewRoot UIComponents
<f:viewAction> javax.faces.component.UIViewAction UIViewRoot
<f:viewParam> javax.faces.component.UIViewParameter UIViewRoot
<f:websocket> javax.faces.component.UIWebsocket UIViewRoot

Herramienta CDI para JSF en Eclipse

Para trabajar con el Framework JSF se debe realizar algunas configuraciones en el IDE, en este caso se procede a la configuración del IDE Eclipse.


Instalación de JBoss Tool Plug-in

La versión estándar para Java EE de Eclipse requiere de una herramienta que pueda dar soporte a CDI.

"CDI define contextos para especificar y gestionar ciclos de vida de bean y utiliza inyección de dependencias para satisfacer las dependencias declaradas de una forma dinámica y con seguridad de tipos. CDI también utiliza un modelo de suceso e interceptor acoplado ligeramente, y proporciona un mecanismo de ampliación portátil potente y flexible para otras infraestructuras para definir sus propios beans de CDI o actualizar los componentes existentes."

Para ello, nos dirigimos al Marketplace de Eclipse como se muestra en la siguiente imagen


Dentro se buscará el complemento "JBoss Tool" y se instalará el mostrado.


Luego se hallarán múltiples elementos, pero solo se requiere la herramienta CDI como se muestra


Luego se debe proceder a aceptar los términos de acuerdo de licencia para posteriormente reiniciar el IDE Eclipse.




Fuente










JSF con Eclipse

Se requiere tener instalados o configurados los siguientes componentes:


Al final tendremos un proyecto Maven de JSF 2.3 con JPA 2.2, Servlets versión 4, JDK 1.8 y Java EE 8

Primer paso: crear un proyecto web dinámico Maven

Crear un nuevo proyecto como se muestra


Seleccionar la opción Maven y luego Maven Project como se muestra


Configurar el proyecto con las siguientes especificaciones


Elegir el Group Id y Artifact Id de su preferencia. Seleccionar la opción war para indicar que se trata de un proyecto Web


Finalmente se obtendrá un proyecto con la siguiente estructura:



Segundo paso: Modificar el archivo pom.xml

El archivo pom.xml se debe modificar de la siguiente manera para indicar la versión 4 de los Servlets, el JDK 1.8 y la versión 8 de Java EE:

<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.jsf</groupId>
   <artifactId>proyectoJSF</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>war</packaging>
   <properties>
      <project.build.sourceEncoding>
         UTF-8
      </project.build.sourceEncoding>
      <project.reporting.outputEncoding>
         UTF-8
      </project.reporting.outputEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
      <failOnMissingWebXml>false</failOnMissingWebXml>
   </properties>
   <dependencies>
      <dependency>
         <groupId>javax</groupId>
         <artifactId>javaee-api</artifactId>
         <version>8.0</version>
         <scope>provided</scope>
      </dependency>
   </dependencies>
</project>

El proyecto se actualizará.


Tercer paso: Configurar el proyecto

Vamos a la opción propiedades haciendo clic derecho sobre el nombre del proyecto y buscamos la opción Project Facets y modificamos los checkbox dela siguiente manera:



Las versiones de JSF y JPA se modificarán manualmente, pero debemos hacer clic en "Further configuration required..." para realizar los siguientes cambios:



Esto provocará que se genere un archivo XML llamado "persistence.xml", pero usualmente en un lugar incorrecto y debemos modificar su ubicación de "src/main/java" a "src/main/resources". Además, de agregar y/o modificar tres archivos XML más llamados "beans.xml", "web.xml" y "faces-config.xml" dentro de la carpeta WEB-INF


El archivo web.xml se debe modificar de la siguiente manera:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
 version="4.0">
 <display-name>proyectoJSF</display-name>
 <servlet>
  <servlet-name>facesServlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>facesServlet</servlet-name>
  <url-pattern>*.xhtml</url-pattern>
 </servlet-mapping>
</web-app>


El archivo faces-config.xml se debe modificar de la siguiente manera:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
 http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
 version="2.3">
</faces-config>


El archivo persistence.xml se debe modificar de la siguiente manera para indicar la versión 2.2 de JPA:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
 version="2.2">
 <persistence-unit name="proyectoJSF">
 </persistence-unit>
</persistence>


El archivo beans.xml se debe modificar de la siguiente manera:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
 http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
 version="2.0" bean-discovery-mode="annotated">
</beans>


Opcionalmente podemos desactivar la validación del JPA para que no se muestre un error en "persistence.xml". Para ello, vamos a las propiedades, luego a "Validation" y realizamos las siguientes modificaciones.


Cuarto paso: crear un Bean y un XHTML

Se ha creado un proyecto que sigue el patrón de diseño MVC donde el controlador es el archivo "web.xml", para tener la vista enlazada a un Bean, crearemos un nuevo paquete llamado: "proyectoJSF/view" y dentro crearemos un nuevo Bean con la herramienta CDI instalada previamente.



Modificamos el código del Bean creado por:

package proyectoJSF.view;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class SaludoView {

 private String input;
 private String output;

 public void submit() {
  output = "Hola estimado " + input;
 }

 public String getInput() {
  return input;
 }

 public void setInput(String input) {
  this.input = input;
 }

 public String getOutput() {
  return output;
 }

}


En la carpeta webapp crearemos dos archivos: "index.html" y "prueba1.xhtml" con los siguientes códigos:
  • index.html
<!DOCTYPE html>
<html>
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Proyecto Demo de JSF</title>
 </head>
 <body>
   <h1>Probando JSF</h1>
   <hr />
   <a href="prueba1.xhtml">Prueba #1</a>
 </body>
</html>

  • prueba1.xhtml
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
   xmlns:f="http://xmlns.jcp.org/jsf/core"
   xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
   <title>Prueba 01</title>
</h:head>
<h:body>
   <h1>Saludando</h1>
   <h:form>
      <h:outputLabel for="input" value="Input" />
      <h:inputText id="input" value="#{saludoView.input}" />
      <h:commandButton value="Submit" action="#{saludoView.submit}">
         <f:ajax execute="@form" render=":output" />
      </h:commandButton>
   </h:form>
   <h:outputText id="output" value="#{saludoView.output}" />
</h:body>
</html>


Tendremos la siguiente estructura en el proyecto:


Quinto paso: Iniciar el proyecto

Debemos agregar el proyecto al servidor una vez que se encuentre activo como se indica:


Luego debe quedar así


Una vez ejecutado el proyecto debemos ir al enlace de prueba #1 e introducir un nombre para ver la respuesta de la página