Primer ejemplo

Ramiro Lago (Mayo 2007)



Empezando el ejemplo

En este ejemplo realizaremos la típica página de validación de usuario y password. Vamos a empezar viendo la organización del proyecto:

La primera página es index.jsp:

Es una sencilla página jsp (no tiene JSF) que contiene un enlace a la página jsp (Login.jsp) con capacidad JSF:


<a href="faces/jsfs/jsf01Login/Login.jsp" target=_blank>Login</a>
	

Las páginas con componentes JSF se sitúan en el directorio /jsf/jsfs/jsf01Login:

La página Login.jsp:



Login.jsp: la primera página con JSF

Su código fuente es:


	<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	    pageEncoding="ISO-8859-1"%>
	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
	<html>
	<head>
		<meta name="locality" content="Spain">
		<meta name="lang" content="es">
		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
		<title>Ejemplo de login</title>
		<meta http-equiv="Pragma" content="no-cache">
		<meta http-equiv="Expires" content="-1">	
	</head>
	
	<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
	<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
	
	<body bgcolor="#FFFF9D">
	<FONT color="#000080" FACE="Arial,Helvetica,Times" SIZE=2>
	<center><H3>Validación</H3></center>
	<HR>
	<br><br>
		<f:view>
			<h:form id="LoginForm" >
				<h:outputText value="Usuario: "/>
				<h:inputText id="usuario" value="#{BeanLogin.usuario}" required="true"/>
				<h:message for="usuario"/>
				<br />
				<h:outputText value="Clave: "/>  
				<h:inputSecret id="clave" value="#{BeanLogin.clave}" required="true"/>
				<h:message for="clave"/>
				<br /><br />	  
				<h:commandButton id="submit" action="#{BeanLogin.getValidacion}" value="Entrar" />
			</h:form>
		</f:view>
	</FONT>
	</body>
	</html>
	

Vamos a comentar los aspectos más importantes del ejemplo:

  1. Empezamos declarando las librerías de etiquetas JSF:
  2. 
    	<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
    	<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
    	
  3. A continuación construimos la jerarquía en forma de árbol de los componentes JSF. Empezamos con f:view, dentro del que se encuentra h:form. Dentro de éste se encuentran los campos de texto (h:inputText), botón (h:commandButton), etc.


  4. Asociamos cada componente de entrada de texto del formulario con un atributo del bean, por ejemplo:
    
    			<h:inputText id="usuario" value="#{BeanLogin.usuario}" required="true"/>
    			<h:inputSecret id="clave" value="#{BeanLogin.clave}" required="true"/>
    	
    Estamos hablando de JavaBeans (al estilo de los que usamos en los jsp), por tanto cada atributo tendrá su correspondientes métodos setAtributo() y getAtributo(); ver capítulo dedicado a los JavaBeans. Si no es así, obtendremos un error en ejecución. A continuación hemos simulado errores o ausencia de los métodos set/get del atributo 'usuario':
    
    		javax.faces.FacesException: Can't set managed bean property: 'usuario'.
    	
    Al iniciarse la página los componentes tendrán el valor definido para su correspondiente atributo en faces-config.xml (salvo h:inputSecret que aparecerá vacio, se ponga lo que se ponga en faces-config.xml). Ejemplo parcial de config-faces.xml:
    
    		<managed-property>
    			<property-name>usuario</property-name>
    			<property-class>java.lang.String</property-class>
    			<value>Pedro</value>
    		</managed-property>
    		<managed-property>
    			<property-name>clave</property-name>
    			<property-class>java.lang.String</property-class>
    			<value>password</value>
    		</managed-property>
    	


  5. Asociamos las 'action' con los métodos necesarios. En nuestro bean tenemos un método (BeanLogin.getValidacion()) que será invocado cuando se pulse el botón. La línea en Login.jsp es:
    
    		<h:commandButton id="submit" action="#{BeanLogin.getValidacion}" value="Entrar" />
    	
    El código del bean es:
    
    	package jsf01Login;
    	
    	public class BeanLogin {
    	
    		private String usuario = new String("Juan");
    		private String clave;
    		
    		public void setUsuario( String usuario) {
    			this.usuario = usuario;
    		}
    		
    		public String getUsuario() {
    			return usuario;
    		}
    		
    		public void setClave( String clave ) {
    			this.clave = clave;
    		}
    		
    		public String getClave() {
    			return clave;
    		}
    		
    		public String getValidacion() {
    			if ( usuario.equals( "Pedro") && clave.equals("Pedro"))
    				return "si";
    			else
    				return "no";
    		}
    	}
    	
    Este método devuelve una cadena, que estará definida en una regla de navegación de faces-config.xml. Por ejemplo, si el método devuelve "si", entonces se mostrará la página Bienvenido.jsp, es decir, si el bean nos dice que se ha validado el usuario/clave, entonces pasamos a la página de bienvenida.
    
    	<navigation-rule>
    		<from-view-id>/jsfs/jsf01Login/Login.jsp</from-view-id>
    		<navigation-case>
    			<from-outcome>si</from-outcome>
    			<to-view-id>/jsfs/jsf01Login/Bienvenido.jsp</to-view-id>
    		</navigation-case>
    	</navigation-rule>
    	
    Una acción no tiene que estar asociada necesariamente con un método del bean. Hay otra forma de especificar una acción: señalando directamente un literal, por ejemplo 'success'; pero en este caso el literal se ha definido en faces-config.xml como uno de los resultados/acciones esperados por la página jsp. En otro ejemplo podríamos indicar que de una acción 'succes' de la página greeting.jsp se deriva la página response.jsp:
    
      <navigation-rule>
        <from-view-id>/greeting.jsp</from-view-id>
        <navigation-case>
            <description>
                Indicates to the NavigationHandler that the response.jsp
                view must be displayed if the Action referenced by a 
                UICommand component on the greeting.jsp view returns 
                the outcome "success".
            </description>
          <from-outcome>success</from-outcome>
          <to-view-id>/response.jsp</to-view-id>
        </navigation-case>
      </navigation-rule>
    	


