Vous êtes sur la page 1sur 18

4

La aplicación
En este capítulo, vamos a comenzar a desarrollar nuestra aplicación web rica!

Vamos a explicar todos los pasos para construir un proyecto vacío de la nada (con seam-gen),
que soporta todas las tecnologías que se necesitan para desarrollar una "verdadera" aplicación
JSF con Ajax.

El objetivo de este libro no sólo debe ser una descripción de una tecnología, sino también
queremos que el lector aprenda sobre el marco RichFaces, mientras que desarrolla de una
aplicación real, de modo que puede estar listo para desarrollar su propia aplicación.

La aplicación que hemos elegido es un administrador de contactos avanzada con una gran
cantidad de "ricas" características que veremos en la siguiente sección.

Después de crear el proyecto, vamos a empezar a buscar en las páginas y entender las
páginas básica generadas así como el formulario de entrada, mientras que vamos haciendo
algunas modificaciones en ellos.

¿ Qué es el lo que vamos a desarrollar ?


El ejemplo que hemos desarrollado en el capítulo 3, primeros pasos fue básica. Ahora, vamos
a desarrollar una aplicación avanzada de administración de contactos con una gran variedad
de funciones.

Durante el desarrollo de todas las características de la aplicación web, vamos a utilizar el


marco Ajax RichFaces tanto como sea posible. También vamos a utilizar los componentes ricos
que pone a nuestra disposición.

La siguiente imagen muestra una maqueta simple de la aplicación que queremos desarrollar:
Características
Aquí está la descripción de las características principales de la aplicación Administrador
Avanzado de Contactos.

Administrador de Grupos
Cada contacto se puede poner en uno o más grupos para una mejor organización de sus
datos. La lista de grupos de contacto que aparece dentro de una lista de colores con una
herramienta de ventana de información emergente que muestra la descripción del grupo.

Subir archivos y notas


El usuario será capaz de asociar los archivos (por ejemplo CV) y notas con "texto enriquecido",
a los contactos. La carga de archivos le permitirá al usuario seleccionar más de un archivo a la
vez y añadir una descripción de cada archivo mediante un asistente de panel modal.

Búsqueda simple
Una simple búsqueda siempre estará disponible para el usuario. Él o ella será capaz de buscar
contactos, filtrar éstos por su nombre y apellido.

El tema del usuario


Cada usuario de la aplicación web puede elegir su propio tema y utilice durante el la sesion.

Multilenguaje
Nuestra aplicación es real. Por lo tanto, aunque no tenga características de RichFaces (pero sí
características JSF/Seam), para dar soporte a diferentes idiomas.
La base de datos: diagrama E-R
Este es el diagrama ER (Entidad-Relación) de la base de datos que vamos a utilizar:

Sobre el diagrama E-R


Un diagrama Entidad-Relación (ER), en definitiva, sirve para representar una base de datos
relacional. En él se describe la información que se almacena en la base de datos en términos
de las entidades y las conexiones entre ellas (relaciones).

Una entidad es un objeto (por ejemplo, una persona o un grupo) que pueden ser identificados
de forma unívoca y es independiente (es decir, que pueden "vivir" solas).

Una relación se describe cómo dos o más entidades relacionadas entre sí.
Tanto las entidades y las relaciones pueden tener atributos. Para encontrar más acerca de los
diagramas ER, se puede leer más en http://en.wikipedia.org/wiki/Entityrelationship_model.

Como puede ver, es bastante simple, todo está en torno a la entidad de contacto. Cada
contacto puede ser también un usuario de la aplicación web (con un nombre de usuario y una
contraseña establecida). Además, los demás campos se puede asociar con un tipo diferente de
campo personalizado (como dirección URL, correo electrónico, etc) y una etiqueta (casa,
trabajo, etc, dependiendo del tipo). Un contacto puede tener una o más direcciones asociadas
con una etiqueta (como el hogar, el trabajo, y así sucesivamente).

