21
Integración de JSF, Spring e Hibernate para crear una Aplicación Web del Mundo Real Autor: Derek Yang Shen Traductor: Juan Antonio Palos (Ozito) Introducción Requerimientos Funcionales de la Aplicación de Ejemplo o Casos de Utilización o Reglas de Negocio o Presunciones o Flujo de Páginas Diseño de la Arquitectura de Alto nivel o Arquitectura Multi-capa o Diseño de la Arquiectura de JCatalog o La Capa de Presentación y JavaServer Faces Model-View-Controller (MVC) JavaServer Faces JSF y MVC ¿Por qué JSF? Bean Manejado, Bean de Respaldo, objeto vista y Modelo de objeto de dominio Seguridad Paginación Caché Subida de Ficheros Validación Personalización de los Mensajes de Error o La Capa de Lógica-de-Negocio y el Marco de Trabajo Spring o La Capa de Integración e Hibernate Data Access Object (DAO) Implementación o Diseño de la Base de Datos o Diseño de Clases o Conectarlo Todo Capa de Presentación Capa de Lógica-de_Negocio Capa de Integración Conclusión

Tutorial JSP - JSF, Spring e Hibernate

Embed Size (px)

DESCRIPTION

Integración de JSF, Spring e Hibernate para crear una Aplicación Web del Mundo RealAutor: Derek Yang Shen Traductor: Juan Antonio Palos (Ozito)• •••Introducción Requerimientos Funcionales de la Aplicación de Ejemplo o Casos de Utilización o Reglas de Negocio o Presunciones o Flujo de Páginas Diseño de la Arquitectura de Alto nivel o Arquitectura Multi-capa o Diseño de la Arquiectura de JCatalog o La Capa de Presentación y JavaServer Faces  Model-View-Controller (MVC)  JavaServer Faces

Citation preview

Page 1: Tutorial JSP - JSF, Spring e Hibernate

Integración de JSF, Spring e Hibernate para crear una Aplicación Web del Mundo RealAutor: Derek Yang ShenTraductor: Juan Antonio Palos (Ozito)

Introducción Requerimientos Funcionales de la Aplicación de Ejemplo

o Casos de Utilización o Reglas de Negocio o Presunciones o Flujo de Páginas

Diseño de la Arquitectura de Alto nivel o Arquitectura Multi-capa o Diseño de la Arquiectura de JCatalog o La Capa de Presentación y JavaServer Faces

Model-View-Controller (MVC) JavaServer Faces JSF y MVC ¿Por qué JSF? Bean Manejado, Bean de Respaldo, objeto vista y Modelo de objeto de

dominio Seguridad Paginación Caché Subida de Ficheros Validación Personalización de los Mensajes de Error

o La Capa de Lógica-de-Negocio y el Marco de Trabajo Spring o La Capa de Integración e Hibernate

Data Access Object (DAO) Implementación

o Diseño de la Base de Datos o Diseño de Clases o Conectarlo Todo

Capa de Presentación Capa de Lógica-de_Negocio Capa de Integración

Conclusión

Page 2: Tutorial JSP - JSF, Spring e Hibernate

Introducción

La tenología JavaServer Faces (JSF) es un nuevo marco de trabajo para interfaces de usuario para aplicación J2EE. Por diseño, es particularmente útil con aplicaciones basadas en la arquitectura MVC (Model-View-Controller). Numérosos artículos han presentado ya JSF. Sin embargo, la mayoría toma una apróximación teórica que no cumple los retos del desarrollo empresarial del mundo real. Quedan muchos problemas por resolver. Por ejemplo, ¿dónde entra JSF en la arquiectura general MVC?, ¿Cómo se integra JSF con otros marcos de trabajo?, ¿Existe la lógica de negocio en los beans que hay tras JSF? Y principalmente, ¿cómo se puede construir una aplicación Web del mundo real utilizando JSF?

Este tutorial corrige todos esos problemas. Muestra cómo integrar JSF con otros márcos de trabajo, espcíficamente, Spring e Hibernate. Demuestra cómo crear la aplicación web JCatalog, un sistema de catálogo de productos online. Usando el ejemplo JCatalog este tutorial cubre todas las fases del diseño de una aplicación Web, incluyendo el descubriemto de los requerimientos del negocio, el análisis, la selección de tecnologías, la arquitectura de alto nivel, y el diseño a nivel de la implementación. Este tutorial discute las ventajas y desventajas de las tecnologías utilizadas en JCatalog y demuestra aproximaciones para diseñar algunos de los aspectos clave de la aplicación.

Este tutorial está escrito para arquitectos Java, desarrolladores que ya han trabajado con aplicaciones Web basadas en J2EE. No es una introduccion a JSF, al marco de trabajo Spring ni a Hibernate.

Requerimientos Funcionales de la Aplicación de Ejemplo

La aplicación de ejemplo de este tutorial, JCatalog, es una aplicación Web del mundo real, suficientemente realista para proporcionar una importante discusión sobre las decesiones arquitecturales de una aplicación Web. Empezaremos presentando los requrimientos de JCatalog. Nos referiremos a esta sección a lo largo del tutorial para dirigir las decisiones técnicas y el diseño de la arquitectura.

La primera fase en el diseño de una aplicación Web es descubrir los requerimientos funcionales del sistema. Los usuarios pueden navegar por un catálogo de productos y ver los detalles de un producto y los administradores pueden manejar el catálogo de productos. Se pueden añadir algunas mejoras, como el control de inventario y el procesamiento de pedidos para hacer que la aplicación sea realmente un sistema de negocio-electrónico.

 Casos de Utilización

