Mostrando entradas con la etiqueta Spring. Mostrar todas las entradas
Mostrando entradas con la etiqueta Spring. Mostrar todas las entradas

miércoles, 28 de agosto de 2013

Integrando Spring Security con el Framework ZK

clip_image002

Spring Security es una solución común para el desarrollador para satisfacer las necesidades de seguridad de una aplicación web de Java, que es ampliamente utilizado y es una tecnología probada. Sin embargo, debido a su naturaleza para proteger los recursos por parte de patrones a través de URL, no es obvia para los desarrolladores de aplicaciones para darse cuenta de la Seguridad de Spring se puede adaptar con una petición Ajax mecanismo de manejo específico de un marco de Ajax [1].

Así que en este artículo, voy a presentarles cómo integrar Spring Security con ZK sin problemas por ir a través de la construcción de una aplicación de demostración sencilla (Una publicación del artículo y un sistema de edición).

Recursos para descargar

Puede descargar el código fuente de aquí

El proyecto está basado en Maven, si quieres probar diferentes versiones de ZK o spring, cambie el número de versión en pom.xml

Demostración Detalles de la aplicación

Esta aplicación Demo es un simple artículo publicar y editar sistema que permite tres tipos de usuarios para acceder a:

  • usuario con rol ROLE_USER
  • usuario con rol ROLE_EDITOR
  • usuario anónimo con rol IS_AUTHENTICATED_ANONYMOUSLY

clip_image004

  • El usuario Anónimo puede visitar la página de inicio que contiene la lista de artículos, y se puede ver el contenido de un artículo haciendo clic en el enlace de página de inicio.
  • Al usuario con rol ROLE_USER se le permite publicar artículos nuevos y editar sus propios artículos.
  • El usuario con rol ROLE_EDITOR es el más poderoso, es capaz de editar y borrar cualquier artículo.

Este artículo se basa en los requisitos de implementación de esta aplicación para demostrar la integración de Spring Security con ZK.

Configuración de Spring Security

En primer lugar, vamos a ver cómo configurar nuestro proyecto. Para utilizar Spring Security, tenemos que añadir algunos oyentes y declaraciones de filtro en web.xml

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

/WEB-INF/applicationContext.xml

/WEB-INF/applicationContext-security.xml

</param-value>

</context-param>

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<listener>

<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>

</listener>

<listener>

<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>

</listener>

<filter><!-- the filter-name must be preserved, do not change it! -->

<filter-name>springSecurityFilterChain</filter-name>

<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

</filter>

<filter-mapping>

<filter-name>springSecurityFilterChain</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>


Como se puede ver, a pesar de los oyentes de contexto ordinarios de Spring (RequestContextListener y ContextLoaderListener), declaramos HttpSessionEventPublisher y springSecurityFilterChain de Spring Security. Aquí HttpSessionEventPublisher es opcional y está diseñada para Spring Security para hacer el control de sesión simultánea detallada, springSecurityFilterChain es el gancho principal de toda la funcionalidad de Spring Security de la aplicación, es necesario y debe ser nombrado springSecurityFilterChain.

applicationContext-security.xml

Aquí, en este proyecto, separamos el fichero applicationContext.xml de Spring en dos archivos, el original applicationContext.xml es para el backend bean y el service bean declarations y el adicional applicationContext-security.xml es sólo para la configuración de Spring Security.

En applicationContext-security.xml, hay dos elementos importantes que tenemos que configurar, que son el elemento <http> y el elemento <authentication-manager>.

Configuración del elemento Http

El elemento <http> es para decirle a Spring qué tipo de recursos necesita ser asegurado, el puerto que será utilizado por contenedor para conexiones http y https, y qué tipo de inicio de sesión en solución se utiliza en esta aplicación web.

<http auto-config="true">

<port-mappings>

<port-mapping http="8080" https="8443"/>

</port-mappings>

<intercept-url pattern="/zkau/**" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="any"/>

<intercept-url pattern="/login.zul" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https" />

<intercept-url pattern="/newArticle.zul" access="ROLE_USER" requires-channel="https" />

<intercept-url pattern="/j_spring_security_check" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https" />

<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="any" />

<session-management session-fixation-protection="none" />

<form-login login-page="/login.zul"

authentication-failure-url="/login.zul?login_error=1"

login-processing-url="/j_spring_security_check"/>

<logout logout-success-url="/index.zul" invalidate-session="true" />

</http>


Configuración del Authentication Manager

La declaración de elemento <authentication-manager> está diseñado para gestionar authentication-provider, que es el proveedor de la instancia de autenticación de Spring y hará el trabajo real de la autenticación. Puede declarar múltiples authentication-providers, con el fin de aprovechar distintas fuentes de los usuarios (por ejemplo: openidAuthenProvider o LDAPAuthenProvider), en este proyecto se extiende UserDetailsService del authentication-provider predeterminado:

<authentication-manager>

<authentication-provider user-service-ref="myUserDetailsService">

<password-encoder hash="md5" />

</authentication-provider>

</authentication-manager>

<beans:bean id="myUserDetailsService"

class="org.zkoss.demo.springsec.model.MyUserDetailsService"/>

La protección de una solicitud de página

Después de la configuración de Spring Security, ahora, vamos a ver cómo utilizarla para proteger a una solicitud de archivo zul.

Escenario: cuando el usuario solicita un recurso limitado

En nuestro proyecto de demostración, NewArticle.zul es un recurso limitado que sólo pueden acceder los usuarios que ya se ha iniciado sesión, lo que es natural, porque para poder hacer un artículo, tenemos que saber quién es el autor. En Spring Security, para restringir un recurso para cierto usuario (que tiene suficiente permiso) para tener acceso es muy sencillo, simplemente declaramos elemento <intercept-url> bajo <http> en applicationContext-security.xml:

<intercept-url pattern="/newArticle.zul" access="ROLE_USER" requires-channel="https" />

Aquí el atributo patrón se utiliza para determinar qué solicitud esta configuración tendrá efecto, y si la dirección URL de una solicitud coincide con este patrón, el atributo de acceso se utilizará para comprobar autorizaciones del usuario actual.

Como podemos ver, la solicitud de protección de página en Spring Security es muy sencilla e intuitiva, todo se basa en la comparación de patrones de solicitar la ruta url.

Log-in Page Implementation in ZK


Now, after the newArticle.zul has been secured, the log-in page(login.zul) which is required for authentication process has to be implemented for user to perform log in. Here let's see how to implement a log-in page in ZUL:

Implementación de la Página Log-in en ZK

Ahora, después de que el newArticle.zul ha sido asegurado, la página de log-in (login.zul) que se requiere para proceso de autenticación tiene que ser implementada para que usuario pueda acceder:

<html:form id="f" name="f" action="j_spring_security_check" method="POST"

xmlns:html="native">

<grid>

<rows>

<row>User: <textbox id="u" name="j_username"/></row>

<row>Password: <textbox id="p" type="password" name="j_password"/></row>

<row spans="2">

<hbox>

<html:input type="reset" value="Reset"/>

<html:input type="submit" value="Submit Query"/>

<button type="submit" label="Accedi_trendy" mold="trendy"/>

<button type="submit" label="Accedi_os" />

</hbox>

</row>

</rows>

</grid>

</html:form>


  1. Un elemento HTML <form> tiene que ser declarado fuera de las entradas de nombre de usuario y contraseña.
  2. El formulario debe contener dos elementos de entrada denominados j_username y j_passoword. Para aplicar un efecto ajax y las características de estos insumos, se puede utilizar el componente <textbox> en su lugar.
  3. El Atributo action Form tiene que asignar el valor del atributo login-processing-url del elemento <form-login> en applicationContext-security.xml

Si un usuario anónimo, hace clic en el botón Nuevo Artículo en página de inicio, será re-direccionado a nuestro login.zul.

Asegurar Vista parcial mediante el uso de EL en ZUL

Con el fin de asegurar parte de la vista parcial de la página web, Spring Security tiene su propio taglib que brinda soporte básico para el acceso a la información de seguridad y la aplicación de restricciones de seguridad en las páginas JSP. Y aquí la seguridad en ZUL, marco ZK también proporciona métodos para definir la nueva biblioteca de etiquetas. En nuestra aplicación de ejemplo, para el uso de Spring Security a través de EL hicimos nuestra propia biblioteca de etiquetas.

Biblioteca de etiquetas Zul para Spring Security.

Aunque ZK Developer Reference proporciona información muy detallada sobre lo que podemos hacer en un taglib personalizado de ZK, aquí sólo nos centramos en lo que queremos tener para Spring Security.