Los usuarios pueden crear uno o más grupos de contactos con un color diferente para cada
uno. Por último, una lista de archivos (como un CV o de otro tipo) se puede asociar a cada
contacto.

La base de datos está lista, podemos pasar a crear la estructura del proyecto y la API de
persistencia Java (JPA) con entidades vinculadas a las tablas de base de datos.

¿ Qué es la JPA ?
Hemos hablado acerca de JBoss Seam y Facelets, pero esta es la primera vez que hemos
hablado sobre JPA. La JPA es el acrónimo de Java Persistence API y es el estándar API de
persistencia y mapeo objeto/relacional para la plataforma Java (SE y EE).

Este es otro de los diversos conocimientos de tecnología. Es muy útil para administrar
(consultar, insertar, actualizar) datos persistentes conectado a un DBMS de una forma sencilla.
El concepto principal es la entidad, que es un POJO que normalmente representa una tabla en
una base de datos, y cada instancia de la misma representa una fila individual de la tabla.

Para dar un ejemplo, si desea insertar una nueva fila en una tabla de base de datos, sólo tienes
que crear una instancia de la clase de entidad que representa la tabla, a continuación, rellene
los campos de la entidad con los datos, y llamar al método persistente para insertar una nueva
fila en la base de datos. Usted no tiene que escribir una sola línea de SQL (JPA va a hacer ese
trabajo por usted). Además, cuando se consulta la base de datos, se utiliza un lenguaje similar
al SQL (llamado Java Persistence Query Language (JPQL)) y el resultado será una lista de
objetos (java.util.list), estos encajan perfectamente en una aplicación JSF.

La conexión con las entidades de las tablas es muy sencilla, utilizando anotaciones (dentro de
la propia clase) o los archivos descriptor XML.

Hay algunas buenas implementaciones de la JPA. Vamos a utilizar una de JBoss, puede que
usted conozca: Hibernate. Fue un marco ORM antes de la existencia de la JPA (que tiene
muchas ideas de él) y está incluido en el proyecto que la seam-gen genera para nosotros.

Importar la base de datos


En primer lugar, tenemos que crear una base de datos MySQL llamado advcm_db e importar
el lenguaje de definición de datos (DDL) que crea la estructura de base de datos que vamos
a utilizar.

El archivo DDL de SQL se llamará adv_contact_manager_create.sql y contiene:

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;


SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

CREATE SCHEMA IF NOT EXISTS `advcm_db` DEFAULT CHARACTER SET utf8 ;


USE `advcm_db`;
-- -----------------------------------------------------
-- Table `advcm_db`.`contact`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `advcm_db`.`contact` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`ContactOwner` INT(11) NULL DEFAULT NULL ,
`name` VARCHAR(45) NULL DEFAULT NULL ,
`surname` VARCHAR(45) NULL DEFAULT NULL ,
`email` VARCHAR(255) NULL DEFAULT NULL ,
`company` VARCHAR(255) NULL DEFAULT NULL ,
`username` VARCHAR(20) NULL DEFAULT NULL COMMENT 'null if the user has no access
permission' ,
`password` VARCHAR(20) NULL DEFAULT NULL COMMENT 'null if the user has no access
permission' ,
`createdOn` DATETIME NOT NULL ,
`lastUpdatedOn` DATETIME NOT NULL ,
`lastAccessOn` DATETIME NULL DEFAULT NULL COMMENT 'Only for user with access
permissions (username not null)' ,
`note` TEXT NULL DEFAULT NULL ,
`active` TINYINT(1) NULL DEFAULT '0' ,
PRIMARY KEY (`id`) ,
INDEX `fk_contact_contact` (`ContactOwner` ASC) ,
INDEX `FK38B724204FF86D69` (`ContactOwner` ASC) ,
CONSTRAINT `FK38B724204FF86D69`
FOREIGN KEY (`ContactOwner` )
REFERENCES `advcm_db`.`contact` (`id` ),
CONSTRAINT `fk_contact_contact`
FOREIGN KEY (`ContactOwner` )
REFERENCES `advcm_db`.`contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

-- -----------------------------------------------------
-- Table `advcm_db`.`contact_address`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `advcm_db`.`contact_address` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`ContactId` INT(11) NOT NULL ,
`position` INT(11) NOT NULL DEFAULT '0' ,
`address1` VARCHAR(255) NULL DEFAULT NULL ,
`address2` VARCHAR(255) NULL DEFAULT NULL ,
`postCode` VARCHAR(50) NULL DEFAULT NULL ,
`city` VARCHAR(255) NULL DEFAULT NULL ,
`province` VARCHAR(50) NULL DEFAULT NULL ,
`country` VARCHAR(255) NULL DEFAULT NULL ,
`label` VARCHAR(255) NOT NULL COMMENT 'it is suggested but can be a free text' ,
`createdOn` DATETIME NOT NULL ,
`lastUpdatedOn` DATETIME NOT NULL ,
PRIMARY KEY (`id`) ,
INDEX `fk_ContactAddress_contact` (`ContactId` ASC) ,
INDEX `FK20846D5EA68B411` (`ContactId` ASC) ,
CONSTRAINT `FK20846D5EA68B411`
FOREIGN KEY (`ContactId` )
REFERENCES `advcm_db`.`contact` (`id` ),
CONSTRAINT `fk_ContactAddress_contact`
FOREIGN KEY (`ContactId` )
REFERENCES `advcm_db`.`contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