Se utiliza el análisis de los casos de utilización para acceder a los requerimientos funcionales de la aplicación. En la siguiente figura se puede ver el diagrama de casos de utilización:

Page 3: Tutorial JSP - JSF, Spring e Hibernate

Un diagrama de casos de utilización identifica los actores en un sistema y las operaciones que podrían realizar. En la aplicación de ejemplo se deben implementar siete casos de utilización. Al actor User puede navegar por el catálogo de productos y ver los detalles de esos productos. Una vez que el User entra en el sistema, se convierte en el actor Administrator, que puede crear nuevos productos, editar productos existentes, y borrar productos obsoletos.

 Reglas de Negocio

JCatalog debe cumplir las siguientes reglas de negocio:

Cada producto tiene un ID único Cada producto pertenece al menos a una categoría El ID de un producto no se puede modificar una vez creado.

 Presunciones

Hacemos las siguientes presunciones para el diseño e implementación de la aplicación:

El Inglés es el idioma por defecto, no se requiere internacionalización No existen más de 500 productos en el catálogo El catálogo no se actualiza muy frecuentemente.

 Flujo de Páginas

La siguiente figura muestra todas las páginas de JCatalog y las transiciones entre ellas:

La aplicación tiene dos grupos de páginas: públicas por Internet y de administración por intranet. La intranet es accesible sólo cuando el usuario se 'logea' en el sistema. ProductSummary no se presenta a los usuarios como una página separada. Se muestra en un marco HTML dentro de la página Catalog. ProductList es un catalogo especial que sólo pueden ver los administradores. Contiene enlaces para crear, editar y borrar productos.

La siguiente figura muestra el esqueleto de la página Catalog. Idealmente, por cada página, se debe incluir en la documentación de los requerimientos un esqueleto que detalle la información de todos los controles y del contenido requerido en la esa página.

Page 4: Tutorial JSP - JSF, Spring e Hibernate

Diseño de la Arquitectura de Alto nivel

La siguiente fase del diseño de una aplicación web es el diseño de la arquitectura de alto nivel. Esto implica subdividir la aplicación en componentes funcionales y particionar estos componentes en capas. El diseño de la arquitectura de alto nivel es neutral a las tecnologías utilizadas.

 Arquitectura Multi-capa

Una arquitectura multicapa particiona todo el sistema en distintas unidades funcionales: cliente, presentación, lógica-de-negocio, integración, y sistema de información empresarial (EIS). Esto asegura una división clara de responsabilidades y hace que el sistema sea más mantenible y extensible. Los sistemas con tres o más capas se han probado como más escalables y flexibles que un sistema cliente-servidor, en el que no existe la capa central de lógica-de-negocios.

La capa del cliente es donde se consumen y presentan los modelos de datos. Para una aplicación Web, la capa cliente normalmente es un navegador web. Los clientes pequeños basados-en-navegador no contienen lógica de presentación; se trata en la capa de presentación.

La capa de presentación expone los servicios de la capa de lógica-de-negocio a los usuarios. Sabe cómo procesar una petición de cliente, cómo interactúar con la capa de lógica-de-negocio, y cómo seleccionar la siguiente vista a mostrar.

La capa de la lógica-de-negocio contiene los objetos y servicios de negocio de la aplicación. Recibe peticiones de la capa de presentación, procesa la lógica de negocio basada en las peticiones, y media en los accesos a los recursos de la capa EIS. Los componenes de la capa de lógica-de-negocio se benefician de la mayoría de lo servicios a nivel de sistema como el control de seguridad, de transaciones y de recursos.

La capa de integración es el puente entre la capa de lógica-de-negocio y la capa EIS. Encapsula la lógica para interactúar con la capa EIS. Algunas veces a la combinación de las capas de integración y de lógica-de-negocio se le conoce como capa central.

Los datos de la aplicación persisten en la capa EIs. Contiene bases de datos relacionales, bases de datos orientadas a objetos, y sistemas antiguos.

Page 5: Tutorial JSP - JSF, Spring e Hibernate

 Diseño de la Arquiectura de JCatalog

La siguiente figura muestra el diseño de la arquitectura de alto nivel de JCatalog y cómo se acopla en la arquitectura multi-capa.

La aplicación utiliza una arquitectura multi-capa no-distribuida. La figura anterior muestra el particionamiento de las capas de la aplicación y las tecnologías elegidas para cada capa. También sierve como diagrama de ejemplo de despliegue de la aplicación. Para una arquitectura colocada, las capas de presentación, de lógica-de-negocio y de integración están físicamente localizadas en el mismo contenedor Web. Interfaces bien-definidos aislan las responsabilidades de cada capa. La arquitectura colocada hace que la aplicación sea más simple y escalable.

Para la capa de presentación, la experiencia muestra que la mejor práctica es elegir un marco de trabajo de aplicaciones Web existente y probado en vez de diseñar y construir un marco de trabajo personalizado. Hay varios marcos de trabajo de este tipo entre los que elegir: Struts, WebWork, y JSF. Nosotros utilizaremos JSF para JCatalog.

Se pueden utilizar EJB (Enterprise JavaBeans) o POJO (plain old Java objects) para construir la capa de lógica-de-negocio. EJB con sus interfaces remotos es una mejor elección si la aplicación es distribuida. Como JCatalog es una aplicación web típica que no requiere acceso remoto, se utilizará POJO con la ayuda del marco de trabajo Spring, para esta capa.

