Sunday, January 10, 2010

Primeros Pasos con Spring Roo en Spring Source Tool Suite

Este ejemplo de primeros pasos esta hecho con el SpringSource Tool Suite, sin embargo, es posible hacerlo también desde la consola de Roo.

Vamos a crear una pequeña aplicacion de libreta de direcciones para este ejemplo.

Lo primero es crear el proyecto del tipo "Roo Project" con el nombre "PrimerosPasos" (el nombre puede ser de su eleccion solo recuerden que con ese nombre tendrá el contexto web).


Esto crea un proyecto con la estructura:



Para aquellos que usan maven se darán inmediatamente cuenta que es una estructura de un proyecto maven.

Para crear/configurar las cosas en Spring Roo se corren comandos desde la consola Roo, la cual desde el SpringSource Tool Suite se puede ejecutar con click derecho sobre el proyecto luego la opcion Spring Tools -> Open Roo Shell.

Ya en la vista de la consola Roo existe un campo de texto donde tecleamos los comandos que pueden ir creando el código de la aplicación. Si teclean "hint" el mismo Roo les dará pistas sobre que comandos teclear según lo ya creado dentro del proyecto.

Lo primero que hay que configurar el proveedor y la base de datos de la aplicación, y de hecho este es el primer punto que pide Roo crear si teclean "hint".


persistence setup --database MYSQL --provider HIBERNATE


Esto imprime como salida en la consola de roo:


roo> persistence setup --database MYSQL --provider HIBERNATE
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml
Created SRC_MAIN_RESOURCES/META-INF/spring/database.properties
please enter your database details in src/main/resources/database.properties
Managed SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml


Dentro de los archivos que fueron creados esta el "database.properties" en el cual hay que configurar los parámetros para conectarnos a nuestra base de datos en mysql.

Ya configurados los parametros para conectarnos a la base de datos es necesario empezar a crear las entidades de nuestra aplicacion. Dado que nuestra aplicacion sera una libreta de direcciones empezaremos con la entidad "Persona".

Una vez mas podemos teclear "hint" en la consola de roo para que nos ayude.

Para crear una entidad hay que teclear el comando "entity" el cual recibe un argumento obligatorio y es el nombre de la clase de la entidad que vamos a crear.


entity --class com.jabaddon.roo.libretadirecciones.dominio.Persona


Sin embargo el comando "entity" puede recibir mas argumentos los cuales nos puede mostrar la consola de roo si tecleamos "--" y luego CRTL+SPACE.

Una vez ejecutado el comando "entity" esta es la salida en la consola de roo:


roo> entity --class com.jabaddon.roo.libretadirecciones.dominio.Persona
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/dominio
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/dominio/Persona.java
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/dominio/Persona_Roo_Entity.aj
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/dominio/Persona_Roo_ToString.aj
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/dominio/Persona_Roo_Configurable.aj


Notaran que la única clase java creada fue "Persona.java" y que si abren el código solo verán lo siguiente:


@Entity
@RooJavaBean
@RooToString
@RooEntity
public class Persona {
}


Los otros archivos "*.aj" son Aspectos agregados a la clase Persona.

En este punto si volvemos a teclear "hint" en la consola de roo nos dará consejos para crearle atributos a nuestra clase.

Agregaremos el atributo nombre a nuestra clase Persona ejecutando el siguientes comando en la consola:


field string --fieldName nombre



roo> field string --fieldName nombre
Managed SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/dominio/Persona.java
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/dominio/Persona_Roo_JavaBean.aj
Managed SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/dominio/Persona_Roo_ToString.aj


Ok, en este punto del ejemplo me gustaría recalcar algo y para lograrlo primero hay que crear una clase de prueba de la clase Persona con el siguiente código:


package com.jabaddon.roo.libretadirecciones.dominio;

import org.apache.log4j.Logger;
import org.junit.Test;

public class PersonaTest {

private static final Logger LOGGER = Logger.getLogger(PersonaTest.class);

@Test
public void imprimirNombrePersona() {
Persona persona = new Persona();
persona.setNombre("Jimmy");
LOGGER.debug("El nombre es = " + persona.getNombre());
}
}


Lo siguiente es crear un archivo "log4j.propeties" en src/test/resources y configurarlo para que imprima el nivel debug de la siguiente forma: (si quieren pueden copiar el log4j.properties que se genero en src/main/resources/META-INF/spring/log4j.properties, pero hay que cambiarle el nivel a debug).


log4j.rootLogger=debug, consola