-- -----------------------------------------------------
-- Table `advcm_db`.`contact_field`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `advcm_db`.`contact_field` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`ContactId` INT(11) NOT NULL ,
`label` VARCHAR(255) NOT NULL COMMENT 'the suggestions on it dipend on type but it
is a free field' ,
`value` VARCHAR(255) NOT NULL ,
`type` VARCHAR(255) NOT NULL COMMENT 'phone, url, email, etc.' ,
PRIMARY KEY (`id`) ,
INDEX `fk_ContactField_contact` (`ContactId` ASC) ,
INDEX `FK387E901BEA68B411` (`ContactId` ASC) ,
CONSTRAINT `FK387E901BEA68B411`
FOREIGN KEY (`ContactId` )
REFERENCES `advcm_db`.`contact` (`id` ),
CONSTRAINT `fk_ContactField_contact`
FOREIGN KEY (`ContactId` )
REFERENCES `advcm_db`.`contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COMMENT = 'It contains the value with a label';

-- -----------------------------------------------------
-- Table `advcm_db`.`contact_file`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `advcm_db`.`contact_file` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`ContactId` INT(11) NOT NULL ,
`fileName` VARCHAR(255) NOT NULL ,
`fileType` VARCHAR(25) NOT NULL ,
`description` TINYTEXT NULL DEFAULT NULL ,
`createdOn` DATETIME NOT NULL ,
`lastUpdatedOn` DATETIME NOT NULL ,
PRIMARY KEY (`id`) ,
INDEX `fk_ContactFile_contact` (`ContactId` ASC) ,
INDEX `FK4C251E3BEA68B411` (`ContactId` ASC) ,
CONSTRAINT `FK4C251E3BEA68B411`
FOREIGN KEY (`ContactId` )
REFERENCES `advcm_db`.`contact` (`id` ),
CONSTRAINT `fk_ContactFile_contact`
FOREIGN KEY (`ContactId` )
REFERENCES `advcm_db`.`contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