La capa de integración maneja la persistencia de los datos con la base de datos relacional. Se pueden utilizar diferentes aproximaciones para implementar la capa de integración:

Page 6: Tutorial JSP - JSF, Spring e Hibernate

JDBC puro (Java DataBase Connectivity): Es la aproximación más flexible; sin embargo es difícil trabajar con JDBC de bajo nivel, y un mal código JDBC no tiene un rendimiento muy bueno.

Beans de entidad: Un Bean de entidad con persistencia manejada por el contenedor (CMP) es una forma costosa de aislar el código de acceso-a-datos y manejar el mapeo O/R (objecto-relacional) para persistencia de datos. Es una aproximación centrada en el servidor de aplicaciones. Un bean de entidad no ata la aplicación a un tipo particular de base de datos, pero si ata la aplicación al contenedor EJB.

Marco de Trabajo de Mapeo O/R: Un marco de trabajo de mapeo O/R toma una aproximación centrada en el objeto para implementar la persistencia de datos. Una aplicación de este tipo es fácil de desarrollar y altamente portable. Existen varios marcos de trabajo bajo este dominio: JDO (Java Data Objects), Hibernate, TopLink, y CocoBase son unos pocos ejemplos. En la aplicación de ejemplo se utiliza Hibernate.

Ahora discutiremos los problemas de diseño asociados con cada capa de la aplicación. Como JSF es una tecnología relativamente nueva, aconsejo su utilización.

 La Capa de Presentación y JavaServer Faces

La capa de presentación recoge la entrada del usuario, presenta los datos, controla la navegación por las página y delega la entrada del usuario a la capa de la lógica-de-negocio. La capa de presentación también puede validar la entrada del usuario y mantener el estado de sesión de la aplicación. En las siguientes secciones, discutiremos las consideraciones de diseño y los patrones de la capa de presentación, y la razón porque la que he elegido JSF para implementar JCatalog.

 Model-View-Controller (MVC)

MVC es el patrón de diseño arquitectural recomendado para aplicaciones interactivas Java. MVC separa los conceptos de diseño, y por lo tanto decrementa la duplicación de código, el centralizamiento del control y hace que la aplicación sea más extensible. MVC también ayuda a los desarrolladores con diferentes habiliades a enfocarse en sus habilidades principales y a colaborar a través de interfaces claramente definidos. MVC es el patrón de diseño arquitectural para la capa de presentación.

 JavaServer Faces

JSF es un marco de trabajo de componentes de interface de usuario del lado del servidor para aplicaciones Web basadas en Java. JSF contiene un API para representar componentes UI y manejar sus estados, manejar sus eventos, ña validación del lado del servidor, y la conversión de datos, definir la navegación entre páginas, soportar internacionalización y accesibilidad; y proporcionar extensibilidad para todas estas características. Tambiéne contien dos librerías de etiquetas JSP (JavaServer Pages) personalizadas para expresar componentes UI dentro de una página JSP y para conectar componentes a objetos del lado del servidor.

 JSF y MVC

JSF encaja bien en la arquitectura de la capa de presentación basada en MVC. Ofrece una clara separación entre el comportamiento y la presentación. Une los familiares componentes UI con los conceptos de la capa-Web sin limitarnos a una tecnología de script o lenguaje de marcas particular.

Los beans que hay tras JSF son la capa de modelo (en una sección posterior hablaremos más de estos beans). También contienen acciones, que son una extensión de la capa del controlador y delegan las peticiones del usuario a la capa de la lógica-de-negocio. Observe, que desde la prespectiva de la arquitectura general de la aplicación, también se puede referir a la capa de lógica-de-negocio como la capa del modelo. Las páginas JSP con etiquetas JSF personalizadas son la capa de la vista. El Servlet Faces proporciona la funcionalidad del controlador.

 ¿Por qué JSF?

JSF no es sólo otro marco de trabajo Web. Las siguientes características diferencian a JSF de otros marcos de trabajo:

Page 7: Tutorial JSP - JSF, Spring e Hibernate

Desarrollo de una Aplicación Web Orientada a Objetos al Estilo Swing: El modelo de componentes UI con estado del lado del servidor con oyentes/manejadores de eventos inicia el desarrollo de aplicaciones Web orientadas a objetos.

Control de Beans-de-Respaldo: Los beans de respaldo son componentes JavaBeans asociados con componentes UI utilizados en la página. El control de beans-de-respaldo separa la definición de los objetos componentes del UI de los objetos que realizan el procesamiento específico de la aplicación y que además contienen los datos. La implementación de JSF almacena y maneja estos ejemplares de beans de respaldo en el ámbito apropiado.

Modelo de componentes UI extensible: Los componentes UI de JSF son elementos configurables, reutilizables que componen los intefaces de usuario de aplicaciones JSF. Se puede extender un componentes UI estándar y desarrollar componentes más complejos, como barras de menú y árboles.

Modelo de Renderizado Flexible: Un renderizador separa la vista y la funcionalidad de los componentes UI. Se pueden crear y utilizar varios renderizadores para definir diferentes apariencias del mismo componente para el mismo o diferentes clientes.

Modelo de Conversión y Validación Extensible: Basados en los convertidores y validadores estándar, se pueden desarrollar convertidores y validadores personalizados, que proporcionan un mejor modelo de protección.

