Curso de JSF

Características

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.

Implementa el controlador y me da una ayuda con la vista. Conceptualmente struts2 y jsf hacen lo mismo. Hay que tener cuidado al meter código javascript en un documento con etiquetas JSF, se mezclan mal.

El código html y javascript generado por jsf:

  • es difícil de entender. El generado por struts2, no.
  • no debe ser modificado. Esto implica problemas cuando queremos crear o modificar tags de JSF.

Por otra parte, JSF es un estandar de java, de hecho utiliza las librerías JSTL.

Existen varias implementaciones de jsf:

MyFaces
RichFaces (quizás la más utilizada)
IceFaces

Cada versión implementa el standard, además te da sus propios tags.

El autor de Struts1 hizo JSF 1.

Hola mundo – redireccionamiento directo

index.html<meta http-equiv="Refresh" content= "0; URL=holaMundo.faces"/>
web.xml
En jsf todo lo que está mapeado con faces se redirige al servlet faces.

<servlet>
      <servlet-name>Faces Servlet</servlet-name>
      <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
</servlet>   
<servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>*.faces</url-pattern>
</servlet-mapping>  
faces-config.xml
<?xml version="1.0"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
	version="1.2">
 </faces-config>
holaMundo.jsp
hola Mundo!

Una redirección a holaMundo.faces irá a holaMundo.jsp cargando el context de JSF (FacesContext). A partir de ese momento será posible utilizar las etiquetas de JSF.Falta enlace a projecto jsf: a_holaMundo.zip

Saludar – el action es un parámetro de navegación

saludar.jsp
<html>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

Las etiquetas de JSF deben estar dentro de las etiquetas <f:view>, las cuales sulen comenzar inmediatamente después de <body> y terminar inmediatamente antes de </body>
<f:view>
	<h:form>
		<h:outputText value="#{msgs.inicioSaludo}" />
		<h:inputText value="#{SaludarBB.nombre}" />
Las etiquetas de JSF que utilicen el atributo action deben ir dentro de la etiqueta <h:form>
		<h:commandButton action="next" />
	</h:form>
</f:view>
</html>
messages.properties
inicioSaludo =hola, introduce tu nombre
hola= hola
web.xml
<servlet>
      <servlet-name>Faces Servlet</servlet-name>
      <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
</servlet>   

<servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>*.faces</url-pattern>
</servlet-mapping>
faces-config.xml
<navigation-rule>
	<from-view-id>/saludar.jsp</from-view-id>
	<navigation-case>
	Tendremos un solo <from-view-id> por cada <navigation-rule>
		<from-outcome>next</from-outcome>
		<to-view-id>/pagina2.jsp</to-view-id>
	</navigation-case>
</navigation-rule>
<managed-bean>
	<managed-bean-name>SaludarBB</managed-bean-name>
	<managed-bean-class>com.pablomonteserin.beans.SaludarBB</managed-bean-class>
	<managed-bean-scope>session</managed-bean-scope>
</managed-bean>   
<application>
	<resource-bundle>
	Esto referencia al fichero messages.properties  colocado en com.pablomonteserin
		<base-name>com.pablomonteserin.messages</base-name>
		<var>msgs</var>
	</resource-bundle>
</application>
SaludarBB.java
package com.pablomonteserin.beans;

public class SaludarBB {
	private String nombre;

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}
	
}
<f:view>	
	<h:outputText value="#{msgs.hola}" />&nbsp;
	<h:outputText value="#{SaludarBB.nombre}" />
</f:view>

Saludar – el action es un método del BackingBean

index.jsp
<html>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<f:view>
	<h:form>
		<h:outputText value="#{msgs.inicioSaludo}" />
		<h:inputText value="#{SaludarBB.nombre}" />
		<h:commandButton action="#{SaludarBB.saludar}"/>
	</h:form>

		
	<h:outputText value="#{msgs.hola}" />&nbsp;
	<h:outputText value="#{SaludarBB.nombre}" />