log4j.appender.consola=org.apache.log4j.ConsoleAppender
log4j.appender.consola.layout=org.apache.log4j.PatternLayout
log4j.appender.consola.layout.ConversionPattern=%d [%t] %-5p %c - %m%n


Una vez creada la prueba unitaria y el archivo log4j.properties, hay que ejecutar las pruebas del proyecto dando click derecho sobre el archivo pom.xml y ejecutar la opcion "Run As -> Maven Test". Con esto ejecutaremos las pruebas unitarias del proyecto y la salida de ejecutar esta acción es la siguiente (o pueden ejectuar las pruebas corriendo el comando "mvn test" en una consola normal):


...
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.jabaddon.roo.libretadirecciones.dominio.PersonaTest
2010-01-10 21:52:35,441 [main] DEBUG org.springframework.beans.factory.wiring.BeanConfigurerSupport - BeanFactory has not been set on BeanConfigurerSupport: Make sure this configurer runs in a Spring container. Unable to configure bean of type [com.jabaddon.roo.libretadirecciones.dominio.Persona]. Proceeding without injection.
2010-01-10 21:52:35,444 [main] DEBUG com.jabaddon.roo.libretadirecciones.dominio.PersonaTest - El nombre es = Jimmy
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.931 sec

Results :

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


Ok, todo fue bien el nombre Jimmy se imprimió bien. Ahora miremos de nuevo el código de la clase Persona.java:


package com.jabaddon.roo.libretadirecciones.dominio;

import javax.persistence.Entity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.roo.addon.entity.RooEntity;

@Entity
@RooJavaBean
@RooToString
@RooEntity
public class Persona {

private String nombre;
}


Alguien puede explicarme porque al crear la prueba unitaria la clase Persona contenía los métodos setNombre y getNombre si el código java no lo tiene?!??!?!?!. La respuesta son dos palabras: Aspectos y Addons.

Recuerdan que al crear la entidad Persona Spring Roo creo unos archivos .aj? estos son los Aspectos. Vía aspectos y anotaciones Spring Roo agrega funcionalidad a las clases. Estos aspectos agregados por anotaciones a las clases son los llamados "Addons".

Los "Addons" son una característica que propone Spring Roo y es muy interesante ya que así podemos agregar funcionalidad a las clases de acuerdo a las necesidades y circunstancias. En algun post siguiente en el blog veremos mas a detalle acerca de los aspectos y addons de Spring Roo incluso para crear uno propio, por ahora continuemos con el ejemplo.

Ok, nuestra clase Persona ya tienen un atributo y es el nombre. Ahora vamos a agregarle otros atributos como: apellido y numero telefonico con los comandos siguientes:

                            
field string --fieldName apellido
field string --fieldName numeroTelefonico


Ahora crearemos la parte web de la aplicación creando los controllers. Para que roo nos ayude hay que teclean "hint controllers" en la consola de roo.

Para crear un controller que contenga las operaciones clasicas de altas, bajas y modificaciones (CRUD) ejecutamos el comando:


controller scaffold --class com.jabaddon.roo.libretadirecciones.web.PersonaController --entity com.jabaddon.roo.libretadirecciones.dominio.Persona


La salida de la ejecucion de este comando es la siguiente:


