Capítulo 2. Crear aplicación Web
Modelo GeneralDesarrollo de una aplicacion Web
Dependencias Maven
Usando el Asistente Maven del IDE
Editar el archivo pom.xml
MODELO DESARROLLO
JPA
Proceder a Crear los Entity con NetBeans
Creación de los EJB
CDI vs ManagedBeans
CREAR UN CDI PARA EL MANEJO DE MENSAJES
Código completo del CDI JSFUtil.java
FACELETS
CREAR PLANTILLA FACELETS CON <p:layout> de PRIMEFACES
Código completo de template.xhtml
Editar template.xhtml
Crear la página Index.xhtml
CREAR CDI BEANS ESTATUSCONTROLLER.java
Crear los Facelets Template Client para insertar Estatus
Editar el entity Estatus.java
Editar EstatusFacade.java
Convertidores
Crear EstatusConverter.java
Modelo General
Desarrollo de una aplicacion Web
Este capítulo muestra el desarrollo de la aplicación de ejemplo de Scrum usando tecnologías JEE 7. Esta aplicación permitirá insertar registros en una tabla utilizando JPA, primefaces / JavaServer Faces, EJB, CDI.
Para ello utilizamos:
- NetBeans IDE 8.0.1
- Maven (como parte del IDE)
- GlassFish 4.1
- Base de datos MySQL
1. Crear un proyecto Maven → Web Application desde NetBeans:
2. Indicar Project Name: scrumweb
Group id: com.avbravo (Es el grupo de proyectos al que pertenece nuestro proyecto)
En Settings, seleccionamos GlassFish Server 4.1. y en Java EE Version 7
El IDE genera la estructura del proyecto:
Ahora, vamos a seleccionar Projects → Properties → Configurations → Configurations: <default config> y presionar el botón Activate.
Hacemos clic en la categoría Frameworks
Hacer clic el botón Add, y luego seleccionar JavaServer Faces
En la pestaña Configuration verificar que esté seleccionado la opción Facelets en la opción Preferred Language:
y en la pestaña Components seleccionamos Primefaces
Dependencias Maven
Maven consta de repositorios donde se encuentran las dependencias (bibliotecas .jar) necesarias para ejecutar nuestros proyectos. La ventaja que ofrece es que no es necesario descargar manualmente estas dependencias. Simplemente Maven se encarga de buscarlas y en los repositorios y nos permite agregarlas facilmente. Si una biblioteca depende de otra, Maven se encargará agregar estas dependencias a nuestro proyecto.
Para nuestra aplicación web utilizaremos las siguientes dependencias:
- primefaces all-themes
- mysql
- primefaces
- itext
- jasperreports
- jfreechart
NetBeans nos ofrece dos alternativas para realizarlo: la primera mediante el asistente y la segunda editando el archivo pom.xml que encontramos en Project Files.
Usando el Asistente Maven del IDE
Usaremos la alternativa del asistente del IDE. Para ello, en el nodo “Dependencies” hacer clic derecho y seleccionar Add Dependency...
En el diálogo Add Dependency escribiremos en el campo Query la dependencia a buscar y presionamos la tecla Intro. En ese momento se mostrará un listado con las dependencias locales y remotas y seleccionamos la que deseamos de la lista.
- Para primefaces all-themes (Permite manejar los temas de primefaces)
- Dependencia mysql-connector-java (Para manejar la comunicación con mysql)
- Actualizamos la versión de primefaces a 5.1 (Última versión de primefaces community al momento de escribir este libro)
- Dependencia itext (Utilizado para reportes)
- Dependencia jasperreports (Utilizado para reportes)
- Dependencia jfreechart (Generación de gráficas)
Editar el archivo pom.xml
La segunda alternativa es editar el archivo pom.xml ubicado en Project Files
Podemos escribir directamente la dependencia, o dar clic derecho Insert Code→ Dependency.
Mostrará el diálogo para buscar dependencias.
En el archivo pom.xml ingresamos directamente la dependencia indicando el groupId(generalmente es la organización o empresa que desarrolla), artifactId (nombre del jar), versión (número de versión )
<dependencies>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>5.1</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.primefaces.extensions</groupId>
<artifactId>all-themes</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
y en repositories agregar
<repositories>
<repository>
<url>http://repository.primefaces.org/</url>
<id>PrimeFaces-maven-lib</id>
<layout>default</layout>
<name>Repository for library PrimeFaces-maven-lib</name>
</repository>
Al terminar de agregar las dependencias, hacer clic derecho sobre el ícono del proyecto, y seleccionamos “Build with Dependencies” para descargar las dependencias del proyecto Maven.
Se observa un listado de dependencias
MODELO DESARROLLO
- Java Server Faces ofrece un mecanismo sencillo para el desarrollo de interfaces de usuario web, el modelo será dividido en tres capas (Capa Web, Capa Negocio, Capa de Datos),
Para poder manejar la base de datos MySQL desde NetBeans IDE, se agrega la base de datos desde la pestaña Services→ Databases→ Drivers→ MySQL
Indicar el nombre de la base de datos el usuario y password, y presionar el botón Test Connection, para comprobar que la conexión a la base de datos sea exitosa.
NetBeans IDE nos ofrece un potente editor de consultas y operaciones sobre la base de datos.
Nota: Desde este panel podemos conectarnos a cualquier base de datos, de cualquier tipo, siempre y cuando contemos con el controlador JDBC.
JPA
EL ORM(Object Relational Mapping), predeterminado en JEE7 es JPA, que ofrece un mecanismo sencillo de manejo de registros de las tablas y su equivalente en clases en Java. Generalmente POJOs(Plain Old Java Object), que se denominan Entity, ya que a diferencia de un objeto Java tradicional, el Entity permite que el valor de sus atributos sea almacenado permanentemente en la base de datos.
Los Entity ofrecen una serie de atributos y anotaciones que facilitan el manejo de los mismos, aprovechando las ventajas de la plataforma Java EE7.
Proceder a Crear los Entity con NetBeans
- Desde menú File, seleccione New
- en Categories, seleccione Persistence
- en File Types, seleccione Entity Classes from DataBase
Luego, si no existe el jdbc/scrumweb procedemos a crear el Data Source para nuestra aplicación, para ello seleccionaremos New Data Source...
Seguidamente, indicamos el nombre JNDI que vamos a utilizar. En nuestro caso, usaremos: jdbc/scrumweb
De ahora en adelante, cada vez que queramos referirnos a la base de datos, lo haremos usando JNDI. Seleccionamos Data Source el nombre JNDI que deseamos crear jdbc/scrumweb
Continuamos con el asistente, y cuando nos pregunte que tablas vamos a importar(Available Tables):
Y como queremos importar todas las tablas, hacemos clic en Add All
Notaremos que algunos nombres de tablas se presentarán en color gris; estas son las que dependen de otras tablas, porque tienen una clave foránea, y es necesaria importarla para que la tabla principal pueda funcionar.
Continuamos con el asistente. En el diálogo Entity Classes, muestra las columnas con el nombre de la tabla, clases y tipo de generación.
En el diálogo Mapping Options, dejamos los valores predeterminados en el campo “Collection Type” con el valor java.util.Collection y presionamos el botón “Finalizar”
Se iniciara la generación de los Entity, en base al análisis de las tablas.
En la imagen podrá apreciar los Entity generados, cada uno corresponde a una tabla de la base de datos
Nos ubicamos en Other Sources /src/main/resources y dar clic derecho sobre persistence.xml, seleccionar Open.
se muestra la configuración del archivo persistence.xml, y comprobar que Data Source: muestra jdbc/scrumweb
si damos clic en la pestaña Source, podemos observar la configuración.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="com.avbravo_scrumweb_war_1.0-SNAPSHOTPU" transaction-type="JTA">
<jta-data-source>jdbc/scrumweb</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>
Creación de los EJB
Los “Enterprise Java Beans” son clases especiales en Java que se ejecutan en el Contenedor Java EE. En estos componentes se establece la lógica de negocio para nuestras aplicaciones. Esto nos permite separar limpiamente la lógica de negocio, de la vista y de la capa de datos.
NetBeans nos permite crear estos EJB con el modelo CRUD (Create-Read-Update-Delete) para nuestras Entities de una manera muy rápida de la siguiente manera.
- Desde menú File, seleccione New
- en Categories, seleccione Enterprise JavaBeans
- en File Types, seleccione Session Beans For Entity Classes
Seleccionar de la lista “Available Entity Classes” y presionar el botón Add All>> para generar todos los EJB para nuestras entidades.
En el dialogo Generated Session Beans, indicar el campo “Package” com.avbravo.scrumweb.ejb (Para almacenar en ese paquete los ejb que se generen) y presionar el botón “Finalizar”
Se crean en el paquete com.avbravo.scrumweb.ejb los EJB AbstractFacade.java y un EJB para cada Entity seleccionado.
CDI vs ManagedBeans
JEE7 utiliza por defecto CDI en lugar de ManagedBeans, ya que estos estan más integrados con la plataforma y permiten la inyección de dependencias.
Para utilizarla debemos importar el paquete javax.enterprise.context y deben implementar la interfaz Serializable para los SessionScoped.
por ejemplo
import javax.annotation.ManagedBean;
import javax.enterprise.context.SessionScoped;
los paquetes que corresponden a ManagedBeans ya no se usarán
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
CDI define los alcances
- @Application Scoped: Se mantiene durante toda la ejecución de la aplicacion.
- @SessionScoped: Se mantiene durante la sesion de un unico usuario.
- @RequestScoped: Corresponde a una unica solicitud HTTP o la invocación de un
método. El beans solo persiste mientras el método es
invocado.
- @ConversationScoped: Se mantiene entre multiples invocaciones.
- @Dependent: Es el mismo ciclo que el de un cliente. Un bean dependiente
es creado cada vez que se inyecta y la referencia es removida cuando la inyección es removida.
Utilizamos la anotación @Named para hacer referencia desde las páginas xhtml , se utiliza la siguiente estandarización: si el CDI se llama JSFUtil y se utiliza @Named este se usará en las páginas xhtml como jSFUtil, con la primera letra en minúsculas.
CREAR UN CDI PARA EL MANEJO DE MENSAJES
1. Crear el CDI JSFUtil
- Desde menú File, seleccione New
- en Categories, seleccione Java Server Faces
- en File Types, seleccione JSF ManagedBeans
- Class Name: JSFUtil
- Package com.avbravo.scrumweb.generales
- Scope: request
Se permite seleccionar el Scope (Alcance) en este ejemplo utilizamos request, indicar el paquete generales donde se almacenará.
Código generado por el IDE
Se procede a eliminar la anotación @ManagedBean y será reemplazada por @Named, la importación javax.faces.bean.ManagedBean y javax.faces.bean.RequestScoped se deben eliminar. Ya que estas en depreciadas para usar en su lugar CDI.
Dar Clic derecho-> Fix import y seleccionar javax.inject.Named y javax.enterprise.context.RequestScoped
Se mostrará el código de la siguiente manera:
package com.avbravo.scrumweb.generales;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
*
* @author avbravo
*/
@Named
@RequestScoped
public class JSFUtil {
/**
* Creates a new instance of JSFUtil
*/
public JSFUtil() {
}
}
En el código usaremos métodos para enviar mensajes a los componentes <p:growl> y <h:messages>, y tambien se usara para desplegar diálogos utilizando Dialog Framework.
Por ejemplo el método addSuccessMessage() actualiza el <p:growl> y <h:messages> de la pagina xhtml.
Mientras el método infoDialog() muestran un diálogo con los mensajes utilizando Dialog Framework de Primefaces implementado en la versión 4.0, y no actualiza <p:growl> ni <h:messages> de la pagina xhtml.
Código completo del CDI JSFUtil.java
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.enterprise.context.RequestScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.component.UISelectItem;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.model.SelectItem;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
import org.primefaces.context.RequestContext;
/**
*
* @author avbravo
*/
@Named
@RequestScoped
public class JSFUtil {
public static SelectItem[] getSelectItems(List<?> entities, boolean selectOne) {
int size = selectOne ? entities.size() + 1 : entities.size();
SelectItem[] items = new SelectItem[size];
int i = 0;
if (selectOne) {
items[0] = new SelectItem("", "");
i++;
}
for (Object x : entities) {
items[i++] = new SelectItem(x, x.toString());
}
return items;
}
/*
* logout
*/
public String logout() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
if (session != null) {
session.invalidate();
}
return "/index";
}
public static void addErrorMessage(Exception ex, String defaultMsg) {
String msg = ex.getLocalizedMessage();
if (msg != null && msg.length() > 0) {
addErrorMessage(msg);
} else {
addErrorMessage(defaultMsg);
}
}
public static void addErrorMessages(List<String> messages) {
for (String message : messages) {
addErrorMessage(message);
}
}
public static void addErrorMessage(String msg) {
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
msg, msg);
FacesContext.getCurrentInstance().addMessage(null, facesMsg);
}
public static void testMessage(String msg) {
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
msg, msg);
FacesContext.getCurrentInstance().addMessage(null, facesMsg);
}
public static void addSuccessMessage(String msg) {
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg,
msg);
FacesContext.getCurrentInstance().addMessage("successInfo", facesMsg);
}
public static void addWarningMessage(String msg) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, msg, ""));
}
public static void addFatalMessage(String msg) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL, msg, ""));
}
public static String getRequestParameter(String key) {
return FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(key);
}
public static Object getObjectFromRequestParameter(String requestParameterName,
Converter converter, UIComponent component) {
String theId = JSFUtil.getRequestParameter(requestParameterName);
return converter.getAsObject(FacesContext.getCurrentInstance(), component, theId);
}
public static void infoDialog(String titulo, String texto) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, titulo,
texto);
RequestContext.getCurrentInstance().showMessageInDialog(message);
}
public static void warningDialog(String titulo, String texto) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, titulo,
texto);
RequestContext.getCurrentInstance().showMessageInDialog(message);
}
public static void fatalDialog(String titulo, String texto) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_FATAL, titulo,
texto);
RequestContext.getCurrentInstance().showMessageInDialog(message);
}
public static void errorDialog(String titulo, String texto) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
titulo, texto);
RequestContext.getCurrentInstance().showMessageInDialog(message);
}
public static java.sql.Date converterDate(java.util.Date fecha) {
try {
long lfecha = fecha.getTime();
java.sql.Date dtfecha = new java.sql.Date(lfecha);
return dtfecha;
} catch (Exception e) {
addErrorMessage("converterDate() " + e.getLocalizedMessage());
}
return null;
}
public static java.util.Date getFechaActual() {
java.util.Calendar ca = java.util.Calendar.getInstance();
java.sql.Date mydate = new java.sql.Date(ca.getTimeInMillis());
return new java.sql.Date(mydate.getTime());
}
public static Integer getAnioActual() {
java.util.Calendar ca = java.util.Calendar.getInstance();
java.sql.Date mydate = new java.sql.Date(ca.getTimeInMillis());
return ca.get(Calendar.YEAR);
}
public static Integer getMesActual() {
java.util.Calendar ca = java.util.Calendar.getInstance();
java.sql.Date mydate = new java.sql.Date(ca.getTimeInMillis());
return ca.get(Calendar.MONTH);
}
public static Integer getMesDeUnaFecha(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int anio = calendar.get(Calendar.YEAR);
int mes = calendar.get(Calendar.MONTH) + 1;
int dia = calendar.get(Calendar.DAY_OF_MONTH);
return mes;
}
public static Integer getAnioDeUnaFecha(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int anio = calendar.get(Calendar.YEAR);
int mes = calendar.get(Calendar.MONTH) + 1;
int dia = calendar.get(Calendar.DAY_OF_MONTH);
return anio;
}
public static Integer getDiaDeUnaFecha(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int anio = calendar.get(Calendar.YEAR);
int mes = calendar.get(Calendar.MONTH) + 1;
int dia = calendar.get(Calendar.DAY_OF_MONTH);
return dia;
}
public static Integer getDiaActual() {
java.util.Calendar ca = java.util.Calendar.getInstance();
java.sql.Date mydate = new java.sql.Date(ca.getTimeInMillis());
return ca.get(Calendar.DATE);
}
public static boolean isValidationFailed() {
return FacesContext.getCurrentInstance().isValidationFailed();
}
public static boolean isDummySelectItem(UIComponent component, String value) {
for (UIComponent children : component.getChildren()) {
if (children instanceof UISelectItem) {
UISelectItem item = (UISelectItem) children;
if (item.getItemValue() == null && item.getItemLabel().equals(value)) {
return true;
}
break;
}
}
return false;
}
public static String getComponentMessages(String clientComponent, String defaultMessage) {
FacesContext fc = FacesContext.getCurrentInstance();
UIComponent component = UIComponent.getCurrentComponent(fc).findComponent(clientComponent);
if (component instanceof UIInput) {
UIInput inputComponent = (UIInput) component;
if (inputComponent.isValid()) {
return defaultMessage;
} else {
Iterator<FacesMessage> iter = fc.getMessages(inputComponent.getClientId());
if (iter.hasNext()) {
return iter.next().getDetail();
}
}
}
return "";
}
public static Throwable getRootCause(Throwable cause) {
if (cause != null) {
Throwable source = cause.getCause();
if (source != null) {
return getRootCause(source);
} else {
return cause;
}
}
return null;
}
}
FACELETS
Facelets nos permite manejar un sistema de plantillas y componentes de manera facil.
CREAR PLANTILLA FACELETS CON <p:layout> de PRIMEFACES
Primefaces nos ofrece el componente <p:layout> que nos permite una disposición adecuada de los componentes. A continuación se mostrará una forma sencilla de integrar facelets con <p:layout> para crear una plantilla dinámica para nuestra aplicación web.
- Desde menú File, seleccione New
- en Categories, seleccione Java Server Faces
- en File Types, seleccione Facelets Template
colocar el nombre File Name: template
El IDE genera el archivo templates.xhtml y en la carpeta resources los css
Eliminamos el código que genera y agregamos el código para implementar el layout de primefaces.
Integramos facelets con el componente <p:layout> de primefaces. Teniendo presente que <p:layout> utiliza <p:layoutUnit position="north”> para definir las areas y facelets necesitamos definir el área mediante <ui:insert name="top"> .
Tabla comparativa
Primefaces
|
Facelets
|
north
|
top
|
south
|
bottom
|
west
|
left
|
east
|
Right
|
center
|
center
|
Indicamos que será pagina completa.
|
<p:layout fullPage="true">
|
usamos <p:layoutUnit de primefaces y dentro de el <ui:insert>
|
<p:layoutUnit position="north" size="100" resizable="true" closable="true" collapsible="true">
<ui:insert name="top">
Header
</ui:insert>
</p:layoutUnit>
|
Si deseamos incluir menú en la parte superior y que estos se muestran en sobre otras áreas y no solo sobre la parte superior incluir el css donde se modifica .ui-layout-north y .ui-layout-unit-content
<style type="text/css">
.ui-layout-north {
z-index:20 !important;
overflow:visible !important;;
}
.ui-layout-north .ui-layout-unit-content {
overflow:visible !important;
}
</style>
Cambiar
|
Por
|
<title>Facelets Template</title>
|
<title><h:outputText value="Scrum web"/></title>
|
Agregar dentro del <h:head> el <f:facet name=”first”>, lo usamos para reordenar el contenido en Primefaces. Indicando lo primero que debe cargarse.
|
<f:facet name="first">
<meta content='text/html; charset=UTF8' http-equiv="ContentType"/>
<title><h:outputText value="Scrum web"/></title>
</f:facet>
|
Código completo de template.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view contentType="text/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<h:outputStylesheet name="./css/default.css"/>
<h:outputStylesheet name="./css/cssLayout.css"/>
<f:facet name="first">
<meta content='text/html; charset=UTF8' http-equiv="ContentType"/>
<title><h:outputText value="Scrum web"/></title>
</f:facet>
<style type="text/css">
.ui-layout-north {
z-index:20 !important;
overflow:visible !important;;
}
.ui-layout-north .ui-layout-unit-content {
overflow:visible !important;
}
</style>
</h:head>
<h:body>
<p:layout fullPage="true">
<p:layoutUnit position="north" size="100" resizable="true" closable="true" collapsible="true">
<ui:insert name="top">
Header
</ui:insert>
</p:layoutUnit>
<p:layoutUnit position="south" size="50" closable="true" collapsible="true">
<ui:insert name="bottom">
Footer
</ui:insert>
</p:layoutUnit>
<p:layoutUnit position="west" size="175" header="Left" collapsible="true">
<ui:insert name="left">
Left
</ui:insert>
</p:layoutUnit>
<p:layoutUnit position="center">
<ui:insert name="center"></ui:insert>
</p:layoutUnit>
</p:layout>
<ui:insert name="bottom">
Footer
</ui:insert>
</p:layoutUnit>
<p:layoutUnit position="west" size="175" header="Left" collapsible="true">
<ui:insert name="left">
Left
</ui:insert>
</p:layoutUnit>
<p:layoutUnit position="center">
<ui:insert name="center"></ui:insert>
</p:layoutUnit>
</p:layout>
</h:body>
</f:view>
</html>
Eliminar los archivos index.html e index.xhtml
Crear menu.xhtml
Crear una página Java Server Faces que contendrá las opciones del Menú separadas del template que luego la incluiremos dentro.
- Desde menú File, seleccione New
- en Categories, seleccione Java Server Faces
- en File Types, seleccione JSF Page
Se utiliza el componente <p:megamenu> de primefaces debe estar incluido dentro de un <h:form>.
Utilizaremos menuitem para indicar las opciones a desplegar en el menu.
<p:menuitem value="Insertar" url="/faces/page/estatus/estatusinsert.xhtml" />
la ruta /faces/pages/estatus/ indica que se debe crear la carpeta /page/estatus dentro de Web Pages.
Código completo de menu.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<ui:composition>
<h:form id="menuForm" >
<p:megaMenu>
<p:submenu label="Registros" icon="ui-icon-check">
<p:column>
<p:submenu label="Estatus">
<p:menuitem value="Insertar" url="/faces/page/estatus/estatusinsert.xhtml" />
<p:menuitem value="Listar" url="/faces/page/estatus/estatuslist.xhtml"/>
</p:submenu>
</p:column>
</p:submenu>
</p:megaMenu>
</h:form>
</ui:composition>
</h:body>
</html>
Editar template.xhtml
en el top, colocamos el <ui:include src=”menu.xhtml”/>, mediante el include incluimos en la parte superior de la plantilla el menú que tenemos en menu.xhtml
<p:layout fullPage="true">
<p:layoutUnit position="north" size="100" resizable="true" closable="true"
collapsible="true">
<ui:insert name="top">
<ui:include src="menu.xhtml"/>
</ui:insert>
</p:layoutUnit>
Crear la página Index.xhtml
Ahora creamos un Facelets Template Client
- Desde menú File, seleccione New
- en Categories, seleccione Java Server Faces
- en File Types seleccione Facelets Template Client
en File Name : index
Presionar el botón Browse de Template:
seleccionamos el Template template.xhtml
Se genera el código de la página y colocamos en comentario top,bottom, left. Utilizando
<!-- --> ,de esta manera el área top, bottom,left serán reemplazadas por la definición en el template, y nosotros editamos el área center, donde escribimos los componentes java server faces que deseamos mostrar. En este caso escribimos BIENVENIDOS A SCRUMWEB
Ejecutamos el proyecto
se carga en el browser, podemos observar el layout con el menú y el mensaje de la página index.xhtml que es la primera en cargarse al ejecutar el proyecto.
CREAR CDI BEANS ESTATUSCONTROLLER.java
Estos CDI los utilizamos invocar las diversas operaciones sobre los Entity y asociar los componentes con las páginas Java Server Faces.
- Desde menú File, seleccione New
- en Categories, seleccionamos Java Server Faces
- en File Types, seleccionamos JSF ManagedBeans
- Class Name: EstatusController
- Package: com.avbravo.scrumweb.controller
- Scope: request
Agregamos las anotaciones @Named, @RequestScoped.
Nota: Recordar utilizar javax.enterprise.context.RequestScoped.
Agregamos el EJB inyectandolo mediante @Inject
@Inject
EstatusFacade estatusFacade;
Agregamos el Entity
Estatus estatus = new Estatus();
creamos los get/set del entity estatus clic derecho Insert Code-->Generated set/get y seleccionamos estatus
Implementamos el método save() donde haremos persistentes los entity en la base de datos, en este método buscaremos por la llave primaria mediante estatusFacade.find(), y si no existe invocamos estatusFacade.create(), para guardarlo.
Si deseamos limpiar la vista escribimos estatus = new Estatus(), de manera que al actualizarse la página xhtml, esta mostrará los atributos limpios.
JSFUtil.infoDialog(), mostrará el mensaje en un diálogo. Si queremos que se muestre en el growl usamos JSFUtil.addSuccessMessage().
Crear métodos edit() y delete(), crear atributo encontrado con los métodos get/set. Recordar cambiar
public Boolean isEncontrado() {
return encontrado;
}
por
public Boolean getEncontrado() {
return encontrado;
}
Código completo de CDI Beans EstatusController.java
import com.avbravo.scrumweb.Estatus;
import com.avbravo.scrumweb.ejb.EstatusFacade;
import com.avbravo.scrumweb.generales.JSFUtil;
import com.avbravo.scrumweb.generales.ResourcesFiles;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
/**
*
* @author avbravo
*/
@Named
@RequestScoped
public class EstatusController {
@Inject
EstatusFacade estatusFacade;
Estatus estatus = new Estatus();
private Boolean encontrado = false;
private List<Estatus> items;
public Estatus getEstatus() {
return estatus;
}
public void setEstatus(Estatus estatus) {
this.estatus = estatus;
}
public Boolean getEncontrado() {
return encontrado;
}
public void setEncontrado(Boolean encontrado) {
this.encontrado = encontrado;
}
/**
* Creates a new instance of EstatusController
*/
public EstatusController() {
}
public String save() {
try {
if (estatusFacade.find(estatus.getIdestatus()) != null) {
JSFUtil.infoDialog("Mensaje", "Existe un registro con ese id");
return null;
}
estatusFacade.create(estatus);
JSFUtil.addSuccessMessage("Guardado");
estatus = new Estatus();
} catch (Exception e) {
JSFUtil.addErrorMessage(e.getLocalizedMessage());
}
return null;
}
public String edit() {
try {
estatusFacade.edit(estatus);
JSFUtil.addSuccessMessage("Guardado");
} catch (Exception e) {
JSFUtil.addErrorMessage(e.getLocalizedMessage());
}
return null;
}
public String delete() {
try {
estatusFacade.remove(estatus);
JSFUtil.addSuccessMessage("Eliminado");
encontrado = false;
estatus = new Estatus();
} catch (Exception e) {
JSFUtil.addErrorMessage(e.getLocalizedMessage());
}
return null;
}
//Devuelve eln list para un selectOneMenu
public List<Estatus> getItems() {
if (items == null) {
items = estatusFacade.findAll();
}
return items;
}
}
Crear los Facelets Template Client para insertar Estatus
Ahora creamos un Facelets Template Client
- Desde menú File, seleccione New
- en Categories, seleccione Java Server Faces
- en File Types, seleccione Facelets Template Client
- En File Name: estatusinsert
- Folder colocamos /page/estatus/
- Template seleccionamos template.xhtml
Se crea el Facelets client estatusinsert.xhtml en la carpeta page/estatus
De la misma manera que hicimos con la página index, colocamos en comentario top, button,left, mediante <!-- →.
Nos ubicamos en la palabra center. En esta parte vamos a reemplazarlo con un formulario generado por el IDE..
<ui:define name="center">
center
</ui:define>
Una vez seleccionado, hacemos clic sobre el texto y seleccionamos Insert Code
Luego, hacemos clic en JSF Form From Entity
Seleccionar el Entity: com.avbravo.scrumweb.Estatus
y el Managed Bean Property: estatusController.estatus
Genera el código con los componentes JSF asociado a los atributos del entity
Indicamos el id del panel esto se utiliza para identificar el componente por el id respectivo
<h:panelGrid id="panel" columns="2">
Colocamos la etiqueta <p:growl id="growl" /> y <p:messages autoUpdate=”true” para que nos muestre los mensajes del aplicativo.
Ahora vemos que la etiqueta <p:growl id="growl" /> muestra un error . Esto se debe a que no está agregado el taglib de primefaces. Para agregarlo, seleccionamos el icono de la sugerencia y seleccionamos que agregue la biblioteca respectiva
Agregamos el componente para mensajes que se mantendrán en la página.
<p:messages autoUpdate="true"/>
Creamos la sección footer en el panelGrid y agregar el boton Guardar, para invocar el método save() del CDI y en la propiedad update utilizamos panel y growl, de manera que el guardar un registro se actualice el panel y se muestre los mensajes en el growl. Si no lo colocamos en el update los mensajes no se mostraran, ya que el <p:commandButton> por defecto tiene Ajax habilitado en true.
<f:facet name="footer">
<p:commandButton value="Guardar" update="panel,growl" action="#{estatusController.save()}"/>
</f:facet>
Vista final de la página estatusinsert.xhtml, con los componentes y el botón Guardar.
Guardamos el archivo, y volvemos a ejecutar la aplicación para mostrar los cambios
Ingresamos los datos y al dar clic en el boton Guardar se almacenan en la base de datos los atributos que estan en el Entity y se envía el mensaje en el growl y en messages.
si ingresamos un idestatus que ya existe nos enviará el mensaje.
Si no usaramos la validación para determinar si existe un registro con esa llave primaria obtendremos el mensaje Transaction aborted, y no sería muy explicativo para el usuario
Si deseamos usar icono en el botón, agregamos el atributo icon="ui-icon-disk" a <p:commandButton>.
En el siguiente enlace podemos encontrar la lista de iconos jquery disponibles para los componentes primefaces, que usaremos mediante icon="nombre del icono”
colocamos el cursor sobre el icono y se despliega el mensaje con el nombre.
Editar el entity Estatus.java
Agregar el @NamedQuery findByEstatusLike que nos permitirá realizar búsquedas por coincidencias en el atributo estatus.
@NamedQuery(name = "Estatus.findByEstatusLike", query = "SELECT e FROM Estatus e WHERE lower(e.estatus) like :estatus"),
Segmento del código Entidad.java donde se agrega el @NamedQuery
@Entity
@Table(name = "estatus")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Estatus.findAll", query = "SELECT e FROM Estatus e"),
@NamedQuery(name = "Estatus.findByIdestatus", query = "SELECT e FROM Estatus e WHERE e.idestatus = :idestatus"),
@NamedQuery(name = "Estatus.findByEstatus", query = "SELECT e FROM Estatus e WHERE e.estatus = :estatus"),
@NamedQuery(name = "Estatus.findByEstatusLike", query = "SELECT e FROM Estatus e WHERE lower(e.estatus) like :estatus"),
@NamedQuery(name = "Estatus.findByEsinicial", query = "SELECT e FROM Estatus e WHERE e.esinicial = :esinicial")})
public class Estatus implements Serializable {
private static final long serialVersionUID = 1L;
Editar EstatusFacade.java
Agregar el método findById , que nos devolverá un objeto de tipo Estatus.
El método find, el cual buscará el entity por la llave primaria.
El método findByEsinicial() que recibe un parámetro correspondiente al valor del atributo esinicial(si/no).
El Entity Estatus findByEsinicial es el @NamedQuery(name = "Estatus.findByEsinicial", usaremos un Query que implementa la búsqueda y devolverá un list.
El método getEstatusList() para que devuelva todos los entity , al invocar Estatus.findAll. y elmétodoo findByEsinicial().
agregar los métodos findByEstatus(), findByIdEstatusList() y findByEstatusLike()
Editar EstatusFacade.java
public Estatus findById(String id) {
return em.find(Estatus.class, id);
}
public List<Estatus> getEstatusList() {
return em.createNamedQuery("Estatus.findAll").getResultList();
}
public List<Estatus> findByEsinicial(String value){
Query query = em.createNamedQuery("Estatus.findByEsinicial");
return query.setParameter("esinicial", value).getResultList();
}
public List<Estatus> findByEstatus(String value){
Query query = em.createNamedQuery("Estatus.findByEstatus");
return query.setParameter("estatus",value).getResultList();
}
public List<Estatus> findByIdEstatusList(String value){
Query query = em.createNamedQuery("Estatus.findByIdestatus");
return query.setParameter("idestatus", value).getResultList();
}
public List<Estatus> findByEstatusLike(String value){
Query query = em.createNamedQuery("Estatus.findByEstatusLike");
value = "%" +value.trim() +"%";
return query.setParameter("estatus", value).getResultList();
}
Convertidores
Convierten los objetos en el tipo de datos necesario. Por ejemplo si usamos un selectOneMenu con una lista de objetos, el converter devolverá el objeto seleccionado.
Crear EstatusConverter.java
Crear EstatusConverter.java
- Desde menú File, seleccione New
- en Categories, seleccione Java Server Faces
- en File Types, seleccione JSF ManagedBeans
- Class Name: EstatusConverter
- Package com.avbravo.scrumweb.converter
import com.javscaz.rigemjsf.Usuarios;
import com.javscaz.rigemjsf.ejb.UsuariosFacade;
import com.javscaz.rigemjsf.generales.JSFUtil;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
@FacesConverter(value = "estatusConverter")
public class EstatusConverter implements Converter {
@Inject
private EstatusFacade ejbFacade;
@Override
public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
if (value == null || value.length() == 0 || JSFUtil.isDummySelectItem(component, value)) {
return null;
}
return this.ejbFacade.find(getKey(value));
}
java.lang.String getKey(String value) {
java.lang.String key;
key = value;
return key;
}
String getStringKey(java.lang.String value) {
StringBuffer sb = new StringBuffer();
sb.append(value);
return sb.toString();
}
@Override
public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
if (object == null
|| (object instanceof String && ((String) object).length() == 0)) {
return null;
}
if (object instanceof Estatus) {
Estatus o = (Estatus) object;
return getStringKey(o.getUsername());
} else {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "object {0} is of type {1}; expected type: {2}", new Object[]{object, object.getClass().getName(), Estatus.class.getName()});
return null;
}
}
}
Nota:
Si la llave primaria es de tipo integer, utilizar el tipo de datos java.lang.Integer
java.lang.Integer getKey(String value) {
java.lang.Integer key;
key = Integer.valueOf(value);
return key;
}
String getStringKey(java.lang.Integer value) {
StringBuffer sb = new StringBuffer();
sb.append(value);
return sb.toString();
}
Comments
gracias de antemano
gracias de antemano
gracias de antemano
gracias de antemano