-- -----------------------------------------------------
-- Table `advcm_db`.`contact_group`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `advcm_db`.`contact_group` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`ContactOwner` INT(11) NOT NULL ,
`name` VARCHAR(255) NOT NULL ,
`description` TINYTEXT NULL DEFAULT NULL ,
`color` VARCHAR(7) NULL DEFAULT NULL ,
`createdOn` DATETIME NOT NULL ,
`lastUpdatedOn` DATETIME NOT NULL ,
PRIMARY KEY (`id`) ,
INDEX `fk_ContactGroup_contact` (`ContactOwner` ASC) ,
INDEX `FK3890E5A04FF86D69` (`ContactOwner` ASC) ,
CONSTRAINT `FK3890E5A04FF86D69`
FOREIGN KEY (`ContactOwner` )
REFERENCES `advcm_db`.`contact` (`id` ),
CONSTRAINT `fk_ContactGroup_contact`
FOREIGN KEY (`ContactOwner` )
REFERENCES `advcm_db`.`contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

-- -----------------------------------------------------
-- Table `advcm_db`.`contact_in_group`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `advcm_db`.`contact_in_group` (
`Contact` INT(11) NOT NULL ,
`ContactGroup` INT(11) NOT NULL ,
`insertedOn` DATETIME NOT NULL ,
PRIMARY KEY (`ContactGroup`, `Contact`) ,
INDEX `fk_ContactInGroup_Contact` (`Contact` ASC) ,
INDEX `fk_ContactInGroup_ContactGroup` (`ContactGroup` ASC) ,
INDEX `FK85EAE8243BA12EF6` (`Contact` ASC) ,
INDEX `FK85EAE824DB2B7A8` (`ContactGroup` ASC) ,
CONSTRAINT `contact_in_group_ibfk_1`
FOREIGN KEY (`ContactGroup` )
REFERENCES `advcm_db`.`contact_group` (`id` )
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `FK85EAE8243BA12EF6`
FOREIGN KEY (`Contact` )
REFERENCES `advcm_db`.`contact` (`id` ),
CONSTRAINT `FK85EAE824DB2B7A8`
FOREIGN KEY (`ContactGroup` )
REFERENCES `advcm_db`.`contact_group` (`id` ),
CONSTRAINT `fk_ContactInGroup_Contact`
FOREIGN KEY (`Contact` )
REFERENCES `advcm_db`.`contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Seam-gen leerá la estructura de base de datos para generar las entidades JPA para nosotros.
Vamos a ver cómo utilizar esta característica al crear el proyecto.

Crear el proyecto
La creación del proyecto es muy similar a la que hemos usado para el ejemplo en el capítulo 3,
la única diferencia es que ahora se va a conectar nuestro proyecto para el DBMS MySQL. Por
lo tanto, tenemos que configurar de una manera adecuada.

Abra una ventana de terminal y ubíquese en el directorio de la distribución de JBoss Seam,


ejecute el comando siguiente desde aquí, para Microsoft Windows y Unix/Linux/Mac OS X:

Microsoft Windows Unix/Linux/Mac OS X


seam setup ./seam setup

Después de que el texto de bienvenida, vamos a entrar en nuestro nuevo proyecto de datos de
configuración (seam-gen guardará los datos anteriores, por lo que no tiene que volver a escribir
toda la información de configuración):

Pregunta Descripción Respuesta