roo> controller scaffold --class com.jabaddon.roo.libretadirecciones.web.PersonaController --entity com.jabaddon.roo.libretadirecciones.dominio.Persona
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/web
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/web/PersonaController.java
Created SRC_MAIN_WEBAPP/WEB-INF/spring
Created SRC_MAIN_WEBAPP/WEB-INF/spring/webmvc-config.xml
Created SRC_MAIN_JAVA/com/jabaddon/roo/libretadirecciones/web/PersonaController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP/images
Created SRC_MAIN_WEBAPP/images/nl.png
Created SRC_MAIN_WEBAPP/images/update.png
Created SRC_MAIN_WEBAPP/images/es.png
Created SRC_MAIN_WEBAPP/images/delete.png
Created SRC_MAIN_WEBAPP/images/add.png
Created SRC_MAIN_WEBAPP/images/resultset_previous.png
Created SRC_MAIN_WEBAPP/images/resultset_next.png
Created SRC_MAIN_WEBAPP/images/favicon.ico
Created SRC_MAIN_WEBAPP/images/banner-graphic.png
Created SRC_MAIN_WEBAPP/images/resultset_last.png
Created SRC_MAIN_WEBAPP/images/gb.png
Created SRC_MAIN_WEBAPP/images/springsource-logo.png
Created SRC_MAIN_WEBAPP/images/it.png
Created SRC_MAIN_WEBAPP/images/show.png
Created SRC_MAIN_WEBAPP/images/sv.png
Created SRC_MAIN_WEBAPP/images/list.png
Created SRC_MAIN_WEBAPP/images/resultset_first.png
Created SRC_MAIN_WEBAPP/images/de.png
Created SRC_MAIN_WEBAPP/styles
Created SRC_MAIN_WEBAPP/styles/standard.css
Created SRC_MAIN_WEBAPP/styles/alt.css
Created SRC_MAIN_WEBAPP/WEB-INF/classes
Created SRC_MAIN_WEBAPP/WEB-INF/classes/standard.properties
Created SRC_MAIN_WEBAPP/WEB-INF/classes/alt.properties
Created SRC_MAIN_WEBAPP/WEB-INF/layouts
Created SRC_MAIN_WEBAPP/WEB-INF/layouts/default.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/layouts/layouts.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views
Created SRC_MAIN_WEBAPP/WEB-INF/views/views.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views/resourceNotFound.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/index.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/uncaughtException.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/dataAccessFailure.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/controller-index.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/tags
Created SRC_MAIN_WEBAPP/WEB-INF/tags/language.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/theme.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/pagination.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/i18n
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_sv.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_nl.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_it.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_es.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_de.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Created SRC_MAIN_WEBAPP/WEB-INF/views/persona
Created SRC_MAIN_WEBAPP/WEB-INF/views/persona/list.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/persona/show.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/persona/create.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/persona/update.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/persona/views.xml
Created SRC_MAIN_WEBAPP/WEB-INF/urlrewrite.xml
Created SRC_MAIN_WEBAPP/WEB-INF/web.xml
Managed SRC_MAIN_WEBAPP/WEB-INF/web.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml
Managed ROOT/pom.xml


Como verán, Spring Roo ha creado todos los archivos necesarios para tener una aplicación básica de altas, bajas y modificaciones sobre nuestra entidad Persona.

Para correr la aplicación bien podemos dar click derecho sobre el proyecto de Spring Source Tool Suite y darle "Run As -> Run on Server" o en una consola normal "mvn jetty:run".

Una vez que ha levantado el servidor vayan a la direccion http://localhost:8080/PrimerosPasos y listo!

Notaran que en la base de datos ya existe una tabla llamada "persona" con los atributos iguales a los que tiene nuestra entidad Persona.

NOTA: Yo tuve problemas ejecutando este ejemplo con Java 1.5 en una Mac pero todo corrió bien con Java 1.6.






8 comments:

pepeguicho said...

Hola.

¡Por fin volviste a escribir algo!
Muy buena explicación por cierto. Se ve muy interesante.

Saludos.

pEpE said...

