JSF 1

Características

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 metodo del BackingBean en lugar de imprimir el resultado.

Ejercicio calculadora

pantallazo calculadora

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.

datatable

<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

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

librería

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)

icono de mandar un mailPreguntame lo que quieras!
Pablo Monteserín
contacta conmigoPablo Monteserín

El servicio de resolución de dudas técnicas es sólo para los usuarios premium. Si tienes cualquier otra duda, usa el formulario de contacto. ¡Gracias!