Introduzca el lugar Este es el directorio en el que queremos Sólo dar intro, ya que es el mismo
de trabajo para sus salvar nuestro nuevo proyecto (que depende que en proyecto de ejemplo.
proyectos de Java de nuestro entorno y preferencias)
(el directorio que
contiene sus
proyectos de Seam)
Ingrese el Es el directorio donde está instalado el (El directorio de JBoss)
directorio servidor de aplicaciones JBoss
predeterminado de
JBoss AS
Introduzca el nombre El nombre de la aplicación AdvContactManager
del proyecto
¿Quieres usar seam-gen también es compatible con No
ICEfaces en lugar de ICEfaces (otro marco de componentes),
RichFaces [n]? pero queremos utilizar RichFaces, así que
pulse Enter
Seleccione un tema Tenemos la opción de seleccionar Solo presione Intro
para RichFaces cualquiera de los temas mostrados para
[classic] (blueSky, nuestro proyecto, tambien podemos
[classic], cambiarlo más tarde, por ahora, el tema
deepMarine, DEFAULT, classic esta bien
emeraldTown,
japanCherry, ruby,
wine)
Este proyecto es Podemos generar un paquete WAR o un Solo presione Intro
empaquetado como un paquete EAR para nuestra aplicación. Nos
EAR (con componentes gustaría una aplicación completa EAR con
EJB) o un WAR (sin soporte EJB
soporte EJB) [ear]
Introduzca el nombre El nombre del paquete que contiene los book.richfaces.advcm
del paquete Java beans de sesión (generado por seam-gen)
para el beans de
sesión
Introduzca el nombre El nombre del paquete que contiene los book.richfaces.advcm
del paquete de Java beans de entidad (generado por seam-gen)
para su beans de
entidad
Introduzca el nombre El nombre del paquete que contiene los book.richfaces.advcm.test
del paquete Java beans para nuestros casos de prueba
para los casos de
prueba
¿Qué tipo de base de Por este simple ejemplo, no usamos mysql
datos se utiliza? ninguna base de datos
Introduzca el Dialecto de Hibernate org.hibernate.dialect.MySQLDialect
dialecto de
Hibernate para la
base de datos
Escriba la ruta del Tiene que ser una ruta de acceso al archivo c:\ruta_controlador_mysql\mysql-
sistema para los JAR del controlador JDBC de MySQL (si no connector-java-5.1.10-bin.jar
controladores jar de lo tiene, puede descargarlo desde
JDBC http://dev.mysql.com/downloads/connector/j/
(la versión actual es
5.1.10-bin.jar)).
Introduzca la clase Clase del Driver JDBC para MySQL com.mysql.jdbc.Driver
para el controlador
JDBC de la base de
datos
Introduzca la URL de conexión a la base de datos jdbc:mysql://localhost:3306/advcm_db
dirección URL de
conexión JDBC de la
base de datos
Introduzca el nombre Usuario de la bases de datos de la root
de la base de datos aplicación
Introduzca la Contraseña de la base de datos de la mysqlpass
contraseña de la aplicación
base de datos
Introduzca el nombre Nombre de la base de datos( está bien sólo pulse Intro
del esquema de base dejar este espacio en blanco)
de datos
Introduzca el nombre (está bien dejar este espacio en blanco) sólo pulse Intro
de catálogo de base
de datos
¿Trabajar con las ¿Usar todas las tablas que están en la base y
tablas que ya de datos?
existen en la base
de datos?
¿Quieres borrar y ¿Borrar la base de datos en cada N y Intro
volver a crear las despliegue?
tablas de base de
datos y los datos en
Import.sql cada vez
que se implante ?

Muy bien, hemos hecho la configuración, y veremos cómo configurarlo para la conexión a un
DBMS MySQL en el siguiente capítulo (cuando vamos a empezar a hacer la aplicación real).
Por ahora las respuestas que está bien utilizar la opción predeterminada.

Estamos dispuestos a crear el proyecto utilizando los siguientes comandos para Microsoft
Windows y Unix / Linux / Mac OS X:

Microsoft Windows Unix/Linux/Mac OS X


seam create-project ./seam create-project

Ahora vamos a crear las entidades de la JPA (nuestro modelo de datos de la aplicación) de
forma automática mediante los siguientes comandos para Microsoft Windows y Unix/Linux/ Mac
OS X:

Microsoft Windows Unix/Linux/Mac OS X


seam generate-model ./seam generate-model

Si está utilizando el IDE de Eclipse, usted tiene que importar el proyecto en el área de trabajo
(que se describe cómo hacer que en el capítulo 2, Introducción). Con otros IDE (IntelliJ o
NetBeans), sólo se puede abrir desde la ubicación en la que he dicho seam-gen para crearlo.

El diagrama de clases
El diagrama de clases siguiente muestra las clases entidad JPA generados por seam-gen:
Como puede ver, no se diferencia mucho del diagrama ER-de hecho, cada clase se
corresponde con cada tabla en la base de datos.

Este es un ejemplo generado de la clase entidad (la entidad ContactGroup). Hemos escrito
algunas partes de la clase, sólo para mostrar algunos puntos relevantes de JPA:

@Entity
@Table(name = "contact_group",
catalog = "adv_contact_manager")
public class ContactGroup implements java.io.Serializable {
private Integer id;
private Contact contact;
private String name;
private Set<ContactInGroup> contactInGroups =
new HashSet<ContactInGroup>(0);
// ... other fields, constructors, getters and setters ...
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ContactOwner", nullable = false)
@NotNull
public Contact getContact() {
return this.contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
@Column(name = "name", nullable = false)
@NotNull
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(cascade = CascadeType.ALL,
fetch = FetchType.LAZY, mappedBy = "contactGroup")
public Set<ContactInGroup> getContactInGroups() {
return this.contactInGroups;
}
public void setContactInGroups(Set<ContactInGroup> contactInGroups)
{
this.contactInGroups = contactInGroups;
}
}

Es sólo una clase normal (con campos, accesores y modificadores) anotado por JPA
(destacamos éstas) que conectan la clase y sus campos con la tabla correspondiente en la
base de datos. Usted puede anotar los campos o el accesor (como en este caso). En ambos
casos, la anotación tiene los mismos efectos.

@NotNull y @Length son anotaciones de Hibernate Validator, que hemos visto en el


capítulo 2. Seam-gen pone algunas anotaciones básicas de Hibernate Validator, pero hay que
completarlas mediante la edición de las clases de entidad (vamos a ver un ejemplo en el
párrafo siguiente).

Otra anotación que debes conocer es JPA @OneToMany que administra la relación con otras
clases de entidad.

Para hacer un ejemplo, la propiedad contactInGroups devuelve todas las instancias


ContactInGroup que están conectados a ContactGroup. De manera sencilla, si tengo una
instancia de ContactGroup, puedo conseguir todos los contactos de ese grupo solo leyendo
esa propiedad.

Algunas modificaciones a las entidades


El uso de la JPA también es conveniente ya que tiene más funciones disponibles, como los
validadores de Hibernate (hemos visto cómo funcionan en el primer ejemplo) y otras
anotaciones útiles que nos ayudan a escribir código limpio.
Seam-gen realiza mucho trabajo por nosotros, pero como toda herramienta automática, no es
perfecto y nos gustaría añadir características a las clases generadas después de la generación
de proyectos.

En este caso, estamos agregando mas validadores Hibernate a nuestras clases de entidad.
Éstos son algunos de utilidad incorporada en los:

 @Length(min=, max=): Comprueba si la longitud de la cadena coincide con valores


mínimo y máximo
 @Max(value=): Comprueba si el valor es menor o igual al valor máximo
 @Min(value=): Comprueba si el valor es superior o igual al valor
 @NotNull: Comprueba si el valor del campo es nulo
 @Email: Comprueba si la cadena se ajusta a la especificación de la dirección de correo
electrónico
 @Range(min=, max=): Comprueba si el valor está entre los valores mínimo y máximo
(incluido)
 @Future: Comprueba si la fecha está en futuro
 @Past: Comprueba si la fecha está en pasado
 @Pattern(regex="regexp", flag=): Comprueba si el que se corresponda con la
expresión regular, habida cuenta de la bandera del partido (ver
java.util.regex.Pattern para más información)
 @Patterns( {@Pattern(...)} ): Al igual que @Pattern, pero para múltiples
expresiones regulares

Usted puede crear sus propios validadores de una manera sencilla. Consulte la documentación
Validadores de Hibernate para ver todas las características de este marco.

Otra característica útil que nos gustaría añadir a nuestras entidades es el representado por las
anotaciones @PrePersist y @PreUpdate. Si un método es anotado con una de estas
anotaciones, será invocado antes de la persistencia de la instancia en la base de datos y antes
de su actualización.

Aquí está el código añadido para la clase de entidad de la sección anterior (la entidad
ContactGroup):

/**
* This method initializes the values before
* the class is persisted
*/
@PrePersist
public void prePersist() {
setCreatedOn(new Date());
setLastUpdatedOn(new Date());
}
/**
* This method initializes the values before
* the class is updated
*/
@PreUpdate
public void preUpdate() {
setLastUpdatedOn(new Date());
}
Aquí usamos las anotaciones @PrePersist y @PreUpdate que nos permiten configurar
automáticamente las propiedades createdOn y lastUpdatedOn (utilizando el
setCreatedOn y métodos setUpdatedOn) sin tener que hacer que cada vez que persisten o
actualización de una entidad. También los utilizan para hacer algo antes de que la entidad se
conserva o actualizada.

También puede utilizar @PreRemove para anotar un método que será llamado después de que
se elimine la instancia correspondiente de la clase de entidad.

Edición de la página de plantilla


Por ahora, nos limitaremos a la edición de esta página para la transformar los componentes
h:messages en RichFaces (rich:messages), que como hemos visto, la caja Ajax
(rich:messages también tiene el mismo atributo como el de la JSF, por lo que no tiene que
modificar nada más).

Para poder usarlo, también tenemos que agregar el espacio de nombres RichFaces que hemos
visto. Por ahora, así se debe de ver la página template.xhtml (algunas partes se han omitido
porque son los mismos que ya antes hemos visto):

<f:view contentType="text/html"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:s="http://jboss.com/products/seam/taglib">
<html>
<head>
...
</head>
<body>
<div class="body">
<rich:messages id="messages"
globalOnly="true"
styleClass="message"
errorClass="errormsg"
infoClass="infomsg"
warnClass="warnmsg"
rendered="#{showGlobalMessages!='false'}"/>
<ui:insert name="body"/>
</div>
...
</body>
</html>
</f:view>

En el próximo capítulo, vamos a añadir las funcionalidades de la plantilla de página, que


queremos compartir a través de las diferentes páginas.

Como puede ver, el atributo rendered del componente rich:messages está controlada por
la expresión EL #{showGlobalMessages!='false'}. showGlobalMessage es un
parámetro Facelet que se puede pasar a la plantilla (¿recuerda el parámetro projectName
pasados al menú, anteriormente?) para forzar no visualizar el componente rich:messages.
La página de menú
Esta es una página incluida (como hemos visto) en la plantilla y es un rich:toolBar con dos
instancias rich:toolBarGroup (uno en la izquierda y otro con alineación a la derecha):

<rich:toolBar
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:rich="http://richfaces.org/rich">
<rich:toolBarGroup>
<h:outputText value="#{projectName}:"/>
<s:link view="/home.xhtml" value="Home"
propagation="none"/>
</rich:toolBarGroup>
<rich:toolBarGroup location="right">
<h:outputText
value="signed in as: #{identity.username}"
rendered="#{identity.loggedIn}"/>
<s:link view="/login.xhtml" value="Login"
rendered="#{not identity.loggedIn}"
propagation="none"/>
<s:link view="/home.xhtml" action="#{identity.logout}"
value="Logout" rendered="#{identity.
loggedIn}"
propagation="none"/>
</rich:toolBarGroup>
</rich:toolBar>

Después de la declaración xmlns (utilizado por Facelets), podemos encontrar los dos grupos
con algunos textos y enlaces dentro. El grupo de la derecha contiene el enlace de entrada al
sistema si el usuario no está conectado, y la información del usuario y el enlace de
desconexión si el usuario se encuentra conectado. Por lo tanto, cuando ningún usuario está
conectado, la página es así:
Cuando un usuario está conectado, aparece como sigue:

Como puede ver, la parte en la parte derecha de la barra de menú cambia según el estado de
la variable identity.loggedIn.

La página de inicio de sesión


Seam-gen genera una página de inicio de sesión estándar que podemos personalizar. Se llama
login.xhtml y usted lo puede encontrar en la ruta /view/. Utiliza las características de
autenticación de JBoss Seam, por lo que se ampliará para incluir a nuestro código de acceso.
Además, utiliza la página template.xhtml que ya hemos visto.