</f:view>
</html>
messages.properties
inicioSaludo = hola, introduce tu nombre
hola= hola
web.xml
<servlet>
	<servlet-name>Faces Servlet</servlet-name>
	<servlet-class>javax.faces.webapp.FacesServlet
	</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>   

<servlet-mapping>
	<servlet-name>Faces Servlet</servlet-name>
	<url-pattern>*.faces</url-pattern>
</servlet-mapping>
faces-config.xml
<navigation-rule>
	<from-view-id>/saludar.jsp</from-view-id>
	<navigation-case>
		<from-outcome>next</from-outcome>
		<to-view-id>/pagina2.jsp</to-view-id>
	</navigation-case>
</navigation-rule>
<managed-bean>
	<managed-bean-name>SaludarBB</managed-bean-name>
	<managed-bean-class>com.pablomonteserin.beans.SaludarBB</managed-bean-class>
	<managed-bean-scope>session</managed-bean-scope>
</managed-bean>   
<application>
	<resource-bundle>
		<base-name>com.pablomonteserin.messages</base-name>
		<var>msgs</var>
	</resource-bundle>
</application>
SaludarBB.java
package com.pablomonteserin.beans;

public class SaludarBB {
	private String nombre;
	public String getNombre() {
		return nombre;
	}
	public void setNombre(String nombre) {
		this.nombre = nombre;
	}
	public String saludar(){
		//busqueda en BD, etc...
/*devolvemos el parámetro de  navegación,
 equivalente a SUCCESS de struts */
		return "next";
	}
}

Saludar con parámetros

saludar.jsp
...
<h:outputFormat value="Hola, que pasa {0}">
	<f:param value="#{SaludarBB.nombre}" />
</h:outputFormat>
<h:outputFormat value="#{msgs.hola}">
	<f:param value="#{SaludarBB.nombre}" />
</h:outputFormat>	
messages.properties
hola=Hola {0}

Ejercicio – sumador

Hacer una aplicación que sume dos números:

Cargar una Combo

Podemos poner explícitamente las option de la combo…

<h:selectOneMenu  value="#{OperaBB.op}">
		<f:selectItem itemLabel="suma" itemValue="suma" />
		<f:selectItem itemLabel="resta" itemValue="resta" />
		<f:selectItem itemLabel="multiplicacion" itemValue="multiplicacion" />
		<f:selectItem itemLabel="division" itemValue="division" />
</h:selectOneMenu>
… o recuperar las combos del Backing Bean:
//Estas operaciones las recuperaríamos de la base de datos
//Para este método no es necesario declarar su correspondiente atributo, ya que sólo vamos a querer recuperarlo, no modificarlo-
//De esta forma, nos evitamos tener cargado en memoria grandes colecciones de datos.
		
<h:selectOneMenu  value="#{OperaBB.op}">
	<f:selectItems value="#{OperaBB.operaciones}"/>
</h:selectOneMenu>

public ArrayList<SelectItem> getOperaciones(){
	ArrayList<SelectItem> al = new ArrayList<SelectItem>();
	al.add(new SelectItem("suma", "+"));
	al.add(new SelectItem("resta", "-"));
	al.add(new SelectItem("multiplicacion", "*"));
	al.add(new SelectItem("division", "/"));
	return al;
}

Error típico

Objetivo inalcanzable, ‘objeto’ devolvió nulo: javax.el.PropertyNotFoundException

Comprobar: que el BackingBean al que estamos llamando:

  • implementa la interfaz Serializable.
  • tiene getters y setters de la propiedad que estamos recuperando.
  • inicializa en su constructor vacío el objeto al que estamos llamando (en caso de que sea un objeto tipo Persona, con propiedades, etc. ) MantenimientoLibroBB(){ libro = new Libro(); ... }
  • En el output text se está llamando a un método del BackingBean en lugar de imprimir el resultado.

Manejo de la sesión y el contexto

En el listener:
HttpSession session = arg0.getSession();
session.setAttribute("sumaTotal", new Integer(0));