El archivo faces-config.xml

Veamos el código fuente completo:


<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

	<faces-config>
	
		<navigation-rule>
			<from-view-id>/jsfs/jsf01Login/Login.jsp</from-view-id>
			<navigation-case>
				<from-outcome>si</from-outcome>
				<to-view-id>/jsfs/jsf01Login/Bienvenido.jsp</to-view-id>
			</navigation-case>
		</navigation-rule>
	
		<navigation-rule>
			<from-view-id>/jsfs/jsf01Login/Login.jsp</from-view-id>
			<navigation-case>
				<from-outcome>no</from-outcome>
				<to-view-id>/jsfs/jsf01Login/Fallo.jsp</to-view-id>
			</navigation-case>
		</navigation-rule>
	
		<navigation-rule>
			<from-view-id>/jsfs/jsf01Login/Fallo.jsp</from-view-id>
			<navigation-case>
				<from-outcome>volver</from-outcome>
				<to-view-id>/jsfs/jsf01Login/Login.jsp</to-view-id>
			</navigation-case>
		</navigation-rule>
	
	
		<managed-bean>
			<description>The "backing file" bean</description>
			<managed-bean-name>BeanLogin</managed-bean-name>
			<managed-bean-class>jsf01Login.BeanLogin</managed-bean-class>
			<managed-bean-scope>session</managed-bean-scope>
			<managed-property>
				<property-name>usuario</property-name>
				<property-class>java.lang.String</property-class>
				<value>Pedro</value>
			</managed-property>
			<managed-property>
				<property-name>clave</property-name>
				<property-class>java.lang.String</property-class>
				<value>password</value>
			</managed-property>
		</managed-bean>
	</faces-config>
	

Características más relevantes:

  1. La definición de etiquetas se hace en web-facesconfig_1_1.dtd.


  2. A continuación hay una regla de navegación que indica: "Si estamos en la página /jsfs/jsf01Login/Login.jsp y el resultado (acción) es "si", entonces nos dirijimos a /jsfs/jsf01Login/Bienvenido.jsp. Es decir, si el bean nos dice que se ha validado el usuario/clave, entonces pasamos a la página de bienvenida.


  3. Otra regla, si en /jsfs/jsf01Login/Login.jsp el método de validación del bean responde "no", entonces el control pasa a /jsfs/jsf01Login/Fallo.jsp.


  4. La siguiente regla también expresa algo bastante sencillo: si en la página Fallo.jsp la acción es "volver", entonces volvemos a la página Login.jsp


  5. Por último especificamos el bean. El bean-name es el nombre con el que será conocido en las etiquetas JSF. El bean-class será la identificación o localización física de la clase (en nuestro caso está en WEB-INF/classes/jsf01Login). bean-scope indica que el bean se mantiene 'vivo' a lo largo de la sesión. JSF hace que el trabajo de instanciar el bean quede oculto al programador. Lo que sigue son las etiquetas property, por medio de las que indicamos los atributos del bean que serán accesibles desde las etiquetas JSF.