En primer lugar, vamos a crear un security.tld bajo / WEB-INF /. Sin embargo, para los proyectos más serios, se puede hacer la ruta de clases: Método metainfo / tld / config.xml como se menciona en la Referencia del programador.

En segundo lugar, se definen las funciones de EL / WEB-INF/security.tld, aquí está el ejemplo:

<taglib>

<uri>http://www.zkoss.org/demo/integration/security</uri>

<description>

Methods and actions for ZK + Spring Security

</description>

<function>

<name>isAllGranted</name>

<function-class>org.zkoss.demo.springsec.SecurityUtil</function-class>

<function-signature>

boolean isAllGranted(java.lang.String authorities) {

</function-signature>

<description>

Return true if the authenticated principal is granted authorities

of ALL the specified roles.

</description>

</function>

...

Como podemos ver, el documento debe comenzar con un elemento raíz: <taglib> con un elemento <uri> en ella. A continuación, se puede declarar funciones. En la declaración de la función, mapeamos un método (isAllGranted ()) de org.zkoss.demo.springsec.SecurityUtil a nuestra función EL isAllGranted, sobre la SecurityUtil, la aplicación de la misma se basa en SecurityContextHolder de Spring Security.

Ahora vamos a ver cómo utilizar taglib personalizado Spring Security en ZUL.

Modo de Uso: Protección de Acción

En nuestro proyecto de demostración, de acuerdo con los casos de uso más arriba, tenemos una función "eliminar artículo" que sólo usuario con rol: ROLE_EDITOR puede acceder. Ahora, con nuestras bibliotecas de etiquetas personalizadas para Spring Security, podemos establecer algunas limitaciones de esta manera:

<?taglib uri="/WEB-INF/security.tld" prefix="sec"?>

...

<button id="deleteBtn" label="Delete"

if="${sec:isAllGranted('ROLE_USER')}"

disabled="${not sec:isAllGranted('ROLE_EDITOR')}"/>

...

Atributos Especiales del componente ZK para la Seguridad

En el código de ejemplo anterior, se ha utilizado el atributo personalizado EL + disabled del botón de ZK para proteger el clic del usuario, ZK también ofrece otras características que pueden ser aplicables para la restricción de seguridad tales como visible y de sólo lectura (para combobox). Estos atributos que se basan en efectos html son muy útiles para cumplir con los requisitos de la escalada de permiso para acceder a la interfaz de usuario.

Protegiendo la solicitud de ZK Ajax

En un marco como el Ajax ZK, hay dos tipos de solicitudes. Ahora, vamos a hablar de la parte más difícil de esta integración es decir, cómo hacer frente a la petición de Ajax ZK usando Spring Security?

En primer lugar, tenemos que echar un vistazo a cómo proteger una solicitud de página de una manera más programática.

Haga Security Check en Listener de ZK

En algunas situaciones, puede ser que necesite el usuario para hacer control de seguridad en el código java no en ZUL, por ejemplo, en nuestro accessDeniedExTest.zul, tenemos un iniciador que hacer el registro de seguridad en el método public void doInit(Page page, Map<String, Object> args) throws Exception.

public class AccessDeniedExInit extends GenericInitiator {

public void doInit(Page page, Map<String, Object> args) throws Exception {

if(SecurityUtil.isNoneGranted("ROLE_EDITOR")){

throw new AccessDeniedException("this is a test of AccessDeniedException!");

}

}

}

El AccessDeniedException es clave para la cadena de filtros de Spring Security para manejar, y todo funciona bien en una situación de solicitud de la página, pero lo que si tiramos la excepción en una acción que dice EventListener de ZK?

Chequeo de Seguridad en Acciones de ZK.

Lanzando AccessDeniedException durante una solicitud Ajax no activar el proceso de autenticación de Spring Securit. Esta autorización se debe a la perspectiva del ZK AU Engine, que es imposible para cualquier otro outsider de org.zkoss.zk.au.http. DHtmlUpdateServlet saber cómo componer una respuesta significativa y correctamente estructurada para el motor del cliente en el navegador. Por lo que cualquier excepción que debe ser manejado dentro de ZK AU Engine.

Para hacer esto tenemos que convertir petición Ajax ZK a una petición de una página normal, así que podemos dejar Spring Security para manejar la AccessDeniedException en una solicitud de página normal. la puesta en práctica de esta idea incluye 3 pasos:

PASO 1: Convertir Ajax Request to Request

En primer lugar, tenemos que decirle ZK queremos encargo del mecanismo de control de errores para AccessDeniedException. Para ello es muy simple, en zk.xml añadimos esta sección:

<error-page>

<exception-type>org.springframework.security.access.AccessDeniedException</exception-type>

<location>security_process.zul</location>

</error-page>

Manejo de errores de ZK es muy sencillo, se asigna un tipo de error a una página ZUL, la página ZUL se analizará con base en el escritorio actual, si ocurre tal error. En nuestro security_process.zul simplemente tenemos un iniciador dentro de manejar AccessDeniedException:

<?init class="org.zkoss.demo.springsec.ui.error.SpringSecurityHandleInit"?>

<zk>

<!-- DO NOTHING! -->

</zk>

Luego, en SpringSecurityHandleInit, podemos comprobar si se trata de una petición Ajax, almacenamos todos los datos necesarios en la sesión y le pedimos al motor del cliente para hacer el cambio de dirección de nuevo a este security_process.zul nuevo.

if(exec.isAsyncUpdate(null) ){

//STEP 1: convert Ajax Request to Page Request(Error Handling Page Request)

System.out.println(">>>> Security Process: STEP 1");

if(ex instanceof AccessDeniedException){

sess.setAttribute(VAR_DESKTOP_REQ_URI, getOriginalDesktopUri());// for login-success-url

sess.setAttribute(VAR_SPRING_SECURITY_ERROR, ex);

Executions.sendRedirect(toSecurityProcessUrl((AccessDeniedException) ex));// GOTO STEP 2 by redirection.

}else{

throw new IllegalArgumentException(

"How come an unexpected Exception type will be mapped to this handler? please correct it in your zk.xml");

}

PASO 2: Lanzar AccessDeniedException de redirección para adaptarse Proceso de seguridad Resorte

El cambio de dirección será de nuevo a este security_process.zul nuevo, y porque esta vez estamos dentro de una solicitud de página, se puede obtener la excepción de regresar de HttpSession y tírelo a la basura para que la cadena de filtros de Spring Security para manejarlo.

Exception err = (Exception) sess.getAttribute(VAR_SPRING_SECURITY_ERROR);

String dtPath = (String) sess.getAttribute(VAR_DESKTOP_REQ_URI);

if(err!=null){

//STEP 2: throw Error in Error Handling Page Request.

System.out.println(">>>> Security Process: STEP 2");

sess.removeAttribute(VAR_SPRING_SECURITY_ERROR);

throw err;// we suppose Spring Security Error Filter Chain will handle this properly.

}

Ahora, Spring Security comprobará principio del usuario actual y hacer el proceso de autenticación o autorización. En el proceso de autenticación, el usuario será redirigido a la login.zul como lo hemos configurado, y si log-in es el éxito, el usuario será redirigido a la ubicación original donde se produjo esta excepción y la ubicación aquí será nuestra security_process.zul que es no es el sitio original en el que la petición Ajax causó el error. Así que tenemos el tercer paso para manejar esta situación.

PASO 3: Maneje el Login Success redirección

Vamos a volver a ver el código de ejemplo de paso 1, el código

sess.setAttribute(VAR_DESKTOP_REQ_URI, getOriginalDesktopUri());

reservado la ruta de solicitud original del ZUL que generó el escritorio, y que se prepara la información para STEP 3, la aplicación de la forma de recuperar la ruta original del escritorio (impl de getOriginalDesktopUri ()) es la siguiente:

private static String getOriginalDesktopUri(){

// developer may implement this part to adapt to PushState or any other Page based Framework, that might have interference to request URI.

String str = Executions.getCurrent().getDesktop().getRequestPath();

String qs = Executions.getCurrent().getDesktop().getQueryString();

System.out.println(">>>security Process: Desktop path= "+str);

return str+"?"+qs;

}

Y ahora en el PASO 3, simplemente redirigir usuarios de nuevo a nuestro camino escritorio:




else if(dtPath!=null){

System.out.println(">>>> Security Process: STEP 3");

//STEP 3: if Spring Security Authentication was triggered at STEP 2,

//then we need STEP 3 to redirect back to original URI the very first desktop belongs to.

sess.removeAttribute(VAR_DESKTOP_REQ_URI);

exec.sendRedirect(dtPath);

}

Para más detalles, por favor, eche un vistazo al código fuente de SpringSecurityHandleInit.

Uso: Proteja botón Abrir Editor

Después de tejer ZK petición Ajax al Spring Security, vamos a ver cómo aplicar restricción de seguridad a la acción del usuario en nuestro proyecto de demostración, en primer lugar, en uno de nuestros casos de uso del usuario escenario se le permite editar un artículo si es el autor o tiene 'ROLE_EDITOR , por lo que el botón de editor abierto en ArticleContentViewCtrl para articleContent.zul se implementa como esto:

@Listen("onClick=#openEditorBtn")

public void edit(){

//ownership & permission check.

if(!isOwner() && SecurityUtil.isNoneGranted("ROLE_EDITOR")){

throw new AccessDeniedException(

"The user is neither the author, nor a privileged user.");

}

ArticleEditor editor = new ArticleEditor();

editor.setParent(container);

editor.doHighlighted();

}

Como se muestra, tiramos AccessDeniedException directamente en un detector de eventos, y podemos hacer lo mismo en la acción ZK Ver Modelo:

public class TestVModel {

...

@Command

@NotifyChange("fullName")

public void doChange(){

if(SecurityUtil.isNoneGranted("ROLE_EDITOR")){

throw new AccessDeniedException("you are not an editor!");

}

}

}

Si está utilizando un bean de Spring con anotación @ Secured etiquetado de algunos métodos, cuando el usuario no pasa el control de seguridad, el AccessDeniedException lanzado será tratada de la misma manera.

Resumen

En este artículo, hablamos de cómo utilizar Spring Security en una aplicación web ZK, y también mostró una solución de adaptar petición Ajax ZK de cadena de filtros de Spring Security.

Esperamos que le sea útil y quedamos al tanto de sus comentarios.




{ Leer Más }


martes, 18 de junio de 2013

Introducción a Spring Roo para el desarrollo rápido de aplicaciones.

clip_image002

Cuando los desarrolladores JAVA se enfrentan a un nuevo proyecto por lo general tienden a reutilizar buenas prácticas, frameworks de diferentes niveles, patrones de diseño y de arquitectura que en su conjunto les ayudan a no reinventar la rueda y a reutilizar cosas ya hechas en trabajos previos.

Esto lleva mucho copy/paste, cambio en las configuraciones y tiempo invertido que se podría utilizar en implementar cosas nuevas. Cuando esto sucede existe un framework que nos puede quitar mucho trabajo de encima: Spring Roo.

Spring Roo es una herramienta RAD (Rapid Application Development) para JAVA y basada en Spring Framework. A partir del uso de este framework se puede comprobar que es un generador avanzado de código que se puede ir utilizando desde una línea de comandos similar a Maven donde a través de una guía vamos configurando todo un proyecto a lo largo de su ciclo de vida.

Importante es que al no contener ningún componente en tiempo de ejecución no interfiere en el despliegue de las soluciones ni crea dependencias con el producto final, de forma tal que resulta transparente para el despliegue en producción.

Su desarrollo está enfocado en una serie de plugins como pasa con Maven y se usan scripts relacionados con estos plugins para ejecutar las tareas.

Entre sus características básicas se pueden identificar:

  • Permite desarrollar una aplicación Web en minutos. Genera un war. Construye dos capas: la de persistencia y la de presentación. Para agregar la capa de negocio, se pueden agregar las clases manualmente a los controladores generados con Roo.
  • Permite generar un modelo de datos complejo, incluyendo validaciones.
  • La aplicación Web es RESTful y tiene soporte para internacionalización en varios idiomas.
  • Tiene soporte de seguridad out-of-the-box.
  • La presentación usa Dojo (incorporar otro, por ejemplo JQuery, se hace a mano y es costoso).

Entre los frameworks que usa podemos listar los siguientes:

  • AspectJ
  • Java Persistence API: Hibernate, OpenJPA, EclipseLink
  • Java Server Pages
  • JUnit
  • Log4J
  • Maven
  • Selenium
  • Spring Framework
  • Spring MVC
  • Spring Security
  • Spring Web Flow

Los requisitos para su uso son bastante sencillos:

1. Tener JAVA instalado.

2. Tener MAVEN instalado.

Para descargar el framework pueden ir a su sitio oficial http://www.springsource.org/roo/ y obtener la versión más actualizada así como ejemplos de su uso.

Revisando la web podemos encontrar los siguientes puntos a su favor:

Usabilidad.

El primer punto a favor de Spring Roo es su interfaz, un intérprete de comandos con autocompletado, muy similar a las shells de *nix con readline.
Esto nos va a permitir crear scripts propios para generar el esqueleto o partes de la aplicación con la flexibilidad y la productividad propia de los intérpretes de comandos. Además el intérprete es realmente intuitivo. Basta pulsar [tab] para ver las opciones que disponemos o introducir el comando 'hint' para obtener indicaciones sobre el próximo paso a seguir. Por supuesto, podemos seguir usando nuestro IDE favorito para el desarrollo. Spring Roo vigila los cambios que hacemos en el código y toma las medidas oportunas en caso de que deba hacerlo.

Funcionalidad.

Spring Roo está basado en una arquitectura modular que permite construir distintos tipos de aplicaciones según los módulos que utilicemos. Sin embargo, en principio, está bastante orientado a la creación de aplicaciones web basadas en Spring MVC en la capa de presentación y una capa de modelos del dominio persistentes mediante JPA.

Los modelos del dominio encapsulan tanto lógica de negocio como la lógica de persistencia, un patrón de ORM, Active Record, descrito por Martin Fowler en P of EAA como:
"An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data."

Representa una simplificación importante sobre la clásica arquitectura de tres capas donde se han suprimido la capa de servicios (Service Layer) y la capa de acceso a datos (DAO, Repository) que suelen ser una sobrecarga innecesaria en proyectos web de tamaño medio o pequeño.

La productividad de la arquitectura basada en registros activos ha sido probada considerablemente en el pasado, por ejemplo en frameworks como Ruby on Rails.

Otra ventaja a tener en cuenta es que suele ser bastante más asequible para equipos de desarrollo con un porcentaje alto (o muy alto) de programadores con poca experiencia, como por ejemplo, las factorías de software. El lanzamiento de la aplicación es un auténtico relámpago y la herramienta se hace cargo de muchas de las tareas que, a pesar de ser monótonas para programadores experimentados, suelen ser barreras difíciles de pasar para los nuevos por la cantidad de conceptos que manejan.

Spring Roo incluye las siguientes funcionalidades:

  • Lanzamiento de una aplicación nueva (aunque también puede aplicarse a una aplicación existente).
  • Configurar el sistema de compilación (actualmente soporta Maven2).
  • Instalar un proveedor de JPA.
  • Configurar la base de datos que se va a utilizar.
  • Configurar Log4Java.
  • Crear entidades JPA y manejar automáticamente las inyecciones de dependencias (Spring) y los métodos de persistencia.
  • Añadir campos a las entidades (Active Records) incluyendo las anotaciones de JPA como del nuevo estándar de validación de Beans JSR 303.
  • Manejar test de integración JUnit automáticos incluso cuando existen relaciones entre entidades o restricciones en las validaciones de los beans.
  • Crear y mantener controladores de Spring MVC que cumplen las convecciones REST, incluyendo la creación y el mantenimiento de las páginas JSP.
  • Crear esqueletos de controladores de Spring MVC que pueden ser terminados por el programador, ahorrando el trabajo de buscar las anotaciones y los métodos que normalmente se utilizan en dichos controladores.
  • Creación dinámica de métodos finders sin necesidad de escribir consultas en JPA QL.
  • Instalación y configuración simple de Spring Security
{ Leer Más }


viernes, 14 de junio de 2013

Desarrollo de una aplicación web MVC en JAVA con ZK, Spring e Hibernate.

Ya en otras entradas hemos visto los temas introductorios a ZK como framework JAVA para el desarrollo de la capa de presentación y también hemos visto el uso de Spring e Hibernate para el desarrollo de la capa de negocio y de persistencia.

En esta entrada veremos a través de un ejemplo práctico como combinar estos frameworks para implementar un CRUD (Patrón de caso de uso con las funcionalidades de añadir, modificar, eliminar, listar).

El proyecto será una aplicación web en Maven por lo que comenzaremos por el fichero pom.xml donde pondremos los repositorios que usaremos y las dependencias a incluir en el proyecto. De esta forma Maven las gestionará por nosotros.

El pom lo pueden ver aquí.

<pre class="brush:xml;">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>GestUsuariosZK</groupId>
<artifactId>GestUsuariosZK</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>GestUsuariosZK</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.springframework.version>3.2.0.RELEASE</org.springframework.version>
<zk.version>6.5.0</zk.version>
<zkel.version>1.1.0</zkel.version>
</properties>

<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.8</version>
<configuration>
<wtpversion>2.0</wtpversion>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>


<!-- dependencias de ZK -->

<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zk</artifactId>
<version>${zk.version}</version>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zul</artifactId>
<version>${zk.version}</version>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zhtml</artifactId>
<version>${zk.version}</version>
</dependency>
<dependency>
<groupId>org.zkoss.common</groupId>
<artifactId>zcommon</artifactId>
<version>${zk.version}</version>
</dependency>
<dependency>
<groupId>org.zkoss.zkforge.el</groupId>
<artifactId>zcommons-el</artifactId>
<version>${zkel.version}</version>
</dependency>
<dependency>
<groupId>org.zkoss.common</groupId>
<artifactId>zweb</artifactId>
<version>${zk.version}</version>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zkplus</artifactId>
<version>${zk.version}</version>
</dependency>


<!-- dependencias comunes -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
</dependency>



<!-- dependencias de Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>

<!-- dependencias para el acceso a datos -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.9.Final</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>zk repository</id>
<url>http://mavensync.zkoss.org/maven2</url>
</repository>
</repositories>
</project>
</pre>

Básicamente la aplicación es una implementación del patrón de arquitectura MVC o Modelo Vista Controlador.

· Tendremos las vistas que serán las páginas .zul.

· Tendremos los modelos que serán las clases encargadas del modelado de las entidades de nuestro sistema, tal y como vimos en las entradas relacionadas con la persistencia.

· Tendremos los controladores que son las clases que se encargan de coordinar las acciones entre las vistas y los modelos. Básicamente recibe eventos de las vistas y actualiza los modelos así como obtienen datos de los modelos y cambian la representación de dichos datos en las vistas.

De esta manera se logra una separación de responsabilidades eficiente. La idea general la pueden ver en la siguiente imagen.

clip_image001

La estructura del proyecto es la siguiente:

clip_image002

En el paquete org.desarrollo.ejemplo1.web se tiene la clase controladora.

En el paquete org.desarrollo.ejemplo1.servicio se tiene la interfaz que me enlaza con el modelo y su implementación así como un localizador del servicio que se encarga de obtener una sesión y cargar el bean de la implementación del modelo.

En el paquete org.desarrollo.ejemplo1.modelo se tiene la clase modelo con su mapeo a hibernate en este caso usando un fichero de configuración y no anotaciones como habíamos visto hasta ahora.

En el paquete org.desarrollo.ejemplo1.dao tengo la implementación del DAO genérico con todo el código de acceso a los datos que puede ser reutilizable.

La interfaz de la aplicación refleja las acciones de caso de uso típico CRUD:

clip_image004

Pueden usar el editor gráfico de ZK como se explica en esta entrada para que puedan visualizar la UI.

Como pueden ver tiene operaciones para:

· adicionar una persona,

· actualizar los datos a partir de la selección de la persona en el listado,

· buscar una persona a partir de uno de sus datos,

· borrar una persona previa selección de la misma en el listado.

La interfaz se diseña en un XML que es el formato usado por ZK para representar sus componentes UI (user interface) o Interfaz de Usuario en español.

La pueden ver aquí:

<pre class="brush:xml;">

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>
<window id="win" apply="org.desarrollo.ejemplo1.web.PersonasController" width="1024px" title="gestion de datos" border="normal">

<groupbox>
<caption label="Operaciones CRUD:" width="580px" />
<label id="label1" value="sdsd"/>
<grid>
<columns sizable="true">
<column width="100px"/>
<column width="370px"/>
</columns>
<rows>
<row>
<label value="Nombre:"/>
<textbox id="nombre" value="@{win$composer.current.nombre}" width="350px"/>
</row>
<row>
<label value="1er Apellido:"/>
<textbox id="apellido1" value="@{win$composer.current.apellido1}" width="350px"/>
</row>
<row>
<label value="2do Apellido:"/>
<textbox id="apellido2" value="@{win$composer.current.apellido2}" width="350px"/>
</row>
</rows>
</grid>
<button id="add" label="Adicionar" />
<button id="update" label="Actualizar" />
<button id="search" label="Buscar" />
<button id="delete" label="Borrar" />
</groupbox>
<listbox id="box" multiple="true" selectedItem="@{win$composer.current}" emptyMessage="No hay personas a mostrar">
<listhead>
<listheader label="Nombre:"/>
<listheader label="1er Apellido:"/>
<listheader label="2do Apellido:"/>
</listhead>
<template name="model">
<listitem width="680px">
<listcell label="${each.nombre}" />
<listcell label="${each.apellido1}" />
<listcell label="${each.apellido2}" />
</listitem>
</template>
</listbox>
</window>
</pre>

Como pueden observar lo primero es definir un grupo donde pondré varios componentes, para eso uso el componente “groupbox”.

Dentro de este componente pongo un “grid” que me permite tal como si usara un listbox ubicar columnas (columns) y filas (rows) para mostrar la primera parte de la UI.

Luego pongo una serie de botones usando el componente “button”.

Al salir del “groupbox” utilizo otro componente para mostrar el listado de las personas, que representan las tuplas en la BD, se trata de “listbox” lo más importante de este componente es el uso de otro componente dentro que se llama “template” y es el que me permite visualizar automáticamente los resultados en función de las acciones sobre la vista y la respuesta de la controladora.

NOTA: es importante que se fijen que todos los componentes tienen un id que me permite referenciarlos en la clase controladora.

Los principales atributos de la clase controladora reflejan los componentes en la UI, como pueden ver en la siguiente imagen.

clip_image005

Como ven uso una anotación Wire para obtener los componentes con esos nombres en la UI.

Igual uso la anotación @Listen para los métodos que se enlazan con los botones de la UI.

clip_image007

Vean como utilizo el evento onClick sobre el componente para relacionarlo con la operación en la clase controladora. Es como si dijera: cada vez que se genere el evento onClick sobre el componente “update” se debe llamar al método update.

Lo demás es muy típico del trabajo con Spring e Hibernate así que les dejo el código fuente  del proyecto para que lo compilen con Maven y lo desplieguen en el servidor de su preferencia.

La tabla que se usó es realmente sencilla y este es su DDL:

CREATE TABLE public.persona (

id BIGINT NOT NULL,

nombre VARCHAR NOT NULL,

apellido1 VARCHAR NOT NULL,

apellido2 VARCHAR NOT NULL

) WITHOUT OIDS;

Para crear el .war de esta aplicación deben pararse en la raíz del proyecto, suponiendo que tengan Maven ya instalado y configurado.

Bastan con ejecutar este comando “mvn clean package”, verán cómo se descargan todas las dependencias del proyecto, se compila, se ejecutan las pruebas, en este caso no hay, y en la carpeta target del proyecto se les creará un .war que deben desplegar en un servidor como tomcat y listo.



.
{ Leer Más }


jueves, 23 de mayo de 2013

Arquitectura genérica para el desarrollo de aplicaciones empresariales.

En varias entradas del blog hemos abordado temas que tienen que ver con la persistencia de los datos en almacenes relacionales y hemos visto el uso de diferentes tecnologías y enfoques para resolver el tema de la persistencia.

Que se toquen estos temas desde lo básico a lo más usado actualmente no es un hecho casual si no que forma parte de una estrategia de ir tocando todos los puntos que forman parte de una arquitectura genérica que se puede usar para el desarrollo de aplicaciones empresariales.

Digo arquitectura genérica primero porque es ampliamente usada por diferentes empresas de desarrollo de software y segundo porque a partir de ella se pueden obtener múltiples variaciones particulares en función del dominio del negocio que se ataque.

Por allá por el 2010 en el sitio de adictos al trabajo sacaron una propuesta de arquitectura que hasta la fecha la considero bastante adecuada para desarrollos basados en JAVA. La pueden ver en esta entrada.

clip_image001

Fig.1. Arquitectura propuesta por Autentia.

En la entrada donde se publica se hace un análisis muy bueno de cada componente y de posibles variantes que existían en la fecha de publicación.

En ese sentido creo que hasta el día de hoy no cambiaría casi que ninguno de los componentes con sus excepciones claro:

En el tema de los servicios web y soluciones de integración e interoperabilidad se ha avanzado bastante por lo que sustituiría los siguientes elementos:

o BPM: ellos proponen JBPM o Intalio. Yo pondría algo como Bonita, Activiti o una herramienta que va surgiendo ahora y es el Bussiness Process Server de WSO2.

o jUDDI: pondría otra herramienta de WSO2, el Governance Registry o GREG. Que expone una UDDIv3 pero que además implementa el WS-Discovery.

o OpenESB: lo cambiaría sin problemas por el ESB de WSO2.

o Servicios Web: siguiendo con la tónica usaría el Application Server de WSO2 más el conjunto de herramientas que necesite para el desarrollo y despliegue de servicios web.

o Subversion: lo cambiaría por Mercurial o por Git.

o En la capa de presentación es donde más debate podría haber. Aun estas tecnologías tienen su fuerza aunque están surgiendo soluciones como Vaadin y ZK que tienen sus pros y sus contras, y a las cuales dedicaré otras entradas.

La capa de persistencia es obvio que la mantendría. Hasta el momento Hibernate como implementación del estándar JPA sigue siendo la mejor solución.

El uso de Spring para la capa de lógica de negocio es evidente que sigue siendo un “top priority”.

IReport lo continuaría seguro, con JasperReport como librería para generar los reportes.

El tema de integración continua es otro de los fuertes de esta propuesta que se sigue manteniendo: el uso de Maven, ya lo hemos tocado en este blog, Hudson que actualmente es Jenkins junto con Sonar son las herramientas básicas para la integración continua.

En el caso de la herramienta para portales no podría estar más de acuerdo. Liferay sigue de líder en este tema, junto con Alfresco en la gestión de contenidos. Y claro en el Business Intelligence la suite de Pentaho llegó para quedarse. Por ultimo como plataforma de aprendizaje y e-learning moodle es la elección por defecto. Ah y claro en las ETL sugieren a Talend, esa si se las debo pues no he trabajado en esta tecnología.

{ Leer Más }


sábado, 18 de mayo de 2013

Introducción a los servicios web con Spring y Apache CXF.

En esta primera entrega de la serie de servicios web con Spring veremos un ejemplo bastante sencillo de cómo usar Maven para crear y gestionar un proyecto de una aplicación web que expone un servicio y lo prueba internamente. La prueba externa la realizaremos usando la herramienta SOAPUI.

Para esta entrada hice uso de un tutorial que pueden encontrar en este blog: http://pfelitti87.blogspot.com/ realmente me pareció bastante sencillo y que funciona sin mucha modificación. Luego lo iremos incrementando con más elementos en otras entradas hasta tener un servicio web completamente funciona. En esta entrada solo quiero mostrarles cómo funciona lo básico.

Lo primero es tener un IDE de desarrollo, el eclipse STS de Spring en mí caso que ya viene con un plugin para Maven instalado, y crear un proyecto de Maven con el arquetipo para aplicaciones web.

Luego modificamos el pom del proyecto para que quede así:

&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

&lt;modelVersion>4.0.0&lt;/modelVersion>

&lt;groupId>com.maven.test&lt;/groupId>

&lt;artifactId>Spring-WS-CXF&lt;/artifactId>

&lt;packaging>war&lt;/packaging>

&lt;version>0.0.1-SNAPSHOT&lt;/version>

&lt;name>Spring-WS-CXF Maven Webapp&lt;/name>

&lt;url>http://maven.apache.org&lt;/url>

&lt;dependencies>

&lt;!-- Dependencias de Spring -->

&lt;dependency>

&lt;groupId>org.springframework&lt;/groupId>

&lt;artifactId>spring-web&lt;/artifactId>

&lt;version>3.2.2.RELEASE&lt;/version>

&lt;scope>compile&lt;/scope>

&lt;/dependency>

&lt;dependency>

&lt;groupId>org.springframework&lt;/groupId>

&lt;artifactId>spring-context&lt;/artifactId>

&lt;version>3.2.2.RELEASE&lt;/version>

&lt;scope>compile&lt;/scope>

&lt;/dependency>

&lt;!-- Dependencias de Apache CXF para servicios web -->

&lt;dependency>

&lt;groupId>org.apache.cxf&lt;/groupId>

&lt;artifactId>cxf-api&lt;/artifactId>

&lt;version>2.6.0&lt;/version>

&lt;scope>compile&lt;/scope>

&lt;/dependency>

&lt;dependency>

&lt;groupId>org.apache.cxf&lt;/groupId>

&lt;artifactId>cxf-rt-frontend-jaxws&lt;/artifactId>

&lt;version>2.6.0&lt;/version>

&lt;scope>compile&lt;/scope>

&lt;/dependency>

&lt;dependency>

&lt;groupId>org.apache.cxf&lt;/groupId>

&lt;artifactId>cxf-rt-transports-http&lt;/artifactId>

&lt;version>2.6.0&lt;/version>

&lt;scope>compile&lt;/scope>

&lt;/dependency>

&lt;!-- For testing purposes -->

&lt;dependency>

&lt;groupId>org.springframework&lt;/groupId>

&lt;artifactId>spring-test&lt;/artifactId>

&lt;version>3.2.2.RELEASE&lt;/version>

&lt;scope>test&lt;/scope>

&lt;/dependency>

&lt;dependency>

&lt;groupId>junit&lt;/groupId>

&lt;artifactId>junit&lt;/artifactId>

&lt;version>4.11&lt;/version>

&lt;scope>test&lt;/scope>

&lt;/dependency>

&lt;/dependencies>

&lt;build>

&lt;finalName>Spring-WS-CXF&lt;/finalName>

&lt;plugins>

&lt;!-- Con este plugin se puede iniciar jetty ejecutando mvn jetty:run -->

&lt;plugin>

&lt;groupId>org.mortbay.jetty&lt;/groupId>

&lt;artifactId>maven-jetty-plugin&lt;/artifactId>

&lt;version>6.1.26&lt;/version>

&lt;configuration>

&lt;scanIntervalSeconds>3&lt;/scanIntervalSeconds>

&lt;/configuration>

&lt;/plugin>

&lt;plugin>

&lt;groupId>org.apache.maven.plugins&lt;/groupId>

&lt;artifactId>maven-compiler-plugin&lt;/artifactId>

&lt;version>3.0&lt;/version>

&lt;configuration>

&lt;source>1.7&lt;/source>

&lt;target>1.7&lt;/target>

&lt;/configuration>

&lt;/plugin>

&lt;/plugins>

&lt;/build>

&lt;/project>


De esta manera ya tendremos todas las librerías descargadas y listas para ser usadas en el proyecto.

Luego crearemos los paquetes tal y como se muestran en la siguiente imagen, claro ustedes lo pueden modificar a su gusto:

image

Como pueden apreciar tengo una clase interface HelloWordService que tiene lo siguiente:

package org.blog.samples.webservices.Interface;

import javax.jws.WebService;

@SuppressWarnings("restriction")

@WebService

public interface HelloWorldService {

public void sayHello();

}

Vean la anotación @WebService que la uso para indicar que esta clase interface es para un servicio web.

Luego viene su implementación:

package org.blog.samples.webservices.Impl;

import org.blog.samples.webservices.Interface.HelloWorldService;

import javax.jws.WebService;

@SuppressWarnings("restriction")

@WebService(endpointInterface = "org.blog.samples.webservices.Interface.HelloWorldService")

public class HelloWorldServiceBean implements HelloWorldService {

public void sayHello() {

System.out.println("Hello World!!!");

}

}

En este caso la anotación tiene un parámetro que establece la interface del endpoint apuntando a la interfaz anterior.

Como pueden ver la implementación es bastante sencilla, pues no es mi intención en esta entrada llegar a una implementación real del servicio, solo los componentes necesarios que lo conforman.

Ahora creamos el fichero service-definition-beans.xml que lo pondremos en src/main/resources y que contendrá lo siguiente:

&lt;?xml version="1.0" encoding="UTF-8"?>

&lt;beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

&lt;bean id="helloWorldService" class="org.blog.samples.webservices.Impl.HelloWorldServiceBean" />

&lt;/beans>

Como pueden ver solo se está creando un bean normal en este fichero.

Ahora vamos a especificar el endpoint del servicio a través del siguiente fichero de configuración webservice-definition-beans.xml que se ubica en la carpeta WEB-INF de la aplicación web:

&lt;?xml version="1.0" encoding="UTF-8"?>

&lt;beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

&lt;import resource="classpath:service-definition-beans.xml" />

&lt;jaxws:endpoint id="helloWorld" implementor="#helloWorldService"

address="/HelloWorld" />

&lt;/beans>

Aquí estamos creando un endpoint que tiene como implementador el bean que creamos en el fichero de configuracion anterior y estamos diciendo que su dirección relativa a la aplicación será /HelloWorld. Luego veremos qué es esto.

Ahora nos encargamos de como probar el servicio para que en caso de que haya un fallo la aplicación no sea creada, o pensando en positivo para crear la aplicación siempre que el servicio pase la prueba.

En este caso la prueba es un poco falsa pues poco hay que probar. Esta es la clase correspondiente:

package org.blog.samples.webservices.test;

import org.blog.samples.webservices.Interface.HelloWorldService;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = { "/service-definition-beans-test.xml" })

public class HelloWorldServiceTest {

@Autowired

@Qualifier("helloWorldClient")

private HelloWorldService helloWorldClient;

@Test

public void helloWorldClientTest() {

helloWorldClient.sayHello();

}

}

Y el fichero service-definition-beans-test.xml es este:

&lt;?xml version="1.0" encoding="UTF-8"?>

&lt;beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

&lt;jaxws:client id="helloWorldClient"

serviceClass="org.blog.samples.webservices.Interface.HelloWorldService"

address="http://localhost:8080/Spring-WS-CXF/HelloWorld" />

&lt;/beans>

Deben ubicarlo en el directorio resources de la aplicación web.

Como ven solo corremos una prueba que utiliza el bean del servicio anteriormente creado, mediante la anotación @Autowired y llama a la operación sayHello.

Si queremos ya podemos construir el war de nuestra aplicación y para eso lanzamos el comando Maven: mvn clean install aunque si ya estamos en el STS damos clic derecho encima del proyecto/Run AS/Maven build y ponemos algo como lo que se muestra en la siguiente imagen. Fíjense que hemos marcado que no se ejecuten las pruebas porque se intentará conectarse a la aplicación web que aún no está corriendo. Si lo quieren hacer desde la línea de comando pueden tirar lo siguiente: mvn clean install -Dmaven.test.skip=true

image

Ahora viene lo interesante porque podemos desde Maven ejecutar un servidor ligero para aplicaciones web y levantar automáticamente nuestra aplicación. Esto es gracias al plugin de Maven “maven-jetty-plugin”

Para eso hacemos lo siguiente:

image

O mvn jetty:run desde la línea de comando.

Esto nos levantará el servidor de jetty y desplegará nuestra aplicación así que ya podemos ejecutar nuestras pruebas a través del siguiente comando: “mvn test” o desde el eclipse, como gusten. Podrán ver la siguiente salida:

-------------------------------------------------------

T E S T S

-------------------------------------------------------

Running org.blog.samples.webservices.test.HelloWorldServiceTest

may 13, 2013 10:41:07 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions

Información: Loading XML bean definitions from class path resource [service-definition-beans-test.xml]

may 13, 2013 10:41:08 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh

Información: Refreshing org.springframework.context.support.GenericApplicationContext@134fd233: startup date [Mon May 13 22:41:08 EDT 2013]; root of context hierarchy

may 13, 2013 10:41:08 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons

Información: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@10554f8b: defining beans [helloWorldClient.proxyFactory,helloWorldClient,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy

may 13, 2013 10:41:08 PM org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass

Información: Creating Service {http://Interface.webservices.samples.blog.org/}HelloWorldServiceService from class org.blog.samples.webservices.Interface.HelloWorldService

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.243 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 6.438s

[INFO] Finished at: Mon May 13 22:41:10 EDT 2013

[INFO] Final Memory: 12M/169M

[INFO] ------------------------------------------------------------------------

Si quieren probar la aplicación pueden ir a: http://localhost:8080/Spring-WS-CXF/

Y verán esto:

image

Si pinchan en el enlace podrán ver el WSDL del servicio que tiene el siguiente aspecto:

&lt;?xml version='1.0' encoding='UTF-8'?>

&lt;wsdl:definitions name="HelloWorldServiceBeanService" targetNamespace="http://Impl.webservices.samples.blog.org/" xmlns:ns1="http://Interface.webservices.samples.blog.org/" xmlns:ns2="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Impl.webservices.samples.blog.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

&lt;wsdl:import location="http://localhost:8080/Spring-WS-CXF/HelloWorld?wsdl=HelloWorldService.wsdl" namespace="http://Interface.webservices.samples.blog.org/">

&lt;/wsdl:import>

&lt;wsdl:binding name="HelloWorldServiceBeanServiceSoapBinding" type="ns1:HelloWorldService">

&lt;soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

&lt;wsdl:operation name="sayHello">

&lt;soap:operation soapAction="" style="document"/>

&lt;wsdl:input name="sayHello">

&lt;soap:body use="literal"/>

&lt;/wsdl:input>

&lt;wsdl:output name="sayHelloResponse">

&lt;soap:body use="literal"/>

&lt;/wsdl:output>

&lt;/wsdl:operation>

&lt;/wsdl:binding>

&lt;wsdl:service name="HelloWorldServiceBeanService">

&lt;wsdl:port binding="tns:HelloWorldServiceBeanServiceSoapBinding" name="HelloWorldServiceBeanPort">

&lt;soap:address location="http://localhost:8080/Spring-WS-CXF/HelloWorld"/>

&lt;/wsdl:port>

&lt;/wsdl:service>

&lt;/wsdl:definitions>

De esta manera sabemos que el servicio está corriendo dentro de la aplicación desplegada con jetty.

Por último algo que siempre hago es probar el servicio, para eso uso el SOAPUI, pero esto lo dejaré para otra entrada para no extenderme más.

Quedo al tanto de sus comentarios.

{ Leer Más }


miércoles, 15 de mayo de 2013

Sustituyendo la capa de persistencia de Spring JDBC por Spring + Hibernate.

Hola a todos.

En esta entrada llevaremos la serie Introducción a Spring JDBC como solución a los problemas de uso e JDBC en proyectos productivos, que hasta la última entrega iba por la entrada 3 a un nuevo nivel sustituyendo la capa de persistencia de Spring JDBC por la combinación de Spring + Hibernate3 y anotaciones propias de Hibernate

La entrada está un poco extensa porque incluiré el código necesario para explicar los cambios.

El diagrama que representa lo que queremos hacer es el siguiente:

clip_image002

Para comenzar haremos una copia del proyecto anterior cambiándole el nombre en el mismo IDE STS de Spring.

clip_image003

Luego comenzaremos a trabajar con las interfaces. Para este caso implementaremos una interfaz genérica que nos servirá para todos los futuros DAO que tengamos que implementar de cualquier entidad del negocio.

Esta interfaz se verá así:

package org.ejemplos.blog.spring.Interfaces;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.hibernate.criterion.DetachedCriteria;

public interface BaseDao&lt;T extends Serializable, E> {
public void deleteAll(Collection&lt;T> instances) throws Exception;

public int bulkUpdate(String query) throws Exception;

public E save(T instance) throws Exception;

public void saveOrUpdateAll(Collection&lt;T> instances) throws Exception;

public void saveOrUpdate(T instance) throws Exception;

public void persist(T transientInstance) throws Exception;

public void attachDirty(T instance) throws Exception;

public void attachClean(T instance) throws Exception;

public void delete(T persistentInstance) throws Exception;

public List&lt;T> findByExample(T instance) throws Exception;

public List&lt;T> findByQuery(String query) throws Exception;

public List&lt;Map&lt;String, Object>> findMapByQuery(String queryString)
throws Exception;

public List&lt;T> findByCriteria(DetachedCriteria criteria) throws Exception;

public T merge(T detachedInstance) throws Exception;

public List&lt;T> findAll() throws Exception;

public T findById(E id) throws Exception;
}

 


Con ayuda de la genericidad no necesitamos especificar el tipo de clase que usará la implementación de esta interface. Luego veremos como se usa y la utilidad que tiene. Solo decir que la interface está parametrizada por una clase genérica, T, y una clave primaria que a su vez es serializable. Esto nos permite que independientemente del tipo de nuestra clase podamos acceder de forma segura a sus métodos.

Estos métodos identificados en la interface nos permiten realizar casi cualquier operación sobre las entidades, es por eso que teniéndolos ya especificamos pues se nos hace más fácil la implementación.

El otro cambio que debemos realizar es en el pom.xml del proyecto para que Maven nos cargue las nuevas dependencias de spring + hibernate, quedaría de la siguiente manera:

&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
&lt;modelVersion>4.0.0&lt;/modelVersion>

&lt;groupId>cu.casa.jorge.spring&lt;/groupId>
&lt;artifactId>ejemplo-dao-spring-hibernate&lt;/artifactId>
&lt;version>1.0-SNAPSHOT&lt;/version>
&lt;packaging>jar&lt;/packaging>

&lt;name>ejemplo-dao-spring-hibernate&lt;/name>
&lt;url>http://maven.apache.org&lt;/url>

&lt;properties>
&lt;project.build.sourceEncoding>UTF-8&lt;/project.build.sourceEncoding>
&lt;org.springframework.version>3.2.2.RELEASE&lt;/org.springframework.version>
&lt;org.spring-test.version>3.2.0.RELEASE&lt;/org.spring-test.version>
&lt;postgresql.version>9.1-901.jdbc4&lt;/postgresql.version>
&lt;junit.version>4.11&lt;/junit.version>
&lt;commons-dbcp.version>1.2.2&lt;/commons-dbcp.version>
&lt;hibernate.version>3.5.0-Final&lt;/hibernate.version>
&lt;/properties>

&lt;dependencies>
&lt;dependency>
&lt;groupId>junit&lt;/groupId>
&lt;artifactId>junit&lt;/artifactId>
&lt;version>${junit.version}&lt;/version>
&lt;scope>test&lt;/scope>
&lt;/dependency>
&lt;dependency>
&lt;groupId>org.springframework&lt;/groupId>
&lt;artifactId>spring-orm&lt;/artifactId>
&lt;version>${org.springframework.version}&lt;/version>
&lt;/dependency>
&lt;dependency>
&lt;groupId>org.hibernate&lt;/groupId>
&lt;artifactId>hibernate-core&lt;/artifactId>
&lt;version>${hibernate.version}&lt;/version>
&lt;/dependency>
&lt;dependency>
&lt;groupId>org.springframework&lt;/groupId>
&lt;artifactId>spring-test&lt;/artifactId>
&lt;version>${org.spring-test.version}&lt;/version>
&lt;/dependency>
&lt;dependency>
&lt;groupId>org.springframework&lt;/groupId>
&lt;artifactId>spring-beans&lt;/artifactId>
&lt;version>${org.springframework.version}&lt;/version>
&lt;/dependency>
&lt;dependency>
&lt;groupId>postgresql&lt;/groupId>
&lt;artifactId>postgresql&lt;/artifactId>
&lt;version>${postgresql.version}&lt;/version>
&lt;/dependency>
&lt;dependency>
&lt;groupId>commons-dbcp&lt;/groupId>
&lt;artifactId>commons-dbcp&lt;/artifactId>
&lt;version>${commons-dbcp.version}&lt;/version>
&lt;/dependency>
&lt;dependency>
&lt;groupId>org.hibernate&lt;/groupId>
&lt;artifactId>hibernate-annotations&lt;/artifactId>
&lt;version>${hibernate.version}&lt;/version>
&lt;type>jar&lt;/type>
&lt;scope>compile&lt;/scope>
&lt;/dependency>
&lt;dependency>
&lt;groupId>org.slf4j&lt;/groupId>
&lt;artifactId>slf4j-api&lt;/artifactId>
&lt;version>1.6.1&lt;/version>
&lt;type>jar&lt;/type>
&lt;scope>compile&lt;/scope>
&lt;/dependency>
&lt;dependency>
&lt;groupId>javassist&lt;/groupId>
&lt;artifactId>javassist&lt;/artifactId>
&lt;version>3.12.1.GA&lt;/version>
&lt;type>jar&lt;/type>
&lt;scope>compile&lt;/scope>
&lt;/dependency>
&lt;dependency>
&lt;groupId>javax.validation&lt;/groupId>
&lt;artifactId>validation-api&lt;/artifactId>
&lt;version>1.0.0.GA&lt;/version>
&lt;scope>compile&lt;/scope>
&lt;/dependency>
&lt;dependency>
&lt;groupId>org.hibernate&lt;/groupId>
&lt;artifactId>hibernate-validator&lt;/artifactId>
&lt;version>4.2.0.Final&lt;/version>
&lt;scope>runtime&lt;/scope>
&lt;/dependency>
&lt;dependency>
&lt;groupId>org.hibernate&lt;/groupId>
&lt;artifactId>hibernate-jpamodelgen&lt;/artifactId>
&lt;version>1.0.0.Final&lt;/version>
&lt;type>jar&lt;/type>
&lt;scope>compile&lt;/scope>
&lt;/dependency>
&lt;/dependencies>
&lt;build>
&lt;plugins>

&lt;plugin>
&lt;artifactId>maven-surefire-plugin&lt;/artifactId>
&lt;version>2.4.3&lt;/version>
&lt;executions>
&lt;execution>
&lt;id>default-test&lt;/id>
&lt;phase>test&lt;/phase>
&lt;goals>
&lt;goal>test&lt;/goal>
&lt;/goals>
&lt;/execution>
&lt;/executions>
&lt;/plugin>
&lt;/plugins>

&lt;/build>
&lt;/project>

 


Seguimos con los cambios y entonces crearemos la interfaz para el futuro DAO que implementaremos, para seguir la idea de las entradas anteriores el DAO se usará con la entidad Capitulo así que la interface ICapitulo quedará así:

package com.test.maven.Interfaces;

import java.util.List;
import com.test.maven.Dominio.Capitulo;

public interface ICapitulo extends BaseDao&lt;Capitulo, String> {

}

 


Como ven es un cambio significativo, ya aquí no tenemos que declarar nuevos métodos pues los extendemos de BaseDao. Es importante señalar que podríamos haber seguido con la interface inicial, pero creo que esta es mucho mejor y permitirá implementar más funcionalidades sin tener que realizarle modificaciones en un futuro.

Fíjense como cuando extendemos de BaseDao le especificamos la clase que se le debe pasar “Capitulo” y que el ID será de tipo String.

Seguimos con los cambios y nos vamos entonces a la clase entidad Capitulo, porque por la implementación que tiene del ejemplo anterior nos da un error en la interface que acabamos de crear.

Lo primero es hacer que la clase implemente la interface Serializable y luego agregarle anotaciones a la misma clase y a sus atributos. Quedando entonces de la siguiente manera:

package com.test.maven.Dominio;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity(name = "Capitulo")
@Table(name = "capitulo")
public class Capitulo implements Serializable {

private static final long serialVersionUID = 7907514315633607867L;
@Id
@Column(name = "idx", length = 100)
private String indice;

@Column(name = "titulo", length = 100, nullable = false)
private String titulo;

@Column(name = "numero_paginas", length = 100, nullable = false)
private int numero_paginas;

@Column(name = "isbn_libro", length = 100, nullable = false)
private String isbn_libro;
/*
* Aquí seguirían los métodos get y set que no cambian en nada
*/

 


Las anotaciones que hemos usado son las siguientes:


  • @Entity: indica que la clase en una entidad.
  • @Table: indica que tabla estamos mapeando en la clase.
  • @Id: indica la propiedad que actúa como identificador.
  • @Column: indica contra que columna de la tabla se mapea una propiedad.

Ahora comenzaremos con la implementación. Para ello implementaremos una clase que extiende de Serializable, de HibernateDaoSupport (un template para hibernate) y que implementa la interface BaseDao. Esta clase la reutilizo siempre entre proyectos a no ser que haya métodos que deban ser implementados de una forma particular. Por lo que la copio de un proyecto anterior. :-D

Quedaría como sigue:

package com.test.maven.DAOImpl;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import com.test.maven.Interfaces.BaseDao;

import org.hibernate.LockMode;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public abstract class BaseDaoHibernate&lt;T extends Serializable, E> extends
HibernateDaoSupport implements BaseDao&lt;T, E> {
public void deleteAll(final Collection&lt;T> instances) throws Exception {
try {
getHibernateTemplate().deleteAll(instances);
} catch (final Exception e) {
throw e;
}
}

public int bulkUpdate(final String query) throws Exception {
try {
return getHibernateTemplate().bulkUpdate(query);
} catch (final Exception e) {
throw e;
}
}

@SuppressWarnings("unchecked")
public E save(final T instance) throws Exception {
try {
return (E) getHibernateTemplate().save(instance);
} catch (final Exception e) {
throw e;
}
}

public void saveOrUpdateAll(final Collection&lt;T> instances) throws Exception {
try {
getHibernateTemplate().saveOrUpdateAll(instances);
} catch (final Exception e) {
throw e;
}
}

public void saveOrUpdate(final T instance) throws Exception {
try {
getHibernateTemplate().saveOrUpdate(instance);
} catch (final Exception e) {
throw e;
}
}

public void persist(final T transientInstance) throws Exception {
try {
getHibernateTemplate().persist(transientInstance);
} catch (final Exception e) {
throw e;
}
}

public void attachDirty(final T instance) throws Exception {
try {
getHibernateTemplate().saveOrUpdate(instance);
} catch (final Exception e) {
throw e;
}
}

public void attachClean(final T instance) throws Exception {
try {
getHibernateTemplate().lock(instance, LockMode.NONE);
} catch (final Exception e) {
throw e;
}
}

public void delete(final T persistentInstance) throws Exception {
try {
getHibernateTemplate().delete(persistentInstance);
} catch (final Exception e) {
throw e;
}
}

public T merge(final T detachedInstance) throws Exception {
try {
final T result = getHibernateTemplate().merge(detachedInstance);
return result;
} catch (final Exception e) {
throw e;
}
}

@SuppressWarnings("unchecked")
public List&lt;T> findByExample(final T instance) throws Exception {
try {
final List&lt;T> results = getHibernateTemplate().findByExample(
instance);
return results;
} catch (final Exception e) {
throw e;
}
}

@SuppressWarnings("unchecked")
public List&lt;T> findByQuery(final String queryString) throws Exception {
try {
final List&lt;T> results = getHibernateTemplate().find(queryString);
return results;
} catch (final Exception e) {
throw e;
}
}

@SuppressWarnings("unchecked")
public List&lt;Map&lt;String, Object>> findMapByQuery(final String queryString)
throws Exception {
try {
final List&lt;Map&lt;String, Object>> results = getHibernateTemplate()
.find(queryString);
return results;
} catch (final Exception e) {
throw e;
}
}

@SuppressWarnings("unchecked")
public List&lt;T> findByCriteria(final DetachedCriteria criteria)
throws Exception {
try {
return getHibernateTemplate().findByCriteria(criteria);
} catch (final Exception e) {
throw e;
}
}

public abstract List&lt;T> findAll() throws Exception;

public abstract T findById(E id) throws Exception;
}

 


Como puede ver casi todos los métodos lo que hacen es llamar al método correspondiente de getHibernateTemplate, que es el template que estamos usando, con excepción de los 2 últimos métodos que vamos a implementar. Esto es a manera de ejemplo porque podríamos brindar la misma funcionalidad con los métodos que ya tenemos.

La implementación del DAO de Capitulo quedaría como sigue:

package com.test.maven.DAOImpl;

import java.util.List;

import com.test.maven.Dominio.Capitulo;
import com.test.maven.Interfaces.ICapitulo;

public class CapituloDAO extends BaseDaoHibernate&lt;Capitulo , String> implements ICapitulo{

@Override
public List&lt;Capitulo> findAll() throws Exception {

return getHibernateTemplate().loadAll(Capitulo.class);

}

@Override
public Capitulo findById(String id) throws Exception {
Capitulo capitulo = getHibernateTemplate().get(Capitulo.class, id);
return capitulo;
}

}

 


Y llegados aquí es importante decir que esta es la clase que tendremos que implementar realmente para el resto de las entidades en nuestra aplicación, ya que casi todo lo demás es reutilizable. Mediante la genericidad, especificamos que nuestro DAO es sobre la entidad Capitulo y su id es de tipo String

Como ven solo tengo que implementar los métodos que no implementé en BaseDaoHibernate.

Siguiendo con los cambios vamos a modificar el fichero de configuración de spring que usaremos para las pruebas quedando como sigue:

&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">


&lt;context:component-scan base-package="com.test.maven" />
&lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
&lt;property name="driverClassName" value="org.postgresql.Driver" />
&lt;property name="url" value="jdbc:postgresql://localhost:5432/BDEjemplo" />
&lt;property name="username" value="postgres" />
&lt;property name="password" value="descarga" />
&lt;/bean>


&lt;bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
&lt;property name="dataSource" ref="dataSource" />
&lt;property name="packagesToScan" value="com.test.maven" />
&lt;property name="hibernateProperties">
&lt;props>
&lt;prop key="hibernate.show_sql">true&lt;/prop>
&lt;prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect&lt;/prop>
&lt;prop key="hibernate.hbm2ddl.auto">update&lt;/prop>
&lt;/props>
&lt;/property>
&lt;/bean>

&lt;bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
&lt;property name="sessionFactory" ref="sessionFactory" />
&lt;/bean>
&lt;bean id="CapituloDAO" class="com.test.maven.DAOImpl.CapituloDAO">
&lt;property name="hibernateTemplate" ref="hibernateTemplate" />
&lt;/bean>

&lt;/beans>

 


Lo importante aquí es la creación del bean sessionFactory que será de tipo AnnotationSessionFactoryBean porque estamos usando anotaciones mediante JPA donde indicamos el bean que nos cargará la fuente de datos usando el atributo ref que nos permite referenciar otros objetos dentro del mismo contexto, los paquetes a escanear y de esa manera no tendremos que indicar las clases a buscar, y le pasamos varias propiedades al hibernate para que nos muestre las consultas que se ejecuten, le especificamos el dialecto, algo importante para que las consultas se construyan bien porque como habrán visto no hemos escrito ninguna consulta, y finalmente especificamos que la estructura de la base de datos se actualice ante cualquier cambio de nuestras clases entidad. El otro bean que creamos es el hibernateTemplate al que le inyectamos el sessionFactory anterior y por último el bean CapituloDAO al que le inyectamos el bean anterior y listo.

Recuerden que en otra entrada explicaré el mecanismo detrás de todas estas cosas nuevas, de momento basta saber que funcionan así como están. :-D

Por último nos vamos a la clase de prueba que queda como sigue:

package com.test.maven;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;

import com.test.maven.DAOImpl.CapituloDAO;
import com.test.maven.Dominio.Capitulo;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("spring-context.xml")
public class CapituloDAOTest {
@Autowired
private CapituloDAO capituloDAO;

public void setCapituloDao(CapituloDAO capituloDao) {
this.capituloDAO = capituloDao;
}

@Before
public void setUp() throws Exception {
}

@Test
public void testFindCapitulobyID() throws Exception {

Assert.isInstanceOf(Capitulo.class, capituloDAO.findById("23"));

}
@Test
public void testRetornaCapitulo() throws Exception{

Capitulo capitulo = capituloDAO.findById("23");
Assert.notNull(capitulo);
}
@Test
public void testListadoCapitulos() throws Exception{

Assert.notEmpty(capituloDAO.findAll());
}
}

 


Cuando corremos esta clase con mvn test o en el STS dando clic derecho en el proyecto Run As/ Maven test, veremos lo siguiente en la consola:

-------------------------------------------------------

T E S T S

-------------------------------------------------------

Running com.test.maven.CapituloDAOTest

may 03, 2013 6:43:50 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions

Información: Loading XML bean definitions from class path resource [com/test/maven/spring-context.xml]

may 03, 2013 6:43:50 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh

Información: Refreshing org.springframework.context.support.GenericApplicationContext@2cf0bca1: startup date [Fri May 03 18:43:50 EDT 2013]; root of context hierarchy

may 03, 2013 6:43:50 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons

Información: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@a39e3dd: defining beans [editoraDAO,libroDAO,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,dataSource,sessionFactory,hibernateTemplate,CapituloDAO,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".

SLF4J: Defaulting to no-operation (NOP) logger implementation

SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

may 03, 2013 6:43:51 PM org.springframework.orm.hibernate3.LocalSessionFactoryBean buildSessionFactory

Información: Building new Hibernate SessionFactory

Hibernate: select capitulo0_.idx as idx0_0_, capitulo0_.isbn_libro as isbn2_0_0_, capitulo0_.numero_paginas as numero3_0_0_, capitulo0_.titulo as titulo0_0_ from capitulo capitulo0_ where capitulo0_.idx=?

Hibernate: select capitulo0_.idx as idx0_0_, capitulo0_.isbn_libro as isbn2_0_0_, capitulo0_.numero_paginas as numero3_0_0_, capitulo0_.titulo as titulo0_0_ from capitulo capitulo0_ where capitulo0_.idx=?

Hibernate: select this_.idx as idx0_0_, this_.isbn_libro as isbn2_0_0_, this_.numero_paginas as numero3_0_0_, this_.titulo as titulo0_0_ from capitulo this_

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.521 sec

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

may 03, 2013 6:43:52 PM org.springframework.context.support.AbstractApplicationContext doClose

Información: Closing org.springframework.context.support.GenericApplicationContext@2cf0bca1: startup date [Fri May 03 18:43:50 EDT 2013]; root of context hierarchy

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 5.472s

[INFO] Finished at: Fri May 03 18:43:52 EDT 2013

[INFO] Final Memory: 8M/104M

[INFO] ------------------------------------------------------------------------

Como se ve los 3 test pasaron sin problema. Por lo que con seguridad podemos decir que nuestra implementación está correcta.

Ahora si quisiéramos seguir con este proyecto implementando los restantes DAO podríamos reutilizar casi todo el código que hemos escrito lo que incrementaría notablemente nuestra productividad y todo gracias a la combinación de Spring + Hibernate.

{ Leer Más }


IconIconIcon