ServletContext sc = arg0.getServletContext();
sc.setAttribute("sumaApplication", new Integer(0));
En el bean:
FacesContext context = FacesContext.getCurrentInstance();
Map sessionMap = (Map) context.getExternalContext().getSessionMap();
Map applicationMap = (Map) context.getExternalContext().getApplicationMap();
Imprimir valores en la vista, recogiendolos de la sesión:
<h:outputText value="#{sessionScope.sumaSesion}" />
<h:outputText value="#{applicationScope.sumaApplication}" />

Ejercicio

Hacer una página que me permita ingresar dos números y me muestre:

  • El total de la suma.
  • El total de la suma de los números en sesión.
  • El total de la suma de todas las sumas del contexto.

Componente datatable de JSF

<h:dataTable value="#{LibroBB.libros}" var="libro"
	columnClasses="column1,column2">

	<h:column>
		<f:facet name="header">
			<h:outputText value="precio" />
		</f:facet>
		<h:outputText value="#{libro.precio}" />
	</h:column>

	<h:column>
		<f:facet name="header">
			<h:outputText value="titulo" />
		</f:facet>
		<h:outputText value="#{libro.titulo}" />
	</h:column>

</h:dataTable>

	Notas:
	
		No poner <h:form> dentro de un datatable
		<h:commandLink /> que mandan información a un BackingBean cuyo <managed-bean-scope> es request, no envían la información. Podría ser session.
	

Enlaces en JSF

Esta la etiqueta de JSF para hacer enlaces:

<h:outputLink id="link1" value="http://www.pablomonteserin.com">
texto enlace
</h:outputLink>

<h:commandLink value="Volver a inicio" action="inicio" />

<h:commandLink value="#{libro.id}" action="#{LibroBB.inicioModifica}">
	<f:param value="#{libro.id}" name="libro.id" />
</h:commandLink>

Recuperar un parámetro en JSF no es tan trivial como en Struts 2. Para hacerlo, habrá que utilizar el siguiente código: 
String idString = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("nombreDelParametro");

Ejercicio – librería

Curso de JSF 1

Una combo actualiza el resto de campos del formulario

modificacion.jsp<h:form id="formulario">
<h:selectOneMenu value="#{MantenimientoPacienteBB.paciente.id}" onchange="submit()" immediate="true" valueChangeListener="#{MantenimientoPacienteBB.consultaPaciente}">
	<f:selectItems value="#{MantenimientoPacienteBB.selectItemPacientes}" /> 
</h:selectOneMenu><br/>	
<h:outputText value="Introduzca el nombre" />
<!-- inmediate="true" permite completar una petición sin que el formulario enviado sea validado, enviando sólo los datos enviados-->
<h:inputText id="nombre" value="#{MantenimientoPacienteBB.paciente.nombre}" immediate="true" />
MantenimientoPacienteBB.java
public void consultaPaciente(ValueChangeEvent e){
	Integer id = (Integer) e.getNewValue();
	paciente=PacienteBO.getPaciente(id);
	//esto para refrescar campos inputtext
	HtmlInputText inputTextGP = (HtmlInputText)FacesContext.getCurrentInstance().getViewRoot().findComponent("formulario:nombre");
	inputTextGP.setValue(paciente.getNombre());
	FacesContext.getCurrentInstance().renderResponse();
}

Ejercicio – hospital

La base de datos tendrá 4 campos: id(PRIMARY KEY, AUTOINCREMENT), nombre (VARCHAR), apellidos (VARCHAR), fecha_alta(DATE).

Para convertir una fecha en un objeto de tipo Date:

SimpleDateFormat formatter = new SimpleDateFormat('dd-MM-yyyy');
Date fecha = formatter.parse(stringFecha'));

Estas conversiones las haremos en el controlador (No modificaremos el pojo paciente para añadirle las propiedades día, mes y año)

Ejercicio calculadora con JSF

Curso de JSF 2

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.