Professional Documents
Culture Documents
Primeros pasos
En este capítulo, empezaremos a entender cómo escribir una aplicación rica utilizando
RichFaces.
Con el fin de hacer esto, hemos decidido empezar con un ejemplo sencillo que implementa una
lista de contactos al estilo Ajax. El usuario será capaz de listar, agregar y eliminar contactos, sin
necesidad de recargar la página del navegador.
Vamos a ver cómo algunos componentes importantes de Ajax trabajan y cómo ajaxizaremos
una aplicación JSF utilizando los conceptos del marco de trabajo RichFaces.
Un administrador de contactos
La aplicación de ejemplo es un simple administrador de contactos, tiene una lista de contactos
y un formulario para añadir nuevos contactos. También, puede eliminar un contacto específico
de la lista.
El ejemplo muestra cómo funciona el marco de Ajax y cómo se puede utilizar los componentes
Ajax RichFaces. También utiliza algunos componentes gráficos RichFaces como:
rich:panel, rich:spacer, y rich:separator. Se utiliza el componente
rich:calendar para la entrada de la fecha, y la versión RichFaces de dataTable
(rich:dataTable y rich:column) con capacidad de filtrado automático y de ordenación.
El tema (skin) que hemos elegido puede cambiar editando el nombre del tema en el archivo
web.xml (veremos cómo hacer ésto en los capítulos siguientes).
Creación del nuevo proyecto
Como hemos visto en el capítulo 2, preparándose, a fin de utilizar la seam-gen, abra una
ventana de terminal y vaya al directorio de JBoss Seam. Desde aquí, podrá ejecutar comandos
seam-gen. Antes de ejecutar el comando seam-gen que crea un proyecto nuevo, debemos
configurarlo con los siguientes comandos.
seam setup
Si usted está usando un sistema operativo tipo Unix como GNU/Linux o Mac OS X, use el
siguiente comando:
./seam setup
Después del texto de bienvenida, seam-gen nos hará algunas preguntas acerca de la
configuración del proyecto, nos gustaría tener, para cada pregunta hay una respuesta por
defecto (encerrada entre corchetes) que puede elegir pulsando la tecla Intro.
Las preguntas no son difíciles de entender, vamos a ir a través de ellos y crear nuestro
proyecto para el ejemplo:
Bien, hemos completado la configuración del proyecto. Vamos a ver cómo configurar un
proyecto para la conexión a un DBMS MySQL en el capítulo 4, la Aplicación (cuando
empezemos a hacer la aplicación real), por ahora está bien utilizar la opción predeterminada
respuestas.
Estamos listos para crear el proyecto utilizando los siguientes comandos. Si está utilizando
Microsoft Windows, utilice el siguiente comando:
seam create-project
Si usted está usando un sistema operativo tipo Unix como GNU/Linux o Mac OS X, utilizar el
siguiente comando:
./seam create-project
Si está utilizando el IDE de Eclipse, tiene que importar el proyecto en el área de trabajo (se
describe cómo hacer esto en el capítulo 2). Con otros IDE (como IntelliJ IDEA o NetBeans),
puede abrir el proyecto en la ubicación especificada durante la ejecución de seam-gen.
Plantillas y Facelets
Nuestro nuevo proyecto no sólo tiene el soporte de Facelets incluido, sino también un archivo
de plantilla, en el que se puede editar para agregar nuestras características. Usted lo puede
encontrar en la ruta /view/layout/template.xhtml.
Esta es la estructura que usamos en otras páginas para evitar volver a escribir en varias
ocasiones los mismos componentes en las demás páginas.
Discutamos la página.
Podemos ver la declaración DOCTYPE, que nos dice el tipo de documento que es, y después la
etiqueta <f:view> con las declaraciones de espacio de nombres XML Facelets de las
bibliotecas de componentes que vamos a utilizar. Tenga en cuenta que en esta página, no
usamos los componentes RichFaces (todavía), únicamente está escrito el espacio de nombres
para los componentes de Ajax4JSF (xmlns:a="http://richfaces.org/a4j". Esto es
porque se utiliza la etiqueta <a:loadStyle>. Si desea utilizar los componentes RichFaces,
tiene que incluir el correspondiente xmlns (el espacio de nombres necesario para poder utilizar
todos los componentes RichFaces con el prefijo rich) como sigue:
xmlns:rich=http://richfaces.org/Rich
Vamos a insertarlo como queremos para utilizar los componentes RichFaces en la página
template.xhtml.
Vamos a seguir analizando la página. Nuestro empieza documento (podemos ver las etiquetas
<html>, <head>, <meta>, <title>, y <link>) después de la etiqueta <f:view>.
Encontramos la etiqueta Facelets <ui:include> usada para incluir a otra página llamada
menu.xhtml en la sección body. En el menú superior que puede ser utilizada para toda la
aplicación. También pasamos dentro de la etiqueta ui:param, que incluye la página que
puede que se puede usar (el parámetro es el nombre del proyecto en este caso).
Ahora nos encontramos con un elemento div que contiene el componente estándar
<h:messages>, el cual vamos a reemplazar con el componente RichFaces correspondiente.
Al final del código, hay otra sección div, incluyendo algunos de texto con el enlace del sitio
web de JBoss Seam.
<ui:include src="menu.xhtml">
<ui:param name="projectName"
value="AdvContactManager"/>
</ui:include>
Ahora abra el archivo home.xhtml para la edición, viene con el texto estándar de la
presentación de la seam-gen. Vamos a eliminar la h1 sección y el componente rich:panel
para tener una página en blanco.
Además, podemos añadir el soporte para los componentes de Ajx4JSF mediante la inserción
del espacio de nombres XML en la parte superior de la página. Ahora, la página tiene el
siguiente aspecto:
Tenemos que agregar la estructura para hacer el formulario y la lista de contactos. Vamos a
utilizar una etiqueta estándar h:panelGrid con dos columnas para este fin, así que vamos a
colocar el siguiente código dentro de la sección body ( reemplazando el comentario <!-- my
code -->):
Como puede ver, también hemos añadido un encabezado (h3) y un espaciador entre el
encabezado y h:panelGrid. También se utilizaron dos clases CSS para el panelGrid, pero no
la hemos definido todavía.
Por lo tanto, vamos a abrir el archivo theme.css dentro del directorio stylesheet. Puede ver
algunas clases agregadas por seam-gen, no hay que hacerles caso y sólo agregue el código
CSS siguiente al final del archivo:
form-column {
vertical-align: top;
width: 20%;
}
table-column {
vertical-align: top;
width: 80%;
}
Esas clases simples CSS defininen el ancho de las dos columnas y alineación del contenido en
la parte superior.
El modelo
Tenemos que almacenar la información de contacto en una clase Java. En este caso, no
tenemos el soporte de una base de datos y los datos permanecen en la memoria. En una
aplicación real que vamos a desarrollar en los próximos capítulos vamos a usar MySQL.
Por lo tanto, estaremos utilizando un sencillo Plain Old Java Object (POJO) para almacenar la
información que necesitamos. Vamos a crear una clase de Java llamado ContactBean en el
paquete book.richfaces.scm (carpeta src/main) e insertar el siguiente código:
package book.richfaces.scm;
import java.util.Date;
public class ContactBean {
private String name;
private String surname;
private String email;
private Date birthdate;
public ContactBean() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirthdate() {
return birthdate;
}
public void setBirthdate(Date birthdate) {
this.birthdate = birthdate;
}
}
Como puede ver, esta es una simple clase Java con propiedades privadas, así como
analizadores y modificadores públicos.
El bean administrado
A fin de administrar las acciones de este ejemplo simple (como la inserción de un nuevo
contacto, borrar un contacto, lista de todos los contactos), necesitamos un bean administrado.
Podemos utilizar un bean administrado JSF estándar (lo que tenemos que haces es configurar
el archivo faces-config.xml) o un componente de Seam y hemos elegido la segunda
opción porque no tenemos que configurar nada durante el uso de un componente de Seam.
Nos limitaremos a añadir una anotación a la clase que se va a utilizar (Seam simplifica el
desarrollo de JSF). De todas formas, el código es simple y puede ser utilizado como un bean
administrado estándar de JSF.
Por lo tanto, vamos a crear una clase de Java llamado ContactsManager en el paquete de
book.richfaces.scm (carpeta src/hot). Al principio, la clase está vacía:
package book.richfaces.scm;
public class ContactsManager {
}
En primer lugar, necesitamos un lugar para salvar a nuestra lista de contactos, una lista
estándar de instancias ContactBean. Por lo tanto, vamos a agregar el código para su manejo:
package book.richfaces.scm;
import java.util.ArrayList;
import java.util.List;
Para insertar contactos, creamos una nueva instancia de ContactBean para conectar con el
formulario Insertar nuevo contacto y una acción para insertarlo en la lista. Vamos a añadir el
código que necesitamos dentro de la clase ContactsManager:
Una vez más, tenemos la propiedad newContact con el accesor y modificador, y una acción
insertContact.
Le mostraremos la dos maneras, para que así usted pueda entender por qué el uso de Seam
es más simple.
Uso de la forma normal de JSF, tenemos que editar el archivo faces-config.xml para
decirle JSF que la clase ContactsManager es un bean administrado. Tenemos que agregar
el siguiente código dentro del elemento faces-config:
<managed-bean>
<managed-bean-name>contactsManager</managed-bean-name>
<managed-bean-class>
com.test.manager.ContactsManager
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
No es un código difícil para todos, pero debe detallarse ya que tenemos que describir la clase,
sus propiedades, y declarar el ámbito de aplicación de la clase (que es la sesión en este caso).
Incluso si las herramientas nos ayudan a hacer esta tarea, manteniendo el archivo faces-
config.xml es muy complicado.
Uso de JBoss Seam, lo único que tienes que hacer es anotar la clase ContactsManager,
que se convierte de esta manera:
package book.richfaces.scm;
import java.util.ArrayList;
import java.util.List;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
@Name("contactsManager")
@Scope(ScopeType.SESSION)
public class ContactsManager {
// code...
}
En este caso, sólo se agregaron dos anotaciones, uno (@Name) esto dice a Seam que es un
componente Seam (y también un bean administrado) llamado contactsManager, y el otro
(@Scope) le dice a Seam que la clase tiene ámbito de sesión (por lo que se mantendrá en la
memoria a través de las diversas solicitudes).
Todos las validaciones de datos se realizan en Ajax al introducir los valores en los campos
Nombre y Apellidos, y después de que el botón ha sido pulsado en los demás campos. Pero es
sólo nuestra elección. Además, podemos aprovechar de las anotaciones Validator de Hibernate
para establecer los validadores en los campos, utilizando el soporte para Ajax RichFaces
Validator en f:validation (veremos cómo se hace esto en esta sección).
Con el fin de mostrar otras funcionalidades Ajax, también queremos que el botón Insertar
cambie el título, mientras el usuario está escribiendo su nombre y apellido.
La captura de pantalla siguiente muestra el aspecto final que queremos para el formulario:
El formulario principal
Para describir la caja del formulario, usamos un componente rich:panel con un encabezado.
Dentro de él, ponemos un h:panelGrid con una columna para insertar campos, uno debajo
del otro. Por lo tanto, tenemos el diseño del formulario listo, solo tienen que insertar este código
en el archivo de home.xhtml (sustituir el comentario <!-- Insert new contact form -
->):
<rich:panel>
<f:facet name="header">Insert new contact</f:facet>
<h:form id="fInsertContact">
<h:panelGrid columns="1">
<!-- fields -->
</h:panelGrid>
</h:form>
</rich:panel>
Hemos declarado un panel simple con un encabezado utilizando el facet "header", al declararlo.
Si el header es sólo texto, también puede utilizar el atributo de cabecera de esta manera:
Como puede ver, un panel es fácil de usar y puedes poner lo que quiera dentro de ella.
Además, es totalmente personalizable mediante temas.
f:verbatim tag
Aquí está el código para la descripción de los campos del formulario, inserta en el lugar del
comentario <!--fields -->:
Como podemos ver, en el primer bloque de código (en el campo nombre) tenemos una etiqueta
estándar de JSF h:outputLabel para la inserción de la etiqueta de la entrada y una etiqueta
estándar h:inputText conectado al campo ContactBean con el atributo de valor.
Hacer una versión de Ajax de la componente estándar es sólo una parte de la labor del equipo
RichFaces ha hecho en este componente. De hecho, añadieron una serie de características
interesantes que se pueden utilizar para personalizar su aplicación.
De hecho, proporcionan una mirada altamente personalizable y se sienten con soporte CSS.
Además, puede personalizar cada parte de los componentes mediante la adición de una carilla
para diferentes tipos de mensajes (WARN, INFO, FATAL, ERROR), y personalizar el
"marcador" (por ejemplo, un icono) en consecuencia:
<rich:message for="myComponentId">
<f:facet name="warnMarker">
<h:graphicImage url="/images/warning.png"/>
</f:facet>
<f:facet name="errorMarker">
<h:graphicImage url="/images/error.png"/>
</f:facet>
<f:facet name="passedMarker">
<h:graphicImage url="/images/passed.png"/>
</f:facet>
</rich:message>
Además, puede agregar una cadena de texto passedLabel que se muestra cuando no hay
mensaje de error.
De esta manera, no tenemos que escribir (y mantener!) los mismos validadores en diferentes
campos, que se refieren a la misma entrada.
En nuestro caso, podemos añadir anotaciones de Hibernate Validator a la clase del modelo
(ContactBean).
rich:beanValidator lee y utiliza éstos para decidir la estrategia de validación; la clase
ContactBean se define ahora como sigue:
No es el propósito de este libro para explicar cómo funciona el marco de Hibernate Validator,
pero es sencillo de comprender desde el ejemplo. Si nos fijamos en el método getName,
podemos ver las anotaciones @NotNull y @Length (este último con dos parámetros). Dicen
rich:beanValidator que el campo no debe ser nulo, y que tiene una longitud mínima de
dos caracteres y una longitud máxima de 20 caracteres. En el 99% de las solicitudes, sólo
tenemos que anotar validadores para cada campo y ya está. De todos modos, siempre es
posible agregar otro f:validator con rich:beanValidator con el fin de agregar reglas
de validación específicos.
Si nos fijamos en los otros campos de la clase ContactBean, podemos encontrar otros
validadores como @Email y @Past. Hay otros que se pueden utilizar y usted puede incluso
crear sus propios validadores para un propósito específico.
Agregar Ajax a componentes estándar de JSF: a4j:support
Volviendo al código de forma, después de la etiqueta del validador, podemos ver otra etiqueta,
a4j:support.
Este es el componente más importante de Ajax de la biblioteca y lo coloca como un niño añade
capacidades de Ajax para componentes estándar de JSF. El atributo event se utiliza para
definir el evento de JavaScript que la solicitud se adjuntará el Ajax (en este caso, onkeyup que
dispara un evento para todas las claves que el usuario).
El atributo timeout describe el número de milisegundos (ms) para esperar antes de disparar
la petición Ajax. En este caso, es útil para evitar una gran cantidad de peticiones Ajax, mientras
el usuario está escribiendo.
El atributo ajaxSingle cuenta el marco que acaba de enviar el valor del campo y no para
enviar el formulario completo (sólo necesitamos la fecha que se incluirá en el campo, y los
datos del formulario se presentará haciendo clic en el botón Insertar).
Por último, el atributo reRender contiene el id (s) del componente JSF para "reRender"
después de la petición Ajax. En este caso, queremos actualizar el título de la componente
insertButton, que contiene el valor del campo (contactsManager. newContact.name)
actualizado por la petición Ajax.
<h:form>
<h:inputText value="#{aBean.myText}">
<a4j:support event="onblur" reRender="out1" />
</h:inputText>
</h:form>
<h:outputText
id="out1"
value="#{aBean.myText}" />
Cuando el usuario pone un poco de texto dentro de inputText y presiona la tecla Tab o haga
clic fuera del campo de entrada (onblur evento JavaScript), a4j:support actualizará la
propiedad myText del grano aBean con el texto escrito. Luego se actualizará el outputText
con id="out1".
El campo Apellido obras como el campo Nombre, a diferencia del campo de correo
electrónico no contiene a4j:support y se valida (siempre usando una petición Ajax) cuando el
usuario hace clic en el botón Insertar (a4j:commandButton).
El campo Calendario
En el cuarto campo, se utiliza el componente rich:calendar para obtener la fecha de
nacimiento del contacto. Es muy simple de usar, pero tiene un montón de campos opcionales y
pueden llegar a ser muy poderosos. Se puede utilizar para ajustar el tiempo también. Es
totalmente personalizable, muestra una ventana emergente, y también trabaja con entrada
manual.
En la siguiente captura de pantalla, puede ver cómo aparece cuando el usuario hace clic en el
icono de la derecha para seleccionar la fecha.
Tendremos en cuenta el uso de este componente con mayor profundidad en los capítulos
siguientes.
El más importante es el atributo reRender que le dice al motor de JavaScript que área (s) de
la página o componente debe ser actualizado después de una respuesta Ajax.
Se puede volver a hacer uno o más componentes después de una petición Ajax. Se acepta un
objeto String (un ID de componente o una coma lista de ID separados), Set, Collection, o Array
(pasa a través de EL JSF).
Además, como se puede ver, el valor contiene el nombre y apellidos inserta. Por lo tanto, si el
usuario escribe a John como el nombre y Wilson como el apellido, el valor del título de
a4j:commandButton se convierte en "Insertar John Wilson", y gracias a a4j:support (como
hemos visto en los párrafos anteriores), cambia mientras el usuario está escribiendo.
<h:form>
<a4j:commandButton value="update" action="#{myBean.
anOptionalAction}"
reRender="block1,text1"
</h:form>
<h:panelGroup id="block1">
...
</h:panelGroup>
<h:outputText id="text1" ... />
La lista de contactos
Con el fin de mostrar (y permitir al usuario eliminar) la lista de contactos, que vamos a utilizar la
versión RichFaces del clásico h:dataTable. Funciona de la misma manera, pero es muy útil y
fácil de usar las características mejoradas. Se incluye en una etiqueta rich:panel (esta vez
sin una cabecera, porque vamos a utilizar la de cabecera el facet rich:dataTable).
Usted puede ver el aspecto final en la siguiente captura de pantalla (el botón de borrar se
muestra como un icono X en la última columna de la tabla.)
Aquí está el código que hay que añadir a su página home.xhtml ( reemplazar el comentario <!-
-Contact list -->) a fin de hacer la lista de contactos:
<rich:panel>
<h:form id="fContactsList">
<rich:dataTable id="edtContactsList"
value="#{contactsManager.contactsList}"
var="contact" rows="5" width="100%">
<f:facet name="header">Contact List</f:facet>
<rich:column sortBy="#{contact.name}"
filterBy="#{contact.name}">
<f:facet name="header">Name</f:facet>
<h:outputText value="#{contact.name}"/>
</rich:column>
<rich:column sortBy="#{contact.surname}"
filterBy="#{contact.surname}">
<f:facet name="header">Surname</f:facet>
<h:outputText value="#{contact.surname}"/>
</rich:column>
<rich:column sortBy="#{contact.email}"
filterBy="#{contact.email}">
<f:facet name="header">Email</f:facet>
<h:outputText value="#{contact.email}"/>
</rich:column>
<rich:column align="center">
<f:facet name="header">Birthdate</f:facet>
<h:outputText value="#{contact.birthdate}">
<f:convertDateTime type="date" dateStyle="short"/>
</h:outputText>
</rich:column>
</rich:dataTable>
<h:outputText value="No contacts found"
rendered="#{empty contactsManager.contactsList}"/>
<rich:datascroller id="dsContactsList" for="edtContactsList"
renderIfSinglePage="false" />
</h:form>
</rich:panel>
Como podemos ver, hemos usado una etiqueta rich:dataTable como una etiqueta
h:dataTable estándar (De hecho, hemos utilizado el valor del parámetro var y rows,
respectivamente, para establecer el arreglo de la lista de contactos. El parámetro de rows es la
solicitud variable de alcance para manejar el objeto de la fila actual y el número de filas por
página.).
También hemos utilizado las versiones "ricas" de h:column, rich:column, con el fin de
configurar el filtrado y funciones de ordenación para los campos nombre, apellido, y correo
electrónico. La habilitación de la columna de base para la ordenación y filtrado es muy simple,
sólo tienes que conectar los atributos sortBy y filterBy de rich:column con el campo
que desea ordenar (o filtro).
Esto es porque tenemos que decirle a insertButton que actualice no sólo la forma, sino
también la lista de contactos después de ejecutar la acción.
Con el fin de hacer eso, basta con modificar la propiedad reRender de insertButton
añadiendo el id del formulario de la lista de contactos (fContactList), por lo que el
componente aparece ahora como esta:
<a4j:commandButton
id="insertButton"
action="#{contactsManager.insertContact}"
value="Insert #{contactsManager.newContact.name}
#{contactsManager.newContact.surname}"
reRender="fContactsList,fInsertContact" />
Ahora también se actualizará la lista de contactos que le mostrará el contacto acaba de
insertar.
Este código es sencillo de entender. Cuando el usuario hace clic en el icono de supresión (es
una X de color rojo), la variable contact (que apunta a la instancia ContactBean de la fila de
la tabla seleccionada) se establecerá en la propiedad contactToDelete del bean
contactsManager. Después de eso, la acción contactsManager.deleteContact será
llamado y la instancia será removido de la lista de contactos. Tras la ejecución de la acción, en
el marco RichFaces volverá a visualizar el formulario lista de contactos (de acuerdo con lo
establecido en la propiedad reRender de a4j:commandLink) que muestra la nueva lista
(sin la fila eliminada).
Resumen
En este capítulo, se probó el poder de los componentes de RichFaces construir aplicaciones
AJAX mediante el desarrollo de un ejemplo sencillo.
Usted aprendió los fundamentos de RichFaces paso a paso, desde la creación del proyecto
hasta la modificación del código, utilizando componentes muy importantes (como
a4j:commandButton, a4j:commandLink, rich:dataTable, y rich:messages) y
sus propiedades Ajax (por ejemplo , reRender).
En el próximo capítulo, vamos a empezar a construir una aplicación real (un gestor de
contactos avanzada), utilizando el marco en profundidad.