A pesar de su potencia, JSF no esta madura aún. Los componentes, convertidores y validadores que vienen con JSF son básicos. Y el modelo de validación por-componente no puede manejar validaciones muchos-a-muchos entre componentes y validadores. Además, las etiquetas personalizadas de JSF no se pueden integrar con JSTL (JSP Standard Tag Library) simultáneamente.

En la siguientes secciones, describiremos varios aspectos claves y decisiones de diseño que he realizado cuando implementé JCatalog con JSF. Empezaré con una discusión de la definición de beans manejados y beans de respaldo en JSF. Luego presentaré cómo manejar la seguridad, la paginación, el caché, la subida de ficheros, la validación y la personalización de mensajes de error en JSF.

 Bean Manejado, Bean de Respaldo, objeto vista y Modelo de objeto de dominio

JSF presenta dos nuevos términos: managed bean (bean manejado) y backing bean (bean de respaldo). JSF proporciona una fuerte facilidad de bean manejado. Los objetos JavaBean manejados por una implementación JSF se llaman beans manejados. Un bean manejado describe como se crea y se maneja un bean. No tiene nada que ver con las funcionalidades del bean.

El bean de resplado define las propiedades y las lógicas de manejo asociadas con los componentes UI utilizados en la página. Cada propiedad del bean de respaldo está unida a un ejemplar de un componente o a su valor. Un bean de respaldo también define un conjunto de métodos que realizan funciones para el componente, como validar los datos del componente, manejar los eventos que dispara el componente, y realizar el procesamiento asociado con la navegación cuando el componente se activa.

Una típica aplicación JSF acopla un bean de repaldo con cada página de la aplicación. Sin embargo, algunas veces en el mundo real, forzar una relación uno-a-uno entre el bean de respaldo y la página no es la solución ideal. Puede causar problemas como la duplicación de código. En el escenario del mundo real, varias páginas podrían necesitar compartir el mismo bean de respaldo detrás de la escena. Por ejemplo, en JCatalog, las páginas CreateProduct y EditProduct comparten la misma definicion de ProductBean.

Un objeto view (vista) es un objeto modelo utilizado específicamente en la capa de presentación. Contiene los datos que debe mostrar en la capa de la vista y la lógica para validar la entrada del usuario, manejar los eventos, e interactúar con la capa de lógica-de-negocio. El bean de respaldo es el objeto vista en una aplicación basadas en JSF. Bean de respaldo y objeto vista son términos intercambiables en este tutorial.

En comparación con la aproximación ActionForm y Action de Struts, el desarrollo con beans de respaldo de JSF sigue unas mejores prácticas de diseño orientado a objetos. Un bean de respaldo no sólo contiene los datos a ver, también el comportamiento relacionado con esos datos. En Struts, Action y ActionForm contienen los datos y la lógica por separado.

Todos hemos oído hablar del modelo de objeto de dominio. Entonces, ¿cuál es la diferenica en el modelo de objeto de dominio y un objeto vista? En una sencilla aplicación Web, un modelo de objeto de dominio

Page 8: Tutorial JSP - JSF, Spring e Hibernate

se puede utilizar entre capas, sin embargo, en aplicaciones Web más complejas, se necesita utilizar un modelo de objeto vista separado. Los modelos de objeto de dominio son como objetos de negocio y deberían pertenecer a la capa de lógica-de-negocio. Contiene los datos de negocio y la lógica de negocio asociados con el objeto de negocio específico. Un objeto vista contiene datos específicos de la presentación y el comportamiento. ProductListBean de JCatalog ofrece un buen ejemplo. Contiene los datos y la lógica específica de la capa de presentación; es decir datos y lógica relacionados con la paginación. La desventaja de separar los objetos vista del modelo de objetos de dominio es que debe ocurrir un mapeo de datos entre los dos modelos de objetos. En JCatalog, ProductBeanBuilder y UserBeanBuilder usan las Commons BeanUtils para implementar el mapeo de datos.

 Seguridad

Actualmante, JSF no tiene una característica de seguridad interna. Los requirimientos de seguridad para la aplicación de ejemplo son básicos: sólo se necesita la autentificación basada en nombre de usuario y password para que el usuario entre en la intranet de administración, y no se requiere autorización.

Se han propuesto varias alternativas para manejar la autentificación de usuarios en JSF:

Usar un bean de respaldo: Esta es una solución simple. Sin embargo, ata los beans de respaldo un árbol de herencia específico.

Usar un decorador ViewHandler JSF: De esta forma, la lógica está fuertemente unida a una tecnología específica de capa Web.

Usar un filtro servlet: Una aplicación JSF no es diferente de cualquier otra aplicación Web basada en Java. Hace que un filtro sea el mejor lugar para manejar el chequeo de autentificación. De esta forma, la lógica de autentificación de desacopla de la aplicación web.

En la aplicación de ejemplo, la clase SecurityFilter maneja la autentificación de los usuarios. Actualmente, los recursos protegidos son sólo tres páginas, y sus localizaciones están codificadas dentro de la clase Filter por simplicidad. Se pueden realizar mejoras para externalizar las reglas de seguridad y los recursos protegidos a un fichero de configuración.

 Paginación

La aplicación de un catálogo requiere paginación. La capa de presentación puede manejar la paginación, lo que significa que los datos se debe recuperar y almacenar en esta capa. La paginación también se puede manejar desde la capa de lógica-de-negocio, la capa de integración o incluso desde la capa de EIS. Una de las presunciones de la aplicación JCatalog era que no podía haber más de 500 productos en el catálogo. La información de todos los productos puede caber en la sesión de usuario. La lógica de paginación está en la clase ProductListBean. El parámetro relacionado con la paginación "product per page" se configura mediante la facilidad del bean manejado de JSF.

 Caché