Veamos el código:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0


Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
template="layout/template.xhtml">
<ui:define name="body">
<h:form id="login">
<rich:panel>
<f:facet name="header">Login</f:facet>
<p>Please login here</p>
<div class="dialog">
<h:panelGrid columns="2" rowClasses="prop"
columnClasses="name,value">
<h:outputLabel for="username">
Username
</h:outputLabel>
<h:inputText id="username"
value="#{credentials.username}"/>
<h:outputLabel for="password">
Password
</h:outputLabel>
<h:inputSecret id="password"
value="#{credentials.password}"/>
<h:outputLabel for="rememberMe">
Remember me
</h:outputLabel>
<h:selectBooleanCheckbox id="rememberMe"
value="#{identity.rememberMe}"/>
</h:panelGrid>
</div>
<p>
<i>Note - </i>
You may login with the username 'admin' and a blank password.
</p>
</rich:panel>
<div class="actionButtons">
<h:commandButton value="Login"
action="#{identity.login}"/>
</div>
</h:form>
</ui:define>
</ui:composition>

Una vez más, vemos DOCTYPE y el componente Facelets ui:composition que obtiene los
contenidos que deben incluirse en otro Facelet. Como puede ver, de hecho, después de las
declaraciones xmlns, está la plantilla de atributo que apunta a la página template.xhtml
que hemos visto y lo utiliza como una plantilla.

¿Recuerda el punto de inserción en el cuerpo template.xhtml? ¿Cómo insertar código en


ese momento?

La respuesta es simple: sólo tiene que utilizar la etiqueta <ui:define> y establecer el atributo
de nombre como uno de los puntos de inserción:

<ui:define name="body">
<!—- this code will be inserted -->
</ui:define>

Lo podemos encontrar en nuestra página login.xhtml. Incluye la parte personalizada de la


página login.xhtml, que es el que tiene el formulario de acceso.

Podemos ver el código al declarar <h:form> y el componente <rich:panel> dentro de él.


Contiene las entradas para nombre de usuario y contraseña (y una casilla Recuérdame).
Debajo del panel, existe la etiqueta JSF estándar h:commandButton que llama a la acción de
login. No queremos un inicio de sesión Ajax, así que está bien utilizar un componente de acción
estándar que se redirigirá a la página de inicio después de la sesión se ha completado.

De todos los componentes hay que apuntar a un componente Seam especial llamada
identidad, que administra la fase de inicio de sesión.

No vamos a editar mucho esta página, lo único que se hará es eliminar la sección Note, ya que
no se necesitará:
<p>
<i>Note - </i> You may login with the username 'admin' and a blank
password.
</p>

Así es como aparece la página de inicio:

La página de inicio
La página de inicio (home.xhtml) es una página en blanco con un cuadro que muestra
Powered by seam y Generated by seam-gen.

Por ahora, simplemente borre el código de la caja a fin de obtener una página en blanco, que
se llenará en los capítulos siguientes. El código es el siguiente:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0


Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
template="layout/template.xhtml">
<ui:define name="body">
</ui:define>
</ui:composition>

Y esta es la forma en que aparece (se puede ver la barra de menú que viene de la plantilla):
Resumen
En este capítulo, hemos creado las bases de nuestro proyecto para tener una idea de las
tecnologías de nuestro lado para que sepamos, como construir buenas aplicaciones, mientras
que empecemos a ser más productivos y rápidos.

Hemos visto el proyecto seam proyecto generado por seam-gen e incluye soporte para Ajax y
los componentes ricos (con RichFaces). Además, vimos las plantillas (con Facelets) y la
autenticación de JBoss Seam. También hemos empezado a personalizar un poco las entidades
(agregando anotaciones Hibernate Validator) y el código XHTML.

En el próximo capítulo, vamos a profundizar en el desarrollo de la aplicación utilizando


componentes RichFaces.

Vous aimerez peut-être aussi