El resto de archivos jsp

Cuando la página de Login responde "si", damos la bienvenida:

El código JSF correspondiente (no olvidar la declaración de librerías de etiquetas) es:


	<f:view>
		<h:form id="LoginForm" >
			<h:outputText value="Bienvenido "/><h:outputText value="#{BeanLogin.usuario}"/>
    		</h:form>
    	</f:view>
	

Cuando la página de Login responde "no", mostramos el fallo y damos la posibilidad de volver:

El código JSF correspondiente (no olvidar la declaración de librerías de etiquetas) es:


	<f:view>
		<h:form id="LoginForm" >
			<h:outputText value="No se le permite el acceso "/><h:outputText value="#{BeanLogin.usuario}"/>
			<%-- En Login.jsp la accion esta asociada a un método; aqui la acción esta asociada
				 a una etiqueta ('volver'). Ver en 'faces-config' que aparece 'volver' como <from-outcome> de
				 una regla --%>
			<p>
			<h:commandLink action="volver">
				<%-- En vez de commandButton puede hacerse un enlace 'clásico' con <h:outputText value="Volver"/> --%>
				<h:commandButton id="submit" value="Volver" />
			</h:commandLink>
			</p>
    		</h:form>
    	</f:view>	
	


Validación

En este primer ejemplo la validación es muy sencilla, nos limitamos a exigir que los campos de texto sean rellenados. En la siguiente pagina vemos lo que ocurre si el usuario deja vacío el campo dedicado a la clave:

Para ello usaremos el atributo 'required'. Ejemplo:


				....
				<h:inputText id="usuario" value="#{BeanLogin.usuario}" required="true"/>
				<h:message for="usuario"/>
				<br />
				<h:outputText value="Clave: "/>  
				<h:inputSecret id="clave" value="#{BeanLogin.clave}" required="true"/>
				<h:message for="clave"/>
				....
	

No debemos olvidar la etiqueta h:message, que indica que se mostrarán los mensajes asociados al campo correspondiente.



web.xml


<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE web-app PUBLIC
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <display-name>Ejemplos de JSF</display-name>
    <description>
        Ejemplos de JSF
    </description>

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
	<context-param>
    	<param-name>javax.faces.CONFIG_FILES</param-name>
	    <param-value>/WEB-INF/faces-config.xml</param-value>
	</context-param>

    <context-param>
        <param-name>com.sun.faces.validateXml</param-name>
        <param-value>true</param-value>
        <description>
            Set this flag to true if you want the JavaServer Faces
            Reference Implementation to validate the XML in your
            faces-config.xml resources against the DTD.  Default
            value is false.
        </description>
    </context-param>

    <context-param>
        <param-name>com.sun.faces.verifyObjects</param-name>
        <param-value>true</param-value>
        <description>
            Set this flag to true if you want the JavaServer Faces
            Reference Implementation to verify that all of the application
            objects you have configured (components, converters,
            renderers, and validators) can be successfully created.
            Default value is false.
        </description>
    </context-param>
    <!-- Faces Servlet -->
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>


    <!-- Faces Servlet Mapping -->
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
</web-app>

	

Lo esencial es la definición del url-pattern del servlet controlador JSF, este servlet es el responsable de interceptar las peticiones JSF y preparar el contexto JSF. Consulte el capítulo dedicado al ciclo de vida de las peticiones JSF. Observe que este patrón (/faces/*) coincide con la URI de la llamada en el index.jsp:


<a href="faces/jsfs/jsf01Login/Login.jsp" target=_blank>Login</a>
	

Si no hubiera coincidencia el servlet no interceptaria la petición y no podría preparar el contexto JSF.




Volver al índice