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:
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:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<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>
<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>
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:
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>
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.
<?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.