JSF María Consuelo Franky Universidad Javeriana 2009 1 JSF: Java Server Faces la nueva generación de páginas web en tecnología Java 2 Niveles de una arquitectura multi-nivel Presentación •Maneja interacción con usuario •Despliegue HTML •Validación Aplicación Servicios •Invoca •Realiza servicios •Validación sintáctica •Adapta respuestas a interfaz usuario sintáctica •Maneja excepciones Cliente con navegador Web servicios sobre objetos del dominio •Implanta reglas del negocio •Estado de sesión -usuario Dominio Persistencia •Servicios •Modela entidades del negocio y sus reglas básicas •Validación semántica •Control básicos de persistencia de objetos del dominio •Transformación ObjetoRelacional •Soporte transacción transacción Servidor Web Servidor de Componentes Servidor BD 3 El metapatrón MVC • Model (Modelo): maneja reglas del negocio y estructura de los datos • View (Vistas): maneja presentación de los datos del sistema al usuario • Controller (Controlador): transforma pedidos del usuario en operaciones sobre los objetos del modelo y selecciona vista para mostrar resultados al usuario (comportamiento del sistema) 4 Nivel web basado en el framework JSF Pantallas se contruyen con componentes gráficos UIComponent que reaccionan a eventos: son componentes de alto nivel que encapsulan elementos HTML y tienen comportamiento asociado muestran y actualizan valores del Modelo contenidos en javaBeans asociados ("backing beans") como reacción a eventos (por ej: oprimir un botón) invocan directamente métodos de los “backing beans” Aspectos de validación de los datos del usuario: Validación automática asociada a cada componente gráfico Cuando la validación falla se vuelve a mostrar la pantalla junto con los mensajes de error Procesamiento de eventos solo cuando la validación es exitosa 5 Framework JSF Presentación Aplicación Servicios Dominio Persistencia CONTROLADOR MODELO servlet Faces EJB entidad C Backing Bean 1 Backing Bean 2 HTML 1 HTML 2 Navegador Cliente EJB sesión A BD relacional JSP pantallazo1 JSP pantallazo2 VISTAS Servidor Web Servidor de componentes Servidor BD6 Ejemplo de pantalla JSF: <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <head> <title>Add 2 numbers</title> </head> <body> <f:view> <h:form id="addForm"> First Number: <h:inputText id="firstNumber" value="#{BackCalc.firstNumber}" required="true" /> <h:message for="firstNumber" /> <br> Second Number: <h:inputText id="secondNumber" value="#{BackCalc.secondNumber}" required="true" /> <h:message for="secondNumber" /> <br> Result: <h:outputText id="output" value="#{BackCalc.result}" /> <br> <h:commandButton id="submitAdd" action="#{BackCalc.add}" value="Add" /> </h:form> </f:view> </body> 7 </html> backing bean para el pantallazo: public class BackCalc { // atributos ligados a los UIComponents: private int firstNumber = 0; private int secondNumber = 0; private int result = 0; // model: podria ser la referencia a un EJB: private Calculator calculator = new Calculator(); //. . . metodos set y get de atributos . . . // reaccion a evento sobre el boton: public String add() { result = calculator.add(firstNumber, secondNumber); return "success"; } } 8 Validación automática: abc "firstNumber": Conversion error occured Validation Error: "secondNumber": Value is required 9 Pantalla JSF simple 10 Pantalla de edición 11 Expone los atributos de un backing bean ... <div class="label">Name:</div> <div class="input"> <h:inputText id="name" value="#{hotel.name}" required="true" /> <br/> <span class="errors"><h:message for="name" /></span> </div> Hay una zona para los mensajes FacesMessages <div class="entry errors"> <h:messages globalOnly="true" /> </div> Los botones invocan acciones sobre un backing bean <div class="input"> <h:commandButton id="proceed" value="Proceed" action="#{hotel.verifyNewHotel}" styleClass="button"/>&#160; <s:button value="Cancel" id="cancel" action="#{hotel.cancel}" styleClass="button"/> </div> 12 Pantalla no editable 13 Pantalla para ver datos de hotel sin editar: confirmHotel muestra cada atributo de un hotel, por ej name : <div class="entry"> <div class="label">Name:</div> <div class="output"> <h:outputText id="name" value="#{hotel.name}" /> </div> </div> botones finales para invocar confirm(), cancel() o regresar a la pantalla anterior <div class="input"> <h:commandButton id="confirm" value="Confirm" action="#{hotel.confirm}" styleClass="button"/> &#160; <h:commandButton id="revise" value="Revise" action="backEditHotel" styleClass="button"/>&#160; <h:commandButton id="cancel" value="Cancel" action="#{hotel.cancel}" styleClass="button"/> </div> observar el alias "backEditHotel" definido como alias en faces-config.xml referente a /pages/hotels/hotelInscription/editHotel.xhtml 14 Estructuración de pantallas “facelets” mediante templates y <div> 15 Concepto de template Concepto de template (plantilla): pantalla base que define estructura común de las pantallas reales contiene partes fijas y partes que deben ser redefinidas por cada pantalla ejemplo de estructura de pantalla: banner sidebar content footer 16 Ejemplo de plantilla: template.xhtml <!-- librerias de etiquetas --> <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:s="http://jboss.com/products/seam/taglib" xmlns:rich="http://richfaces.ajax4jsf.org/rich"> <!-- referencia al archivo que define estilos de los div --> <head> <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1" /> <title>Hotels reservation system</title> <link href="#{facesContext.externalContext.requestContextPath} /pages/public/css/screen.css" rel="stylesheet" type="text/css" /> </head> 17 <body> <!-- div que define estructura global de toda pantalla --> <div id="document" > <!-- toda pantalla tiene un banner fijo --> <div id="header"> <div id="title"> <img src="../../public/img/hdr.title.gif"/></div> <div id="status"> <h:form id="welcome"> #{messages['WelcomeUser']} | <s:link id="search" action="main" value="#{messages['Search']}" propagation="none"/> | <s:link id="logout" action="#{login.logout}" value="#{messages['Logout']}" /> </h:form> </div> </div> <div id="headerMenu"> <div id="titleMenu"><h4>The title</h4></div> <div id="statusMenu"> <h:form id="menuRich"> <rich:toolBar binding="#{toolBar}"> </rich:toolBar> </h:form> </div> </div> 18 <!-- toda pantalla tiene un contenido variable: partes sidebar y content deben ser definidos por c/pantalla --> <div id="container"> <div id="sidebar" style=" width : 150px;"> <ui:insert name="sidebar"/> </div> <div id="content" style="width : 500px;"> <ui:insert name="content"/> <ui:include src="footer.xhtml" /> </div> </div> </div> </body> </html> 19 facelet: Pantalla real facelet: que se basa en el template etiqueta más externa <ui:composition> indica que se usa un template la etiqueta <ui:define> redefine partes variables del template se diseña con <div> que tienen estilos asociados ejemplo: password.xhtml : <!-- librerias de etiquetas; template utilizado --> <ui:composition 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:t="http://myfaces.apache.org/tomahawk" xmlns:s="http://jboss.com/products/seam/taglib" template="../common/template.xhtml"> <!-- definicion de la parte content --> <ui:define name="content"> <div class="section"> <h1>Change Your Password</h1> </div> <div class="section"> ... </div> </ui:define> <!-- definicion de la parte sidebar --> <ui:define name="sidebar"> <h1>changePassword use case</h1> </ui:define> </ui:composition> 20 Estilos asociados a los <div> se definen en el archivo screen.css algunos estilos: /* para el div mas externo de una pantalla */ #document { padding: 0 1px; background: #fff url(../img/bg.gif) 0 0 repeat-y; float: left; border-bottom: 1px solid #C3BBB6; } /* para el banner con el menu */ #headerMenu { float: left; width: 100%; height: 40px; background: url(../img/hdr.bg.gif) 0 0 repeat-x; } /* para el contenido variable */ #container { float: left; width: 100%; background: url(../img/hdr.bar.jpg) 0 0 repeat-x; } 21 /* para la parte content dentro del contenido variable */ #content { float: left; width: 80%; margin-top: 75px; padding-top: 5px; background: #fff url(../img/cnt.bg.gif) 0 0 repeat-x; } /* para un div section dentro de content */ #content .section { float: left; width: 70%; padding: 15px 15px 0 15px; } /* redefine h1 dentro de div section dentro de content */ #content .section h1 { font-family: "Trebuchet MS", Arial, sans-serif; line-height: normal; font-weight: normal; font-size: large; } ... 22 Taller en Eclipse para construir un proyecto JSF simple 23 Creación inicial del proyecto Registrar en Eclipse el servidor JBoss Lanzar el servidor JBoss Solicitar un nuevo proyecto de tipo JSF escoger versión "JSF 1.2 with Facelets" y template: "FaceletsKickStartWithoutLibs" Ejecutar el proyecto sobre el servidor JBoss registrado (desde ventana: JBoss Server View) opcion "Run on Server" Observar validación JSF de un elemento de edición 24 Estudiar el código fuente Backing bean: Person.java (contiene solo un atributo: name) Template de páginas: common.xhtml carga archivo de propiedades internacionales : <f:loadBundle basename="resources_es" var="msg" /> las páginas usarán esas propiedades con expresiones como ${msg.prompt} el template también referencia hoja de estilos css o los incluye con la etiqueta <style> el template define 3 secciones variables que serán redefinidas por cada página: <ui:insert name="pageTitle">Page Title</ui:insert> <ui:insert name="pageHeader">Page Header</ui:insert> <ui:insert name="body">Page Body</ui:insert> 25 Paginas: index.jsp : redirige a inputname.jsf que corresponde en realidad a inputname.xhtml inputname.xhtml : redefine las secciones variables del template: <ui:define name="pageTitle">Input User Name </ui:define> <ui:define name="pageHeader"> Facelets Hello Application </ui:define> <ui:define name="body"> … </ui:define> contiene forma que va a ser validada por JSF y la invocación de la acción "greeting" utiliza propiedades internacionales como ${msg.prompt} greeting.xhtml : se muestra como resultado de la acción "greeting" 26 Flujo de navegación descrito en faces-config.xml: abrirlo con el editor gráfico en ventana " Web projects" (con dobleclick invoca editor "JSF Page Flow editor") observar declaración del backing bean y de flujo para acción "greeting" utiliza un lenguaje de etiquetas basado en XML: etiqueta s <managed-bean>, <navigation-rule> descrito en XSD (variación de un DTD): en http://java.sun.com/xml/ns/javaee/webfacesconfig_1_2.xsd Descriptor web.xml abrirlo con editor "Jboss Tools XML editor" configura el servlet JSF sufijo real de páginas que procesará JSF: .xhtml sufijo en los url: .jsf 27 Manejar el proyecto a través del ant Despublicar el proyecto de JBoss Publicar el proyecto en modo "deployed" desde el ant: en ventana ant: añadir el build.xml del proyecto invocar tareas: clean y deploy Copiar el .war en el servidor : observar el proyecto publicado en modo "exploded" directorio deploy de JBoss despublicarlo desde ventana: JBoss Server View (desaparece del directorio deploy de Jboss) sobre el war usar opcion "Deploy to Server" observar consola Invocar la aplicación en el navegador: http://localhost:8080/nombreAplicacion/ 28 Modificar páginas facelets Provocar error de validación en primera página y luego corregirlo En la segunda página (greeting.xhtml) agregar botón que permita navegar a la primera página debe arreglarse reglas de navegación en faces-config En la primera página (inputname.xhtml) defecto: cuando se regresa con el browser de la segunda pagina a la primera el error de validacion sigue todavía solo se limpia cuando se navega al url de la primera página agregar más elementos a la forma: codigo numérico de la persona agregar este nuevo atributo al backing bean probar validación de tipo Agregar acción de validación especial al backing bean e invocarlo desde botón de primera página el codigo debe estar entre 1000 y 9000 29 Acciones de los backing beans y mensajes construidos para el usuario Agregar acción de validación especial al backing bean e invocarlo desde botón de primera página el codigo debe estar entre 1000 y 9000 public String validacionCodigo() { if (…) { FacesMessage message = new FacesMessage("codigo invalido"); FacesContext.getCurrentInstance() .addMessage("codigo", message); return "primerapagina"; } return "segundapagina"; } mostrar estos mensajes primera pagina con etiqueta <h:messages /> en 30 Agregar una tercera página facelet y modificar el template Usar ayuda de Eclipse para agregar tercera página xhtml Agregar un botón en segunda pagina para ir a tercera página en Jboss Tools Web >> XHTML file , usando template FaceletBlank colocar algún elemento simple arreglar navegacion en faces-config.xml Modificar el template para que muestre una imagen en el header y un texto en el footer Todas las páginas deben usar este template Republicar y probar 31 ANT del proyecto 32 Importancia de Ant como manejador del proyecto El ANT del cualquier proyecto Java es necesario para manejar con flexibilidad todas las tareasrelacionadas con el proyecto: compilación empaque publicación en el servidor generación de documentación javadoc generación de referencias cruzadas testing compilación por aspectos ...etc. El ANT permite manejar el proyecto de forma independiente de los ambientes de programación 33 Principales tareas del Ant Contiene: definición de propiedades definición de filesets, zipefilesets, paths principales tareas: clean: elimina archivos generados compile: compilación de todos los fuentes java war: empaca las pantallas de la aplicación ejb3: empaca todos los componentes ejb ear: empaca toda la aplicación en un archivo .ear deploy: publica la aplicación testapplication: tests funcionales (con TestNG) javadoc: genera documentación de los fuentes java 34 Ejemplo de contenido de un archivo build.xml . . . . <!-- GENERAL PROPERTIES ======================== --> <!-- root directory --> <property name="root.dir" value=".." /> <!-- external file of properties --> <property file="build.properties" /> <!-- build directory --> <property name="build.dir" value="build" /> <property name="classes.dir" value="${build.dir}/classes" /> . . . . <!-- GENERAL FILESETS, ZIPFILESETS AND PATTERNSETS ==== --> <fileset id="lib" dir="${lib.dir}"> <include name="*.jar" /> </fileset> . . . . <!-- classpath for compilation --> <path id="build.classpath"> <fileset refid="lib" /> <fileset refid="el.jar" /> <fileset refid="seam.jar" /> <fileset refid="cincosoft.jar" /> </path> . . . . 35 <!-- TARGETS ============================= --> . . . . <!-- compile --> <target name="compile" depends="init" > <echo message="property javac.debug = ${javac.debug}" /> <javac source="1.5" target="1.5" destdir="${classes.dir}" classpathref="build.classpath" debug="${javac.debug}" deprecation="${javac.deprecation}" nowarn="on” > <src path="${src.java.dir}" /> <src path="${src.test.dir}" /> </javac> </target> <!-- WAR building --> <target name="war" depends="compile"> . . . . <echo message="Building the war " /> <jar destfile="${build.dir}/${application.name}.war"> <fileset refid="index" /> <zipfileset refid="application.war.docroot" /> . . . <zipfileset dir="${build.dir}"> <include name="WEB-INF/web.xml" /> <include name="WEB-INF/components.xml" /> </zipfileset> </jar> </target> 36 <!-- EJB3 building --> <target name="ejb3" depends="compile"> <echo message="Building the jar of ejbs" /> <jar jarfile="${build.dir}/${application.name}.jar"> <fileset refid="application.classes" /> <fileset refid="application.ejb3.root" /> </jar> </target> <!-- EAR building --> <target name="ear" depends="ejb3, war" > <echo message="Building the ear " /> <jar destfile="${build.dir}/${application.name}.ear"> <fileset refid="seam.jar" /> . . . <fileset refid="application.ejb3.lib" /> <zipfileset dir="${build.dir}"> <include name="${application.name}.jar" /> </zipfileset> <zipfileset dir="${build.dir}"> <include name="${application.name}.war" /> </zipfileset> <zipfileset refid="application.ear.resources" /> <zipfileset refid="application.configuration" /> </jar> </target> 37 <!-- deploy --> <target name="deploy" depends="ear" > <copy file="${build.dir}/${application.name}.ear" todir="${deploy.dir}" /> </target> <!-- javadoc --> <target name="javadoc"> <mkdir dir="${javadoc.dir}" /> <javadoc classpathref="build.classpath" destdir="${javadoc.dir}" use="true" protected="true" version="true" windowtitle="Documentation of ${Name}" Overview="${overview.dir}/overview.html" doctitle="${Name} Application Documentation" link="${javadoc.link}” > <packageset dir="${src.java.dir}" defaultexcludes="yes"> <include name="**/project/**" /> </packageset> </javadoc> <copy file="${overview.dir}/overview.html” todir="${javadoc.dir}" /> </target> •mirar más tareas descritas en el manual de ANT: http://ant.apache.org/index.html •estudiar ANT del proyecto facelets y agregar publicación en el servidor 38