El Caché es una las tecnicas más importantes para mejorar el rendimiento de las aplicaciones web. El caché se puede conseguir en muchas capas dentro de la arquitectura de una aplicación. Es más beneficioso cuando una capa arquitectural puede evitar llamadas a la capa de al lado. La facilidad del bean manejado de JSF hace que el caché sea más sencillo en la capa de presentación. Cambiando el ámbito del bean manejado, los datos que él contiene se pueden cachear dentro de diferentes ámbitos.

La aplicación de ejemplo utiliza un caché de dos niveles. El primer nivel de caché existe dentro de la capa de lógica-de-negocio. La clase CachedCatalogServiceImpl mantiene un caché de lectura/escritura para todos los productos y categorías. Entonces, el caché de primer nivel es un caché de lectura/escritura en el ámbito de la aplicación.

Para simplificar la lógica de paginación y así mejorar la velocidad de la aplicación, los productos también son cacheados dentro de la capa de presentación en el ámbito de la sesión. Cada usuario mantiene su propio ProductListBean dentro de la sesión. Las costes de esta aproximación son la memoria del sistema y datos obsoletos. Durante una sesión de usuario, éste podría ver datos de un catálogo obsoleto si el administrador actualiza el catálogo. Sin embargo, basado en las presunciones, como no existen más

Page 9: Tutorial JSP - JSF, Spring e Hibernate

de 500 productos y el catálogo no se actualiza de forma frecuente, deberíamos poder asumir estos costes.

 Subida de Ficheros

La implementación de referencia de JSF de Sun no soporta subida de ficheros. Struts tiene buenas capacidades para esto, sin embargo se necesita la librería de integración Struts-Faces para utilizar esta característica. En JCatalog, se asocia una imagen con cada producto. Después de que el usuario crea un nuevo producto, debe subir la imagen asociada con él. La imagen es almacenada dentro del sistema de ficheros del servidor de aplicaciones. El ID del producto es el nombre de la imagen.

La aplicación de ejemplo utiliza el servlet <input type="file">, y el API de subida de ficheros de Jakarta Commons, para implementar una utilidad sencilla. Esta utilidad toma dos parámetros, el directorio de imágenes de producto y la result page de la imagen subida. Los dos son configurables mediante ApplicationBean. Puede ver más detalles en la clase FileUploadServlet.

 Validación

Los validadores estándar que vienen con JSF son básicos y podrían no cumplir con los requerimientos del mundo real. Desarrollar sus propios validadores JSF es sencillo. Yo he desarrollado el validador SelectedItemsRange con una etiqueta personalizada en la aplicación de ejemplo. Valida el número de ítems seleccionados por el componente UI UISelectMany:

<h:selectManyListbox value="#{productBean.selectedCategoryIds}" id="selectedCategoryIds">

   <catalog:validateSelectedItemsRange minNum="1"/>

   <f:selectItems value="#{applicationBean.categorySelectItems}" id="categories"/>

</h:selectManyListbox>

 Personalización de los Mensajes de Error

En JSf, se pueden configurar paquetes de recursos y personalizar los mensajes de error para convertidores y validadores. El paquete de recursos se configura dentro de faces-config.xml:

<message-bundle>catalog.view.bundle.Messages</message-bundle>

Las parejas clave-valor de los mensajes de error se añaden al fichero Message.properties:

#conversion error messages

javax.faces.component.UIInput.CONVERSION=Input data is not in the correct type.

#validation error messages

javax.faces.component.UIInput.REQUIRED=Required value is missing.

 La Capa de Lógica-de-Negocio y el Marco de Trabajo Spring

Los objetos y servicios de negocio existen en la capa de lógica-de-negocio. Un objeto de negocio no sólo contiene datos, también la lógica asociada con ese objeto específico. En la aplicación de ejemplo se han identificado tres objetos de negocio: Product, Category, y User.

Los servicios de negocio interactúan con objetos de negocio y proporcionan una lógica de negocio de más alto nivel. Se debería definir una capa de interface de negocio formal, que contenga los interfaces de servicio que el cliente utilizará directamente. POJO, con la ayuda del marco de trabajo Spring,

Page 10: Tutorial JSP - JSF, Spring e Hibernate

implementará la capa de lógica-de-negocio de la aplicación JCatalog. Hay dos servicios de negocio: CatalogService contiene la lógica de negocio relacionada con el manejo del catálogo, y UserService contiene la lógica de manejo del usuario.

Spring está basado en el concepto de inversión de control (IoC). Entre las características de Spring utilizadas en la aplicación de ejemplo se incluyen:

Manejo de Beans con contexto de aplicación: Spring puede organizar de forma efectiva nuestros objetos de la capa central y manejar las conexiones por nosotros. Spring puede eliminar la proliferación de solitarios y facilita unas buenas prácticas de programación orientada a objetos, por ejemplo utilizando interfaces.

Manejo de Transaciones Declarativo: Spring utiliza AOP (aspect-oriented programming) para ofrecer manejo de transaciones declarativo sin utilizar un contenedor EJB. De esta forma, el control de transaciones se puede aplicar a cualquier POJO. El control de transaciones de Spring no está atado a JTA (Java Transaction API) y puede funcionar con diferentes estrategias de transación. En la aplicación de ejemplo se utiliza el manejo de transación declarativo con Hibernate.