Buen día, una pregunta, al efectuar los pasos descritos se supone que ROO automáticamente crea la BD y las tablas en MySQL? porque hice todo pero no veo que cree nada en MySQL :(

pEpE said...

Me contesto: el problema es que si tenemos que crear antes la BD en MySQL y Roo crea automáticamente las tablas que estan relacionadas a las clases que se crean en Roo.

saludos y gracias por la info de tu Blog.

Unknown said...

Buenas Tardes, Mucho Gusto!!!!. Estoy haciendo los procedimientos paso a paso, Pero después del comando persistence setup --database MYSQL --provider HIBERNATE me están dando problemas de Dependencias:

20/10/10 05:13:20 PM VET: Missing artifact com.mysql.jdbc:com.springsource.com.mysql.jdbc:jar:5.1.6:compile
20/10/10 05:13:20 PM VET: Missing artifact org.antlr:com.springsource.antlr:jar:2.7.6:compile
20/10/10 05:13:20 PM VET: Missing artifact org.jboss.javassist:com.springsource.javassist:jar:3.3.0.ga:compile
20/10/10 05:13:20 PM VET: Missing artifact net.sourceforge.cglib:com.springsource.net.sf.cglib:jar:2.1.3:compile
20/10/10 05:13:20 PM VET: Missing artifact org.objectweb.asm:com.springsource.org.objectweb.asm:jar:1.5.3:compile
20/10/10 05:13:20 PM VET: Missing artifact org.objectweb.asm:com.springsource.org.objectweb.asm.attrs:jar:1.5.3:compile
20/10/10 05:13:20 PM VET: Missing artifact org.hibernate:com.springsource.org.hibernate.ejb:jar:3.3.2.GA:compile
20/10/10 05:13:20 PM VET: Missing artifact org.jboss.util:com.springsource.org.jboss.util:jar:2.0.4.GA:compile
20/10/10 05:13:20 PM VET: Missing artifact edu.oswego.cs.concurrent:com.springsource.edu.oswego.cs.dl.util.concurrent:jar:1.3.4:compile
20/10/10 05:13:20 PM VET: Missing artifact net.sourceforge.ehcache:com.springsource.net.sf.ehcache:jar:1.4.1:compile
20/10/10 05:13:20 PM VET: Missing artifact net.sourceforge.jsr107cache:com.springsource.net.sf.jsr107cache:jar:1.0.0:compile
20/10/10 05:13:20 PM VET: Missing artifact edu.emory.mathcs.backport:com.springsource.edu.emory.mathcs.backport:jar:3.1.0:compile
20/10/10 05:13:20 PM VET: Missing artifact org.slf4j:com.springsource.slf4j.log4j:jar:1.5.6:compile
20/10/10 05:13:20 PM VET: Missing artifact org.slf4j:com.springsource.slf4j.api:jar:1.5.6:compile
20/10/10 05:13:20 PM VET: Missing artifact javax.persistence:com.springsource.javax.persistence:jar:1.0.0:compile
20/10/10 05:13:20 PM VET: Missing artifact org.hibernate:com.springsource.org.hibernate.validator:jar:4.0.0.GA:compile
20/10/10 05:13:20 PM VET: Missing artifact javax.validation:com.springsource.javax.validation:jar:1.0.0.GA:compile
20/10/10 05:13:20 PM VET: Missing artifact javax.transaction:com.springsource.javax.transaction:jar:1.1.0:compile
20/10/10 05:13:20 PM VET: Missing artifact org.apache.commons:com.springsource.org.apache.commons.dbcp:jar:1.2.2.osgi:compile
20/10/10 05:13:20 PM VET: Missing artifact org.apache.commons:com.springsource.org.apache.commons.pool:jar:1.3.0:compile

Y me dice lo Siguiente:

20/10/10 05:13:21 PM VET: Build errors for PrimerosPasos; org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal on project PrimerosPasos: The repository system is offline and the requested artifact is not locally available at /home/ctorrev/.m2/repository/com/mysql/jdbc/com.springsource.com.mysql.jdbc/5.1.6/com.springsource.com.mysql.jdbc-5.1.6.jar
com.mysql.jdbc:com.springsource.com.mysql.jdbc:jar:5.1.6

from the specified remote repositories:
com.springsource.repository.bundles.release (http://repository.springsource.com/maven/bundles/release, releases=true, snapshots=true),
com.springsource.repository.bundles.external (http://repository.springsource.com/maven/bundles/external, releases=true, snapshots=true),
com.springsource.repository.bundles.milestone (http://repository.springsource.com/maven/bundles/milestone, releases=true, snapshots=true),
com.springsource.repository.bundles.snapshot (http://repository.springsource.com/maven/bundles/snapshot, releases=true, snapshots=true),
central (http://repo1.maven.org/maven2, releases=true, snapshots=false)
Path to dependency:
1) com.roo.primerospasos:PrimerosPasos:pom:pom:0.1.0-SNAPSHOT
2) com.mysql.jdbc:com.springsource.com.mysql.jdbc:jar:5.1.6

De antemano muchas Gracias!!!

Rafael Gutiérrez said...

Hola,

Segun veo en tu log dice "The repository system is offline and the requested artifact is not locally available", ya verificaste que maven no este trabajando offline?

Unknown said...

Hola Muchas Gracias por responder!!!. Ya solucioné eso, ahora cuando corro la aplicación me dice:
Estado HTTP 404 - /PrimerosPasos/

type Informe de estado

mensaje /PrimerosPasos/

descripción El recurso requerido (/PrimerosPasos/) no está disponible.
Apache Tomcat/7.0.2

Unknown said...

Buenas Tardes, ya pude configurar todo, corro la Aplicación y abre perfectamente pero cuando voy a agregar una nueva Persona, me dice lo siguiente:

"Recurso Solicitado No Encontrado"

Me pude dar cuenta que se creo la tabla Persona, y le agrego campos adicionales (id, version).

Juanjo said...

Hola, me sucede algo parecido a lo de ctorrev, me aparece el mensaje de "Recurso Solicitado No Encontrado" al momento de tratar de agregar una nueva persona, o de consultar... me podrías decir como solucionar eso porfavor???

De antemano muchas gracias