Árbol de Excepciones de Acceso a Datos: Spring proporciona un magnífico árbol de excepciones en lugar de SQLException. Para poder utilizar este árbol de excepciones, se debe definir un traductor de excepciones de acceso a datos dentro del fichero de configuración de Spring:

<bean id="jdbcExceptionTranslator" class=

"org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator">    <property name="dataSource">       <ref bean="dataSource"/>    </property> </bean>

En la aplicación de ejemplo, si se inserta un producto nuevo con el ID duplicado, se lanza una DataIntegrityViolationException. La excepción es capturada y relanzada como una DuplicateProductIdException. De esta forma, la DuplicateProductIdException se puede manejar de forma diferente a cualquier otra excepción de acceso a datos.

Integración con Hibernate: Spring no nos fuerza a utilizar su potente característica de abstracción JDBC. Se integra bien con marcos de trabajo de mapeo O/R, especialmente con Hibernate. Spring ofrece un manejo seguro y eficiente de sesiones Hibernate, maneja la configuración de la SessionFactorie de Hibernate y las fuentes de datos JDBC en el contexto de la aplicación, y hace que la aplicación sea más fácil de testear.

 La Capa de Integración e Hibernate

Hibernate es un marco de trabajo de mapeo O/R Open Source que evita la necesidad de utilizar el API JDBC. Hibernate soporta la mayoría de los sistemas de bases de datos SQL. El Hibernate Query Language, diseñado como una extensión mínima, orientada a objetos, de SQL, proporciona un puente elegante entre los mundos objeto y relacional. Hibernate ofrece facilidades para recuperación y actualización de datos, control de transaciones, repositorios de conexiones a bases de datos, consultas programáticas y declarativas, y un control de relaciones de entidades declarativas.

Hibernate es menos invasivo que otros marcos de trabajo de mapeo O/R. Se utilizan Reflection y la generación de bytecodes en tiempo de ejecución, y la generación del SQL ocurre en el momento de la arrancada. Esto nos permite desarrollar objetos persistentes siguiendo el lenguaje común de Java: incluyendo asociación, herencia, polimorfismo, composición y el marco de trabajo Collections de Java. Los objetos de negocio de la aplicación de ejemplo son POJO y no necesitan implementar ningún interface específico de Hibernate.

 Data Access Object (DAO)

Page 11: Tutorial JSP - JSF, Spring e Hibernate

En JCatalog se utiliza el patrón DAO. Este patrón abstrae y encapsula todos los accesos a la fuente de datos. La aplicación tiene dos interfaces DAO: CatalogDao y UserDao. Sus clases de implementación, HibernateCatalogDaoImpl y HibernateUserDaoImpl contienen lógica específica de Hibernate para manejar los datos persistentes.

Implementación

Ahora veamos cómo conectar todo junto e implementar JCatalog. Puede descargar todo el código fuente

de la aplicación desde aquí.

 Diseño de la Base de Datos

Creamos un esquema llamado Catalog para la aplicación de ejemplo, que consta de cuatro tablas, como se ve en la siguiente figura:

Diseño de Clases

En la siguiente figura puede ver el diagrama de clases de la aplicación:

Page 12: Tutorial JSP - JSF, Spring e Hibernate

Durante el diseño se ha utilizado la programación contra interfaces. En la capa de presentación, se han utilizado cuatro beans de respaldo: ProductBean, ProductListBean, UserBean, y MessageBean. La capa de lógica-de-negocio contiene dos servicios de negocio (CatalogService y UserService) y tres objetos de negocio (Product, Category, y User). La capa de integración contiene dos interfaces DAO y sus implementaciones Hibernate. El contexto de aplicación Spring conecta y maneja la mayoría de los beans dentro de las capas de lógica-de-negocio y de integración. ServiceLocator integra JSF con la capa de lógica-de-negocio.

 Conectarlo Todo

Debido a la limitación de espacio de este artículo, sólo examinaremos un caso de uso. El caso de utilización CreateProduct demuestra como conectar todo y construir la aplicación. Antes de sumergirnos en los detalles, usaremos un diagrama de secuencia (en la siguiente figura) para demostrar la integración de principio-a-fin de todas las capas.

Page 13: Tutorial JSP - JSF, Spring e Hibernate

Ahora veremos los detalles de cómo implementar CreateProduct.

 Capa de Presentación

La implementación de la capa de presentación implica crear las páginas JSP, definir la navegación por las páginas, crear y configurar los beans de respaldo, e integrar JSF con la capa de lógica de negocio:

Página JSP: createProduct.jsp es la página para crear un nuevo producto. Contiene componentes UI y conecta los componentes al ProductBean. La etiqueta personalizada ValidateItemsRange valida el número de categorías que el usuario ha seleccionado. Por cada producto nuevo se debe seleccionar al menos una categoria.

Navegación de páginas: La navegación por la aplicación se define en el fichero de configuación de la aplicación, faces-navigation.xml. Aquí están las reglas de navegación definidas para CreateProduct:

<navigation-rule>    <from-view-id>*</from-view-id>    <navigation-case>       <from-outcome>createProduct</from-outcome>       <to-view-id>/createProduct.jsp</to-view-id>    </navigation-case> </navigation-rule> <navigation-rule>    <from-view-id>/createProduct.jsp</from-view-id>    <navigation-case>       <from-outcome>success</from-outcome>       <to-view-id>/uploadImage.jsp</to-view-id>    </navigation-case>    <navigation-case>       <from-outcome>retry</from-outcome>       <to-view-id>/createProduct.jsp</to-view-id>    </navigation-case>    <navigation-case>       <from-outcome>cancel</from-outcome>       <to-view-id>/productList.jsp</to-view-id>    </navigation-case> </navigation-rule> Bean de respaldo:

El ProductBean no sólo contiene los mapeos de propiades a los datos de los componentes UI

Page 14: Tutorial JSP - JSF, Spring e Hibernate

de la página, también tiene tres acciones: createAction, editAction, y deleteAction. Aquí está el código para el método createAction():

public String createAction() {    try {       Product product = ProductBeanBuilder.createProduct(this);       //Save the product.       this.serviceLocator.getCatalogService().saveProduct(product);       //Store the current product id inside the session bean.       //For the use of image uploader.       FacesUtils.getSessionBean().setCurrentProductId(this.id);       //Remove the productList inside the cache.       this.logger.debug("remove ProductListBean from cache");       FacesUtils.resetManagedBean(BeanNames.PRODUCT_LIST_BEAN);    } catch (DuplicateProductIdException de) {       String msg = "Product id already exists";       this.logger.info(msg);       FacesUtils.addErrorMessage(msg);       return NavigationResults.RETRY;    } catch (Exception e) {       String msg = "Could not save product";       this.logger.error(msg, e);       FacesUtils.addErrorMessage(msg + ": Internal Error");       return NavigationResults.FAILURE;    }    String msg = "Product with id of " + this.id + " was created

successfully.";    this.logger.debug(msg);    FacesUtils.addInfoMessage(msg);    return NavigationResults.SUCCESS; }

Dentro de la acción, se construye un objeto de negocio Product basado en las propiedades de ProductBean. ServiceLocator busca el CatalogService. Finalmente, createProduct pide su delegado al CatalogService, que está en la capa de lógica-de-negocio.

Declaración del Bean Manejado: El ProductBean se debe configurar en el fichero de configuración de recursos JSF, faces-managed-bean.xml:

<managed-bean>    <description>       Backing bean that contains product information.    </description>    <managed-bean-name>productBean</managed-bean-name>    <managed-bean-class>catalog.view.bean.ProductBean</managed-bean-class>    <managed-bean-scope>request</managed-bean-scope>        <managed-property>       <property-name>id</property-name>       <value>#{param.productId}</value>    </managed-property>    <managed-property>       <property-name>serviceLocator</property-name>       <value>#{serviceLocatorBean}</value>    </managed-property> </managed-bean>

Page 15: Tutorial JSP - JSF, Spring e Hibernate

Se configura el ProductBean para tener un ámbito de petición, lo que significa que la implementación JSF crea un nuevo ejemplar de ProductBean por cada petición si se ha referenciado dentro de la página JSP. La propiedad ID-managed se rellena con el parámetro productId de la petición. La implementación JSF obtiene el parámetro desde la petición y selecciona la propiedad manejada.

Integración entre las capas de presentación y de lógica-de-negocio: ServiceLocator abstrae la lógica para localizar los servicios. En la aplicación de ejemplo, ServiceLocator está definido como un interfae. El interface está implementado como un bean manejado JSF, ServiceLocatorBean, que busca los servicios desde el contexto de aplicación Spring:

ServletContext context = FacesUtils.getServletContext(); this.appContext =

WebApplicationContextUtils.getRequiredWebApplicationContext(context); this.catalogService =

(CatalogService)this.lookupService(CATALOG_SERVICE_BEAN_NAME); this.userService = (UserService)this.lookupService(USER_SERVICE_BEAN_NAME);

El ServiceLocator está definido como una propiedad dentro de BaseBean. La facilidad de bean manejado de JSF conecta la implementación del ServiceLocator con aquellos beans manejados que deben acceder a él. Se utiliza la Inversión de Control.

 Capa de Lógica-de_Negocio

La tarea de esta capa consiste en definir los objetos de negocio, creando los interfaces de servico con sus implementaciones, y conectándo los objetos con Spring.

Objetos de Negocio: Como Hibernate proporciona la persistencia, los objetos de negocio Product y Category deben proporcionar métodos get y set para todos sus campos.

Servicios de Negocio: El interface CatalogService define todos los servicios relacionados con el control del catálogo:

public interface CatalogService {    public Product saveProduct(Product product) throws CatalogException;    public void updateProduct(Product product) throws CatalogException;    public void deleteProduct(Product product) throws CatalogException;    public Product getProduct(String productId) throws CatalogException;    public Category getCategory(String categoryId) throws CatalogException;    public List getAllProducts() throws CatalogException;    public List getAllCategories() throws CatalogException; }

CachedCatalogServiceImpl es la implementación del interface de servicio, que contiene un método set para un objeto CatalogDao. Spring conecta el CachedCatalogServiceImpl con el objeto CatalogDao. Como estámos condificando para interfaces, no acoplamos fuertemente las implementaciones.

Configuración de Spring: Aquí está la configuración de Spring para CatalogService:

<!-- Hibernate Transaction Manager Definition --> <bean id="transactionManager"

class="org.springframework.orm.hibernate.HibernateTransactionManager">    <property name="sessionFactory"><ref local="sessionFactory"/></property> </bean>

Page 16: Tutorial JSP - JSF, Spring e Hibernate

<!-- Cached Catalog Service Definition --> <bean id="catalogServiceTarget"

class="catalog.model.service.impl.CachedCatalogServiceImpl" init-method="init">

   <property name="catalogDao"><ref local="catalogDao"/></property> </bean> <!-- Transactional proxy for the Catalog Service --> <bean id="catalogService"

class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

   <property name="transactionManager"><ref local="transactionManager"/></property>

   <property name="target"><ref local="catalogServiceTarget"/></property>    <property name="transactionAttributes">       <props>          <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>        <prop key="save*">PROPAGATION_REQUIRED</prop>        <prop key="update*">PROPAGATION_REQUIRED</prop>        <prop key="delete*">PROPAGATION_REQUIRED</prop>       </props>    </property> </bean>

Se configura el control de transación declarativo para el CatalogService. CatalogService puede conectarse a una implementación diferente de CatalogDao. Spring crea y maneja un único objeto CatalogService y no se necesita una factoría.

Ahora que la capa de lógica de negocio está lista, conectémosla con la capa de integración

Integración entre Spring e Hibernate: Aquí está la configuración de HibernateSessionFactory:

<!-- Hibernate SessionFactory Definition --> <bean id="sessionFactory"

class="org.springframework.orm.hibernate.LocalSessionFactoryBean">    <property name="mappingResources">       <list>          <value>catalog/model/businessobject/Product.hbm.xml</value>          <value>catalog/model/businessobject/Category.hbm.xml</value>          <value>catalog/model/businessobject/User.hbm.xml</value>       </list>    </property>    <property name="hibernateProperties">       <props>          <prop

key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>        <prop key="hibernate.show_sql">true</prop>        <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>        <prop

key="hibernate.cache.provider_class">net.sf.hibernate.cache.HashtableCacheProvider</prop>

      </props>    </property>    <property name="dataSource">       <ref bean="dataSource"/>    </property> </bean>

Page 17: Tutorial JSP - JSF, Spring e Hibernate

CatalogDao utiliza HibernateTemplate para integrarse entre Hibernate y Spring. Aquí está la configuración para HibernateTemplate:

<!-- Hibernate Template Defintion --><bean id="hibernateTemplate" class="org.springframework.orm.hibernate.HibernateTemplate">   <property name="sessionFactory"><ref bean="sessionFactory"/></property>   <property name="jdbcExceptionTranslator"><ref bean="jdbcExceptionTranslator"/></property></bean>

 Capa de Integración

Hibernate mapea objetos a la base de datos relacional utilizando un fichero de configuración XML. En JCatalog, Product.hbm.xml expresa el mapeo para el objeto de negocio Product. Se utiliza Category.hbm.xml para el objeto de negocio Category. Los ficheros de configuración están en el mismo directorio que los objetos de negocio correspondientes. Aquí está el Product.hbm.xml:

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC       "-//Hibernate/Hibernate Mapping DTD 2.0//EN"      "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping package="catalog.model.businessobject">   <class name="Product" table="product">      <id name="id" column="ID" unsaved-value="null">         <generator class="assigned"/>      </id>      <property name="name" column="NAME" unique="true" not-null="true"/>      <property name="price" column="PRICE"/>           <property name="width" column="WIDTH"/>            <property name="height" column="height"/>           <property name="description" column="description"/>      <set name="categoryIds" table="product_category" cascade="all">         <key column="PRODUCT_ID"/>         <element column="CATEGORY_ID" type="string"/>      </set>   </class></hibernate-mapping>

CatalogDao se conecta con HibernateTemplate mediante Spring:

<!-- Catalog DAO Definition: Hibernate implementation --><bean id="catalogDao" class="catalog.model.dao.hibernate.CatalogDaoHibernateImpl">   <property name="hibernateTemplate"><ref bean="hibernateTemplate"/></property></bean>

Conclusión

Este tutorial ha mostrado cómo integrar JSF con el marco de trabajo Spring e Hibernate para construir una aplicación Web del mundo real. La combinación de estas tres tecnologías proporciona un sólido marco de trabajo para el desarrollo de aplicaciones Web. Para este tipo de aplicaciones se debería utilizar una arquitectura multi-capa como arquitectura de alto nivel. JSF se acopla muy bien en el patrón de diseño MVC y se puede utilizar para implementar la capa de presentación. El marco de trabajo Spring se puede utilizar en la capa de lógica-de-negocio para manejar los objetos de negocio, y porporcionar control de transaciones declarativoo y control de recursos. Spring se integra muy bien con Hibernate. Hibernate es un poderoso marco de trabajo de mapeo O/R y puede proporcionar el mejor servicio dentro de la capa de integración.

Particionando toda la aplicación Web en capas y programando contra interfaces, se pueden reemplazar las tecnologías usadas para cada capa de la aplicación. Por ejemplo, Struts puede ocupar el lugar de JSF para la capa de presentación, y JDO puede reemplazar a Hibernate en la capa de integración. La integración entre las capas no es trivial. El uso de la inversión de control y del patrón de diseño Service

Page 18: Tutorial JSP - JSF, Spring e Hibernate

Locator puede hacerlo más sencillo. JSF proporciona funcionalidades que no poseen otros marcos de trabajo como Struts. Sin embargo, esto no significa que usted tenga que tirar Struts y empezar a utilizar JSF ahora mismo. Si JSF debe utilizarse o no como marco de trabajo Web para sus aplicaciones, depende del estado de sus proyectos, de los requerimientos funcionales, y de la experiencia de su equipo.