viernes, 27 de noviembre de 2015

Dao Generico + Spring + JPA 2

Aquí vamos,  a montar un dao genérico, que contenga las siguientes operaciones básicas:
  • ObtenerId: Nos obtiene la entidad asociada a un id.
  • Eliminar: Se encarga de eliminar la entidad que le pasamos.
  • Actualizar: Se encarga de actualizar la entidad que le pasamos.
  • Crear: Se encarga de crear un entidad.
  • Obtener todos:  Nos devuelve todos los registros del sistema.
La idea de un dao generico, es que estas operaciones las hereden todos los dao de nuestro proyecto, sin necesidad de tener que picarlas.
El dao genérico, se compone de una interfaz y una clase que implementa las operaciones.

En el siguiente proyecto podéis encontrar https://github.com/blancoparis-tfc/SpringCrud

Interfaz

Lo primer que tenemos que hacer es definir las operaciones, en una interfaz, en la cual además de las operaciones, vamos a definir en la cabecera de la interfaz, dos tipos genéricos, que van a representar a la entidad con la que vamos a trabajar y el id de la entidad.

Gracias a estos dos genéricos, es lo que va hacer la magia que nos va a permitir que estas operaciones valgan para cualquier de nuestras entidades del proyecto.

package org.dbp.core.dao;

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

public interface GenericDao {

 public E obtenerId(ID id);

 public void eliminar(E entidad);
 
 public void crear(E entidad);
 
 public E actualizar(E entidad);
 
 public List obtenerTodos();
 
}

Clase

Ahora vamos a implementar las operaciones que hemos puesto en el interfaz, en la siguiente clase.

package org.dbp.core.dao.impl;

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

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.dbp.core.dao.GenericDao;
import org.springframework.transaction.annotation.Transactional;

@Transactional(rollbackFor=Exception.class)
public class GenericDaoImpl  implements GenericDao{

 @PersistenceContext private EntityManager em;
 
 private Class clazzE;

 public GenericDaoImpl(Class clazzE) {
  super();
  this.clazzE = clazzE;
 }

 public E obtenerId(ID id){
  return em.find(clazzE, id);
 }

 public void eliminar(E entidad){
  em.remove(entidad);
 }
 
 public void crear(E entidad){
  em.persist(entidad);
 }
 
 public E actualizar(E actualizar){
  return em.merge(actualizar);
 }
 
 public List obtenerTodos(){
  CriteriaBuilder cb=em.getCriteriaBuilder();
  CriteriaQuery criteria=cb.createQuery(clazzE);
  Root from=criteria.from(clazzE);
  TypedQuery query=em.createQuery(criteria.select(from));
  return query.getResultList();
 }

}

Ejemplo

Una vez definido el dao genérico, para ver todo su potencial es ver el uso y poder apreciar el ahorro de código por un lado, y por otro lado y mas importante que ahora estas operaciones las tenemos centralizadas y si el día de mañana queremos cambiarlas o añadir alguna a todas las entidades lo podemos hacer o cambiar la versión del ORM o lo que sea, nos facilitara la vida.

package org.dbp.dao.impl;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.dbp.bom.Usuario;
import org.dbp.core.dao.impl.GenericDaoImpl;
import org.dbp.dao.UsuarioDao;
import org.springframework.stereotype.Repository;

@Repository
public class UsuarioDaoImpl  
 extends GenericDaoImpl 
 implements UsuarioDao{

 @PersistenceContext private EntityManager em;
 
 public UsuarioDaoImpl() {
  super(Usuario.class);
 }
 
 @Override
 public Usuario obtenerLogin(String login){
  return em.createQuery("from Usuario u where u.login = :login",Usuario.class)
  .setParameter("login", login)
  .getSingleResult();
 }
 
}

Test

Para ver el funcionamiento he creado el siguiente test:

package org.dbp.dao;

import static org.junit.Assert.*;

import java.util.List;

import org.dbp.bom.Usuario;
import org.dbp.core.config.TestConfiguracion;
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.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@ContextConfiguration(classes = TestConfiguracion.class)
public class UsuarioDaoTest {

 @Autowired private UsuarioDao usuarioDao;
 
 @Test
 public void testRecuperarTodos(){
  List usuarios=usuarioDao.obtenerTodos();
  assertEquals("Miramos el número de elementos",1,usuarios.size());
 }
 @Test
 public void testObtenerPorId(){
  Usuario usuario=usuarioDao.obtenerId(1L);
  assertEquals("Validamos el ID:",new Long(1L),usuario.getId());
  assertEquals("Validamos el loging","dblanco",usuario.getLogin());
 }

 @Test
 public void testObtenerLogin(){
  Usuario usuario=usuarioDao.obtenerLogin("dblanco");
  assertEquals("Validamos el ID:",new Long(1L),usuario.getId());
  assertEquals("Validamos el loging","dblanco",usuario.getLogin());
 }
}

Conclusión

Yo solo os puedo decir, que en todos los proyectos que hago monto este patrón junto con un servicio desde el año 2007, que lo vi por primera vez.

viernes, 23 de octubre de 2015

Configurar la pagina de login. En Spring security

Uno de los primeros pasos que tenemos que hacer una vez tenemos configurado spring security. Es crear nuestra propia pagina de login.

Creamos la pagina de login:

Lo primero que tenemos que hacer es crear la JSP, que vamos a utilizar como pagina de login.
<c:url value="/" var="contexto" />
<c:url value="/login" var="loginUrl"/>
<head>
 <link href="${contexto}resources/bootstrap/css/bootstrap.min.css" rel="stylesheet">
 <link href="${contexto}resources/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet">
 <link href="${contexto}resources/css/login.css" rel="stylesheet">
</head>
<body>

    <div class="container">
<form action="${loginUrl}" method="post" class="form-signin">   
 <h2 class="form-signin-heading">Login</h2>    

  <label for="username">Usuario</label>
  <input type="text" id="username" name="username" class="form-control"/> 

  <label for="password">Contraseña</label>
  <input type="password" id="password" name="password" class="form-control"/> 

 <input type="hidden"                        
  name="${_csrf.parameterName}"
  value="${_csrf.token}"/>
 <button type="submit" class="btn btn-lg btn-primary btn-block">Conectarse</button>
</div>
</form>

Creamos el mapeo a la pagina de login

Lo siguiente que tenemos que hacer es crear un mapeo a la pagina de login, como en este caso no es necesario crear un controlador, vamos a establecerlo en la configuración de los controladores, como una vista.

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    super.addViewControllers(registry);
    registry.addViewController("/login").setViewName("login");
    registry.setOrder(Ordered.HIGHEST_PRECEDENCE);  
}

Le indicamos a Spring security donde buscar la nueva pagina.

En el post anterior, teníamos puesta la configuración por defecto que es la siguiente:
http
    .authorizeRequests()
        .anyRequest().authenticated()
        .and()
    .formLogin().and()
    .httpBasic();
Ahora lo que vamos hacer es sobrecribir el método de configure y indicar a spring security donde encontrar, la pagina web, en nuestro caso vamos a extender la configuración del formLogin:
  • Indicar donde se encuentra la pagina de login (loginPage)
  • Le damos todos los permisos asociados a loginPage.
@Override
protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.authorizeRequests()    // Le indicamos que la autorizacion va a ser a nivel de request.
        .anyRequest().authenticated()  // Le indicamos que cada solicitud requiere que el usuario de autentique.
        .and()
    .formLogin()    // Configurar el formato de login.
        .loginPage("/login") // aqui le indicamos donde se encuentra la pagina de login.
        .permitAll();// Aqui le indicamos que la pagina de login es publica.*/
}

Maquetar la pagina login.

Ya que tenemos una pagina de login, la vamos a maquetar con nuestra css para que tengamos una pagina de login acorde con la maquetación de nuestra aplicación. Para este ejemplo he utilizado la siguiente pagina http://getbootstrap.com/examples/signin/ que podéis encontrar en bootstrap.

Permitir que las css de la maquetación, se pueda visualizar.

Para lo siguiente vamos a quitar de la seguridad, la ruta de los /resources/**, para que nuestra pagina de login tenga acceso a ellos:

@Override
 public void configure(WebSecurity web) throws Exception {
     web
      .ignoring()
      .antMatchers("/resources/**");
  super.configure(web);
 }

Con este cambio ya podemos visualizar el login, con su maquetación.

martes, 6 de octubre de 2015

Configurar Spring 4.1 + Spring security


En los artículos anteriores, hemos visto como crear un proyecto web con spring, activar jackson, como establecer diferentes entornos y los contenidos estáticos. Ahora lo que vamos hacer es  configurar la librería de seguridad, para controlar el acceso a nuestra aplicación.
Con la versión actual, al menos por lo que pone la documentación hay que utilizar las dependencias de spring 4.1.6 o podemos tener problemas con el classpath.
En la siguiente URL podeis accedr al ejemplo del articulo: https://github.com/blancoparis-tfc/SpringSeguridad

Añadir la dependencia de spring security.

En este caso vamos a ir a la pagina del proyecto de spring security, para ver a día de hoy cual es la ultima versión, estable, que en nuestro caso sera la versión 4.0.2.REALEASE, podemos observar que es independiente de la versión del core de spring. Esto es debido a que son proyecto independientes en su desarrollo.
Editaremos el fichero de build.gradle y le pondremos la dependencia que nos han pasado.
compile 'org.springframework.security:spring-security-web:4.0.2.RELEASE'
compile 'org.springframework.security:spring-security-config:4.0.2.RELEASE'

Una vez puesta la dependencia podemos observar que el proyecto sigue funcionando, como antes. Ya que por defecto no activa ninguna configuración se seguridad.

Configuración de seguridad.

En este ejemplo vamos a realizar una configuración estándar, que va a consistir en:
  • Toda la web va a ser privada.
  • Los usuarios los vamos a poner en memoria, para realizar las pruebas. (Lo normal es que en producción estén en una B.D o LDAP, y en desarrollo en memoria).
  • Nos logaremos por una pagina web estándar.

Configuración de seguridad.

Para simplificarnos el trabajos y dar claridad a las configuraciones, vamos a crear la configuración de seguridad en una clase separada. 

Para este ejemplo la configuración va a ser bastante simple, ya que solamente vamos a tener que activar la configuración (@EnableWebSecurity) que herede de la clase WebSecurityConfigurerAdapter y por ultimo le vamos a indicar cual es el usuario en memoria para realizar la configuración.
package org.dbp.conf;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SeguridadConfig extends WebSecurityConfigurerAdapter  {

 @Autowired
 public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  auth
   .inMemoryAuthentication()
    .withUser("user").password("password").roles("USER");
 }
 
}

Ya tenemos establecida nuestra configuración de seguridad, pero o sorpresa si arrancamos el proyecto, sigue sin funcionar la seguridad. Esto es debido a que nos falta por poner un filtro, que para que funcione necesitamos que el contexto este compartido, para lo cual tenemos que establecerlo en un filtro para que lo compartan todos. (Nos lo va a indicar cuando activemos el filtro).

Ojo: En los ejemplos básico de internet, esta destalle no lo vamos a ver ya que va a estar todo en la misma configuración.

Configurar el contexto compartido


Para poder tener el contexto compartido tenemos que realizar los siguientes cambios, en el web.xml.
  • Configurar el listener: ContextLoaderListener
  • Trasladar el fichero de configuración al listener y quitarlo del servlet. (Poniendo una cadena vacía en contextConfigLocation.
  
   <context-param>
      <param-name>contextClass</param-name>
      <param-value>
         org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
   </context-param>
   <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>org.dbp.conf.WebConfig</param-value>
   </context-param>
  <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener> 
 

Ahora vemos en el servlet, como quitar le fichero de configuración.
   <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value></param-value>
  </init-param>
Ya tenemos configurado el contexto, a nivel del contenedor, para que el filtro de seguridad pueda acceder a el.

Ojo con servlet estas configuraciones también se pueden hacer desde clases java tambien.

Configuramos el filtro de seguridad

Aquí simplemente tenemos que crear una clase que herede de AbstractSecurityWebApplicationInitializer. Esta clase si observamos no es un filtro si no un inicializador del contexto de aplicación, que se engancha a nuestro contexto compartido que hemos establecido en el apartado anterior. (Pero al final lo que se configura es un filtro (springSecurityFilterChain) para los temas de la seguridad).
  

package org.dbp.conf;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer  {

}

Enganchar la configuración de seguridad, a la de nuestra aplicación

En este caso es muy fácil simplemente tenemos que establecer, la importación de la configuración. @Import(SeguridadConfig.class) 

Resultado

Una vez realizados los siguientes cambios, que ademas se adaptan adecuadamente a los artículos anteriores, el sistema nos pondrá una pagina de login estándar sin maquetación, para logarse. Aparte según la documentación de spring tendremos las siguiente configuraciones por defecto.

  • Requiere autenticación, por cada URL.
  • Crear el formulario de login.
  • tiene un logout.
  • Prevención de los ataques CSRF-
  • Protecion a (Session Fixation).
  • Integración de la seguridad con la cabecera....
  • Se integran métedo del api Servlet.
    • getRemoteUser.
    • getUserPrincipal
    • isUserInRole
    • login
    • logout

sábado, 5 de septiembre de 2015

Multi-proyecto + Java + Gradle


En un articulo anterior,  ya hemos visto como se puede montar en gradle un multiproyecto, ahora vamos a ver como aplicar esto a un proyecto java dividido en, bom y el service.

Adaptar los sub-proyectos.

Ahora vamos a adaptar los sub-modulos.
  • Establecer la estructura de directorios.
  • Establecemos la configuración común.

Creamos la estructura de directorios

Lo primero será crear la estructura de directorios, en este caso es igual a la que usa maven.
  • /src/main/java
  • /src/main/resources
  • /src/test/java
  • /src/test/resources
Crearemos esta estructura en cada sub modulo.

 

Configurar los módulos

La idea es indicar que los proyectos son de tipo java, en este caso por un lado vamos a configurar la parte común de todos los proyectos, y luego la parte de los sub-proyectos.

Todos los proyectos

- Le indicamos el tipo de proyecto, que en nuestro caso es java y vamos a trabajar con eclipse.
- Aquí estableceremos la versión del proyecto y el grupo que es común para todos los proyectos.
allprojects {
  apply plugin: 'java'
  apply plugin: 'eclipse'
  group = 'org.dbp'
  version = '1.0'
}

En los sub-Modulos.


Aquí vamos a configurar las dependencias.
subprojects{
  repositories {
    mavenCentral()
  }

  dependencies {
   compile 'org.slf4j:slf4j-api:1.7.10'
   compile 'ch.qos.logback:logback-classic:1.1.2'
    testCompile group: 'junit', name: 'junit', version: '4.+'
  }
}

Conclusión


Ahora con estos pequeños cambios ya tenemos el esqueleto pelado para un proyecto java modular.

sábado, 29 de agosto de 2015

Multi-proyecto con gradle


Vamos analizar la necesidad de crear un proyecto, compuesto de varias sub-proyectos.
  • Nos permite realizar una separación lógica de nuestro proyecto. Un clasico es el bom( la B.d), service(La capa de negocio), webapp (La capa de vista).
  • Esta separación nos va evitar que desde un modulo no se puedan llamar a clases del otro ( Si los configuramos como capas separadas). Ejemplo, llamar desde un servicio a la request de un contenedor de servlet que pertenece a la capa de vista.
Cada sub-proyecto va a ser independiente entre si, aunque lo normal es que tenga rasgos comunes.
Ojo: Esto es un ejemplo de como darle utilidad a los subproyectos.
Vamos a ver en este articulo un ejemplo, simple de montar un proyecto raiz y 2 modulos (bom, service).
El ejemplo esta en la siguiente dirección https://github.com/blancoparis-tfc/MultiProyectoGradle.

Organización del fichero.


El proyecto raiz ( o padre), contendrá cada uno de los sub-proyectos (El nombre de la carpeta será el nombre de cada uno de los subProyectos:
Organización del proyecto:
  • build.gradle: El buil del proyecto raiz.
  • settings.gradle: Donde indicaremos los modulos.
  • bom(Directorio): Es el subProyecto  bom.
  • service(Directorio): Es el sub-proyecto service.

Vamos a crear un tarea que nos diga el nombre de cada proyecto, para lo cual nos vamos a apoyar en el buid.gradle del proyecto raiz, vamos a poner una configuración común, de la tarea hola.

Configurar los sub-proyectos.


Ahora le indicamos los sub-proyectos, que en nuestro caso van a ser bom y service.
Fichero (settings.gradle)
include 'bom','service'

Configurar todos los proyectos.


Aquí vamos a ver como establecer la configuración a todos los proyectos.
Fichero (build.gradle)
allprojects {
  task hola << { task -> println "Soy $task.project.name"}
}
$task.project.name—> Accede al nombre del proyecto
La etiqueta allprojects nos pone la configuración en todos los proytectos, incluido el proyecto raiz
Ahora le indicamos los sub-proyectos, que en nuestro caso van a ser bom y service.
Fichero (settings.gradle)
include 'bom','service'
Ahora ejecutamos la tarea hola, ejecutando
gradle –q hola
El resultado es:
>Soy MultiProyectoGradle
>Soy bom
>Soy service

Configurar solo los submodulos


Aqui vamos a ver como establecer la configuración solo para los submodulos, para lo cual vamos a utilizar subprojects.
allprojects {
  task hola << { task -> println "Soy $task.project.name"}
}
subprojects{
  hola << {println "   - Dependo de multi-proyecto"}
}
Ahora ejecutamos la tarea hola, ejecutando
gradle –q hola
El resultado es:
>Soy MultiProyectoGradle
>Soy bom
>    - Dependo de multi-proyecto
>Soy service
>    - Dependo de multi-proyecto

Establecer un comportamiento especifico a un proyecto.


Ahora vamos a verr, como podemos indicar una configuración especifica a un sub-proyecto en cuestión, para lo cual vamos a usar project('<nombre del sub-proyecto).<tarea>
allprojects {
  task hola << { task -> println "Soy $task.project.name"}
}
subprojects{
  hola << {println "   - Dependo de multi-proyecto"}
}
project(':bom').hola << {
  println "        - Soy el proyecto  donde va a estar el modelo de dominio "
}
Ahora ejecutamos la tarea hola, ejecutando
gradle –q hola
>Soy MultiProyectoGradle
>Soy bom
>    - Dependo de multi-proyecto
>          - Soy el proyecto donde va a estar el modelo de dominio
>Soy service
>    - Dependo de multi-proyecto

Nota: La configuración del modulo, lo idea es que este en su propio scripts del proyecto, pero asi vemos como podemos establecer la configuración desde el modulo raiz.

Configurar los sub-proyectos


Ahora vamos a ver como configurar cada sub-modulo, con su propio scripts de gradle

/bom/build.gradle
hola.doLast {
  println "             - Soy el proyecto donde vamos a definir el modelo de dominio";
}
/service/build.gradle
hola.doLast {
  println "             - Soy el proyecto que implementa la capa de negocio";
}
Ahora ejecutamos la tarea hola, ejecutando
gradle –q hola
>Soy MultiProyectoGradle
>Soy bom
>    - Dependo de multi-proyecto
>          - Soy el proyecto donde vamos a definir el modelo de dominio
>Soy service
>    - Dependo de multi-proyecto
>          - Soy el proyecto que implementa la capa de negocio

Reglas de ejecución:


En este caso sigue la regla de ejecutar todas las tareas que se encuentren en la jerarquía, hacia abaojo, por lo cual si entramos en el directorio bom, solo ejecutara la de bom. 

 bom/gradle –q hola

>Soy bom
>    - Dependo de multi-proyecto
>          - Soy el proyecto donde vamos a definir el modelo de dominio

El orden de ejecución es el alfabetico por defecto segun los encuentra  en la jerarquia, por lo cual en el nivel inferior, (ejecuta el multi-proyecto (nivel 0), luego bom y service.

Establecer el orden de ejecución:


Como hemos visto en los ejemplos anteriores, el orden de ejecución es el raiz y el resto por orden alfabetico.

Aunque en este caso no lo necesitamos vamos a ver como establecer un orden de ejecución entre los diferentes sub-proyectos.

Para este ejemplo crearemos la tarea inverso y en le proyecto bom, le vamos a indicar que esta tarea le precede el service, para lo cual utilizaremos el atributo dependsOn

/bom/build.gradle
hola.doLast {
  println "             - Soy el proyecto donde vamos a definir el modelo de dominio";
}
task inverso(dependsOn: ":service:inverso") <<{
  println " El ultimo es bom";
}
/service/build.gradle
hola.doLast {
  println "             - Soy el proyecto que implementa la capa de negocio";
}
task inverso <<{
  println " El primero es service";
}
gradle –q inverso
> El primero es service
> El ultimo es bom

Conclusión

En este articulo hemos visto con unos ejemplos tontos diferentes comportamientos, a la hora de trabajar con un proyecto en gradle por módulos, sin meter ninguna complicación mas. Para realizarlo me he basado en la documentación de gradle oficial, donde vienen muchas mas cosas en el siguiente enlace (https://docs.gradle.org/current/userguide/multi_project_builds.html#multiprojectUseSubprojects)

Nota: En la documentación oficial de gradle hay muchas mas cosas, como mecanismos para filtrar etc...

sábado, 15 de agosto de 2015

Como configurar un Map en JPA



Vamos a ver como configurar un mapa en JPA. Yo lo he necesitado por que tengo un enumerado asociado a un campo String (Que tiene un valor), en vez de crear un campo por cada valor, creo un map al que le paso el tipo y me devuelve el valor.  Y si mañana necesito otro campo con la misma lógica, solo tengo que registrarlo en el enumerado y la B.D no se toca.

Ejemplo practico: Tengo 3 dimensiones para la visibilidad o entidades del sistema a las que le asocio una opción en el enumerado, a las cuales le aplico un comodín para saber a que usuarios aplico la seguridad. Por lo cual la lógica en el código es común y nos interesa,  que el modelo de datos lo tengo en un mapa, para que sea escalable. Tocando solo el tipo enumerado.

Nota: Yo estas cosas las hago cuando ya hay 2 o mas casos, o este muy claro que va a crecer en los requisitos, es mas una excepción que otra cosa.





Como configurar el mapeo:


En este caso vamos a crear un mapeo de un tipo enumerado a un campo:

public enum TipoDimensiones{

Dim1,Dim2,Dim3

}

Añadimos el mapeo a la entidad en cuestión

@Entity
public class Entity(){

@id
private Long id;

@ElementCollection
@MapKeyColumn(name = "tipoDimension")
@JoinTable(name="Entity_visivilidad", joinColumns=@JoinColumn(name="id"))
@Column(name="valor")
private Map<Tipodimensiones,String> visivilidad;

Ahora voy a explicar cada una de las anotaciones. para que entendamos que estamos haciendo y no copiemos como loros :P.


  • ElementCollection: Indica que vamos a rellenar el collection a partir de una tabla.

  • MapKeyColumn: Indica la clave del mapa, usaremos MapKeyColumn cuando sea un tipo básico, en caso de ser una entidad usaremos MapKey (Ojo con esto). 

  • JoinTable: Indicamos la tabla donde se va a persistir el mapa (atributo name) y como que campo de la entidad tenemos que relacionarlo (joinColumn) en nuestro caso es la clave primaria.

  • Column: Le indicamos cual sera la columna que alimentara el valor.




Otra forma de configurar el mapeo


Esto hace lo mismo que lo anterior, pero si nos fijamos en la configuración anterior es un poco redundante el indicarle el id, cuando hibernate tiene la capacidad de saber cual es su id.

Por defecto hibernate utiliza el número de orden para saber cual es el enumerado ( Que corresponde por la posición en el enum que tenemos, si queremos por claridad o otras historias indicarle que el tipo enumerado de la clave guarde el string usaremos la anotación MapKeyEnumerated.

@ElementCollection
@CollectionTable(name="Entity_visivilidad")
@MapKeyEnumerated(EnumType.STRING)
@MapKeyColumn( name = "tipoDimension" )
@Column(name="valor")
private Map<Tipodimensiones,String> visivilidad;

martes, 4 de agosto de 2015

Spring 4.2 + Jpa 2.1 + Hibernate 4.3


Ahora vamos a montar un proyecto de spring, configurando Jpa 2.1 implementado por hibernate 4.3.
Como B.D vamos a usar una embebida (HSQLBD), para que el proyecto sea totalmente autónomo.
Para lo cual vamos a seguir los siguientes pasos:
  • Establecer las dependencias necesarias para un proyecto Spring.
  • Montar la configuración de spring.
  • Montar la configuración de spring JPA.
  • Crear el entorno de test.
  • Montar un test, para que podamos probar nuestra configuración.
El ejemplo de este articulo lo podéis descargar del siguiente enlace https://github.com/blancoparis-tfc/SpringHibernate

Dependencias:

Primero vamos a ver que librerías que vamos a necesitar:

Spring

Las dependencias relacionadas con la versión de spring, en nuestro ejemplo vamos a utilizar la versión 4.2.0.RELEASE.
  • Spring-context: Es la parte de spring encargada de levantar un contenedor de beans.
  • Spring-orm: Es el modulo de spring que utilizaremos para trabajar con los orm, que en nuestro caso sera hibernate como implementación de JPA 2.1.
  compile 'org.springframework:spring-context:4.2.0.RELEASE'
  compile 'org.springframework:spring-orm:4.2.0.RELEASE'

JPA2.1 + Hibernate 4.3


Las dependencias, relacionada con jpa2.1 + hibernate 4.3.10.FINAL.


  • Hibernate-core: Es la implementación de hibernate normal.
  • Hibernate-entitymanager: Es la integración de hibernate con JPA.
    compile 'org.hibernate:hibernate-core:4.3.10.Final'
    compile 'org.hibernate:hibernate-entitymanager:4.3.10.Final'

B.D


Las dependencias, relacionadas como la B.D, que en nuestro caso sera la libreria de HSQLBD mas una implementación de el datasource.


  • Hsqlbd: Es la bd embebida que vamos a utilizar.
  • commons-dbcp: Es una implementación para el datasource, en un proyecto de producición podemos utilizar mejor este c3p0.
    compile 'commons-dbcp:commons-dbcp:1.4'
    compile 'org.hsqldb:hsqldb:2.3.3'

Entorno de test:


La librería que vamos a utilizar, para realizar los test, que en nuestro caso será junit + la librería de test de spring.


  • Junit: Es la librería que vamos a utilizar para realizar los test unitarios.
  • Spring-test: Es la librería para poder lanzar spring, desde los entornos de test.
    testCompile group: 'junit', name: 'junit', version: '4.+'
    testCompile 'org.springframework:spring-test:4.2.0.RELEASE'



Crear el proyecto


Ahora que ya sabemos cuales son las dependencias que necesitamos, vamos a crear el fichero de gradle para poder montar nuestro proyecto.


  • Le tenemos que indicar, que es un proyecto de java y se va integrar con eclipse, para lo cual usaremos los pluging de (java,eclipse)
  • La indicamos con que maquina de java, vamos a trabajar utilizando la variable sourceCompatibility
  • Le indicamos que vamos a usar los repositorios de maven:
  • Ponemos las dependencias que necesitemos.
apply plugin: 'java'
apply plugin: 'eclipse'

sourceCompatibility = 1.8
version = '1.0'

repositories {
    mavenCentral()
}

dependencies {
  compile 'org.springframework:spring-context:4.2.0.RELEASE'
  compile 'org.springframework:spring-orm:4.2.0.RELEASE'
    compile 'commons-dbcp:commons-dbcp:1.4'
    compile 'org.hsqldb:hsqldb:2.3.3'
    compile 'org.hibernate:hibernate-core:4.3.10.Final'
    compile 'org.hibernate:hibernate-entitymanager:4.3.10.Final'
    
    testCompile group: 'junit', name: 'junit', version: '4.+'
    testCompile 'org.springframework:spring-test:4.2.0.RELEASE'
    
}

Configuración de Spring:


Aquí vamos a ver las configuraciones necesarias para spring, en mi caso las colocaremos en el paquete org.dbp.core.config.

Configuración básica de spring


Vamos a ver que necesitamos para poder configurar Spring, mínimo. En este caso la verdad, lo único que le tenemos que indicar a spring en que paquete van a estar los beans con los que vamos a trabajar en nuestro caso sera (org.dbp.service).


  • @Configuration: Le indicamos a spring, que es una clase para configurar spring.
  • @ComponentScan: Le indicamos los paquetes donde se encontraran los beans del contexto, que en nuestro caso “org.dbp.service”
package org.dbp.core.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan(basePackages = "org.dbp.service")
public class TestConfiguracion {

}

Configuración de JPA + Hibernate:


Para la configuración de la JPA, vamos a crear otra clase independiente donde estableceremos toda la configuración necesaria para la persistencia y que inyectaremos en la configuración general.

Para la persistencia tendremos que configurar los siguientes aspectos:


  • Habilitar las transaciones: @EnableTransactionManagement
  • El datasource: Configuraremos el datasource, que realizara la conexión con la B.D, con la que vamos a trabajar. (Si el día de mañana quisiéramos poner un pool de conexión aquí es donde se establecerá).
  • El entityManagerFactory: Configuramos la factoria de los entityManager de JPA, que es donde pondremos la configuración de JPA necesarias.
  • Las transaciones: Aquí configuramos las transacciones de jpa, con spring (Tengamos en cuenta que estas transacciones serán por orientación aspectos).
package org.dbp.core.config;

import java.util.Properties;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class TestJpaConfiguration {

 @Bean
 public DataSource getDataSource() {
     BasicDataSource dataSource = new BasicDataSource();
  dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
  dataSource.setUrl("jdbc:hsqldb:mem:pruebas");
  dataSource.setUsername("sa");
  dataSource.setPassword("");
     return dataSource;
 }
 
 /**
  * Configuramos el entity manager en JPA. - Le indicamos el data source con
  * el que va a trabajar. - Le indicamos el paquete donde se encuentran las
  * clases. - Le pasamos el adaptador de JPA que en nuestro caso sera
  * hibernate. - Por otro lado le pasamos las propiedades.
  * 
  * @return
  */
 @Bean
 public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
  LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
  em.setDataSource(getDataSource());
  em.setPackagesToScan(new String[] { "org.dbp.bom" });
  JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
  em.setJpaVendorAdapter(vendorAdapter);
  em.setJpaProperties(propiedadesAdicionalesJpa());
  return em;
 }
 
 /**
  * Le indicamos el tipo de configuraci�n que nos interesa para hibernate -
  * Le indicmaos que cada vez que entremos borre y cree las B.D. - Le
  * indicamos que utilice el dialecto con HSQL.
  * 
  * Nota: este m�todo no es parte de la configuraci�n de spring.
  * 
  * @return
  */
 private Properties propiedadesAdicionalesJpa() {
  return new Properties() {
   {
    setProperty("hibernate.hbm2ddl.auto", "create");
    setProperty("hibernate.jdbc.batch_size", "20");
    setProperty("hibernate.show_sql", "true");
    setProperty("hibernate.dialect","org.hibernate.dialect.HSQLDialect");
    setProperty("hibernate.hbm2ddl.import_files","/META-INF/inicializar.sql");
   }
  };
 }

 /**
  * Configura las transaciones en JPA.
  * 
  * @return
  */
 @Bean
 public PlatformTransactionManager transactionManager(EntityManagerFactory emf){ 
  JpaTransactionManager transactionManager = new JpaTransactionManager();
  transactionManager.setEntityManagerFactory(emf);
  return transactionManager;
 }
 
}

Ahora simplemente tenemos que indicarle en la configuración general que importe esta configuración con @Import({TestJpaConfiguration.class})




Creamos una entidad.


Para poder probar la configuración, vamos a crear una entidad, en nuestro caso sera el típico ejemplo de usuario con los campos (id,login y descripción).

package org.dbp.bom;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Usuario implements Serializable{

 @Id
 private Long id;
 
 private String login;
  
 private String nombre;

 public String getLogin() {
  return login;
 }

 public void setLogin(String login) {
  this.login = login;
 }

 public String getNombre() {
  return nombre;
 }

 public void setNombre(String nombre) {
  this.nombre = nombre;
 }

 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

}

Test, para probar la configuración


Para poder probar esta configuración básica, la vamos a poner en el entorno de test,  y llamando a un test, consultamos un registro y insertamos otro y así podemos ver que funciona correctamente.
package org.dbp.core.config;

import static org.junit.Assert.*;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.dbp.bom.Usuario;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
 * Test para validar la configuración del JPA.
 * @author david
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@ContextConfiguration(classes = TestConfiguracion.class)
public class ConfigurationJpaTest {

 @PersistenceContext EntityManager em;
 
 @Test
 public void testRecuperarUnUsuario(){
  Usuario usuario=em.find(Usuario.class, 1L);
  assertEquals("El id del usuario 1",new Long(1L),usuario.getId());
  assertEquals("El login del usaurio","dblanco",usuario.getLogin());
  assertEquals("El nombre","david blanco paris",usuario.getNombre());
 }
 
 @Test
 public void testInsertarUsuario(){
  Usuario usuario=new Usuario();
  usuario.setId(2L);
  usuario.setLogin("perico");
  usuario.setNombre("Perico el de los palotes");
  em.persist(usuario);
 }
 
}

Conclusión


En este articulo hemos visto como configurar, un proyecto de spring + jpa. Para no complicar en exceso la configuración lo he montado en un entorno de test, pero ese mismo fichero se lleva a una configuración de spring y nos vale igual.

sábado, 30 de mayo de 2015

Configurar el entorno de trabajo (Spring 4.1). (Producción/Integración/Desarrollo)

La idea es ver como podemos montar en nuestro proyecto, diferentes entornos.
Esto es algo que mucha, veces no le damos mucha importancia, pero que al largo plazo nos simplifica mucho la vida y si lo tenemos claro no es muy difícil de implementar.
El proyecto de ejemplo lo puede consultar en la siguiente url https://github.com/blancoparis-tfc/SpringProfile

Antes de nada vamos a ver los diferentes tipos de entornos que podemos tener en un proyecto.

  • Desarrollo: Es el entorno con las configuraciones para el desarrollo.
  • Integración: Es el entorno donde vamos a subir todos los programadores los cambios, para poder ver si chocan, y realizar las diferentes pruebas, 
  • PreProduccion: Es un entorno equivalente al de produccion, para probar los cambios sin ir a producción.
  • Producción: Es el entorno de producción.
Esta historia se puede plantear de dos maneras:
  • Una construcción independiente por cada entorno, delegando la responsabilidad a la herramienta de build (Maven, gradle), con sus diferentes profile por cada entorno.
  • Una misma construcción que a partir de una variable de entorno establece que entorno y configuraciones vamos a trabajar.
Las dos opciones son factibles, a mi personalmente  me gusta la segunda opción. Que ademas nos proporciona las siguientes ventajas:
  • La responsabilidad del entorno la delegamos al servidor, y por lo cual un administrador de sistema puede realizar cambios sin necesidad de depender del equipo de desarrollo (En algunas cosas), seguridad, B.D etc...
  • Un desarrollador cambiando la configuración de su IDE, puede estar trabajando sobre producción (Si fuera necesario).
  • Podemos llevar el war de desarrollo directamente a producción, sin tener que realizar un montaje. Esto en algún caso de emergencia nos ahorraría algo de tiempo. 
  • Quita la responsabilidad de las configuraciones en la herramienta de build, simplificando su trabajo.
Desventajas:
  • Requiere, de unas configuraciones algo mas complejas y un nivel de abstracción mayor.
  • Es necesario que el framework nos de herramientas que nos facilite esta gestión.

Una vez expuesto, que es un entorno para mi y de que manera vamos a resolver el problema, vamos a ver con que herramientas contamos en Spring:

En el caso de spring ,  nos proporciona el concepto de profile, que nos permite tener uno o varios. Aquí se nos plantea otro dilema como vamos a utilizarlo.
  • Un solo profile: Aquí tendríamos un solo profile activo,  y un profile por cada entorno al cual vincularemos la configuración.
  • Varios profile: Aquí tendríamos varios profile activos y en cada entorno tendríamos que ir poniendo los profile que nos interesen.
En la documentación de spring nos ponen un ejemplo con un profile activo para desarrollo y otro para producción.
Un solo profile activo

El profile activo, se refiere al entorno en cuestión (dev, prod, preProd,int). Aquí la filosofía, es que hacemos una configuración a medida para el entorno.  Esto es una buena opción en un proyecto empresarial o a medida en el cual tengamos 3 o 4 configuraciones idénticas. Normalmente la norma es poner una configuración por defecto y el entorno nos active las excepciones.

Si tenemos 3 o 4 entornos nos simplifica la configuración del servidor, ya que  solo tenemos que mapear el profile con el entorno.
Esta solución no es la mejor si vamos a tener múltiples entornos de producción y queremos que nuestra herramienta, sea muy adaptable y que la configuración fuera del código.
Varios profile activos

Aquí, tendremos varios profiles activos, cada uno se refería a un aspecto de configuración, por ejemplo en el caso de la seguridad en spring podemos tener 3 tipos diferentes:

  • SeguridadMemoria: Mock en memoria (Usuarios puesto a fuego), se suele utilizar en el entorno de desarrollo.
  • SeguridadLadp: Ldap, se validan los usuarios contra un directorio activo. + Configuración del ldap en cuestión en un fichero externo. 
  • SeguridadBD: Los usuarios se valida contra la B.D. + Esquema de B.D. 
En este ejemplo, en el entorno de desarrollo y integración podemos tener los usuarios de palo, ya que no tenemos la necesidad de ir contra el directorio activo y saber las contraseñas de usuarios. Y en preproducción y producción dependiendo del entorno iremos contra un directorio activo o  la B.D.


Y esta operación la podríamos realizar por cada aspecto de la configuración que lo precisara.

Como podemos ver esta configuración le da mas libertad al administrador en el servidor para activar las diferentes configuraciones. En cada entorno, Pero también complica esa configuración.
 Esto tiene sentido si tenemos muchos entornos diferentes al que llevar nuestra aplicación.

Conclusión:

Con que configuración nos vamos a quedar, pues en este caso dependiendo de nuestras circunstancias, como aquí estamos planteando como realizar una separación de un proyecto en 4 entornos de trabajo, nos sale mas a cuenta la primera opción.

Profile

Ahora que ya tenemos claro que vamos a configurar 4 entorno de trabajo, con una misma construcción y que vamos a trabajar con un solo entorno activo, vamos a ver que herramientas nos proporciona spring, para facilitarnos la tarea. Desde la versión 3 de spring mas o menos permite utilizar el concepto de profile.

Profile: Es un grupo lógico de las definiciones de configuración que se activan y beans.
 En los ejemplo de la documentación oficial de spring, nos ponen un ejemplo de dev(desarrollo) y prod (Producción). Mas o menos tenemos que saber 2 cosas de los profile en spring:
  • Como se activa, ya que por defecto no tiene ninguno.
  • Como indicas a una configuración o beans de spring que esta asociado a un profile.

¿Como se activa un profile?

Aquí tenemos diferentes maneras, que utilizaremos según nuestras necesidades, 
  • Programáticamente a través del WebApllicationInitializer
@Configuration
public class MyWebApplicationInitializer implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.setInitParameter("spring.profiles.active", "dev");
    }
}

  • Programáticamente a través de ConfigurableEnviroment.
@Autowired
private ConfigurableEnvironment env;
...
env.setActiveProfiles("someProfile");

  • Parametro de contexto en web.xml
<context-param>

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

    <param-value>/WEB-INF/app-config.xml</param-value>

</context-param>

<context-param>

    <param-name>spring.profiles.active</param-name>

    <param-value>dev</param-value>

</context-param>


  • JVM parámetro del sistema
-Dspring.profiles.active=dev

  • Variable de entorno.
export spring_profiles_active=dev

El tema de activación lo he sacado del siguiente articulo http://www.baeldung.com/spring-profiles

Una vez hemos visto algunas formas, como podemos plantear en nuestro proyecto la activación de un profile, esto es un poco a gusto del consumidor y de las necesidades del proyecto. Yo por ejemplo me gusta que siempre haya una configuración por defecto activa, si no configuro nada y claro esta en su defecto para evitar desgracias mayores siempre es el entorno de desarrollo (Sobra explicar por que no poner producción por defecto xd). 

Como podemos conseguir ese comportamiento que hemos explicado en el párrafo anterior, pues muy fácil, utilizaremos por un lado la configuración programáticamente del WebAplicationInitializer, que seguirá el siguiente algoritmo, si no tenemos activo ningún profile, activa pragmáticamente "dev".  Y para activar el entorno que nos interesa usaremos la configuración de JVM parámetro del sistema esto nos permite que la elección del entorno estar fuera de nuestro código y podremos configurar-lo en el servidor web, que lo contendrá y de esta manera tendremos el mismo paquete para cualquier entorno. 
package org.dbp.conf;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.apache.commons.lang3.StringUtils;
import org.dbp.conf.profiles.ProfilesAplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.WebApplicationInitializer;

@Configuration
public class MiWebApplicationInitializer implements WebApplicationInitializer {
 
 @Override
 public void onStartup(ServletContext servletContext)
   throws ServletException {
  String entornoActivo=System.getProperty("spring.profiles.active");
  if(StringUtils.isBlank(entornoActivo)){
   entornoActivo=ProfilesAplication.dev;
  }
  servletContext.setInitParameter("spring.profiles.active",entornoActivo);  
 }

}

¿Como indicar que configuración se asocia a un profile?

Esto es fácil, solo tenemos que utilizar, la anotación @Profile("<entorno>) y esto activara la configuración o bean asociado.

Otra forma es recuperar del entorno los contextos activos y actuar en consecuencia, en nuestro ejemplo de momento vamos a definir los recursos estáticos distintos para cada contexto como ejemplo:
 @Override
 public void addResourceHandlers(ResourceHandlerRegistry registry) {
  String entorno=env.getActiveProfiles()[0];
  registry
       .addResourceHandler("/resources/**")
       .addResourceLocations("/resources/")
       .setCachePeriod(3600)
       .resourceChain(true)
       .addResolver(new PathResourceResolver());
  registry
       .addResourceHandler("/env/**")
       .addResourceLocations("/resources/env/"+entorno+"/")
       .setCachePeriod(3600)
       .resourceChain(true)
       .addResolver(new PathResourceResolver());  
 }


Como podéis observar en este articulo, es bastante fácil de usar y nos da muchas opciones por lo cual es algo que al final tenemos que ajustar el traje a nuestras necesidades.





martes, 5 de mayo de 2015

Configurar los contenidos estáticos en un proyecto de spring 4.1

Vamos a ver como definir los contenidos estáticos, en un proyecto de Spring. En este caso en concreto, vamos a cargar la librería de bootstrap, para la maquetación.

ResourceHttpRequestHandler

Este clase es la utilizar spring, para trabajar con los recursos estáticos, en el siguiente diagrama vamos a ver como funciona.
Esta implementación sigue las directivas (page Speed, Yslow). Para lo cual gestiona la cache del navegador.

 
Como podemos ver, en el ciclo de vida se diferencia, en dos operaciones:
  • Resolver la operación (Encontrar el recurso segun un path, u otros criterios).
  • Transformar el recurso.
Esta clase ademas se encarga de gestionar la cache del navegador, y actualizar los recursos cuando sea necesario, para lo cual gestionara el (expire y control-cache), de esta manera evitaremos la sobrecarga de la red, con el código 304 y asi no sobrecargar el sevidor.



Para mas información podéis mirar el javadoc de la clase: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.html
Para configurar esta clase utilizaremos ResourceHandlerRegistry, Usaremos los siguientes métodos:

  • addResourceHandler: Indicamos como vamos a localizar el recursos desde la petición de http.  
  • addResourceLocations: Indicamos donde se van a encontrar los recursos, para un mismo recurso podemos tener varios sitios donde buscarlo. (Nota: También puede buscar dentro de los classpath). 
  • setCachePeriod: Establecemos el valor max-age en segundos, en la cabecera de Http destinada para las caches. http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-12
  • resourceChain: Los usaremos para establecer una cadena de resolute y transformadores. Se recomienda establecerlo solo en producción. (Por defecto si no establecemos, nada se configurara PathResourceResolver)
  • addResolver: Le indicamos el resolver que nos interesa entre (PathResourceResolver ,GzipResourceResolver...)
  • addTransformer: Le podemos indicar los transformadores que nos interesan.

Configurar los recursos estáticos:

Ahora que hemos visto un poco, como funciona en spring, la gestión de los recursos estáticos vamos a ver como podemos configurar los en nuestro proyecto. En nuestro caso en cuestión vamos a marcar que los contenidos estáticos, se van a encontrar en el path /resources/ y físicamente lo vamos a dejar en la carpeta resources (Coincide en mi caso para facilitar la búsqueda de los recursos). Entonces que ventaja nos da el utilizar este mecanismo, pues la gestión que hace de la cache spring de esos recursos. Vamos a crear una cadena de resolver y transformer, aunque va a ser igual a que utiliza por defecto (me gusta dejar estas configuraciones declarativas, ya que no todo el mundo se tiene que acordar de la configuración por defecto).

 @Override
 public void addResourceHandlers(ResourceHandlerRegistry registry) {
   registry
       .addResourceHandler("/resources/**")
       .addResourceLocations("/resources/")
       .setCachePeriod(3600)
       .resourceChain(true)
       .addResolver(new PathResourceResolver());
 }

Bootstrap

Ya que tenemos configurados en spring los recursos estáticos, vamos a empezar por configurar la librería bootstrap,  copiaremos en resources la carpeta de bootstrap.


Lo siguiente sera crear la hoja de estilo del proyecto css/app.css
body {
 padding-top: 50px;
}

.starter-template {
 padding: 40px 15px;
 text-align: center;
}

Maquetamos la pagina de inicio

Aquí vamos a crear una plantilla básica con bootstrap (He adaptado uno de las plantillas que nos propone).
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core"%>
<c:url value="/" var="contexto" />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Proyecto de ejemplo">
<meta name="author" content="Arquitectura de ejemplo">
<title>Inicio</title>
<!-- Bootstrap core CSS -->

<link href="${contexto}resources/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="${contexto}resources/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet">
<link href="${contexto}resources/css/app.css" rel="stylesheet">
</head>
<body>
 <nav class="navbar navbar-inverse navbar-fixed-top">
  <div class="container">
   <div class="navbar-header">
    <button type="button" class="navbar-toggle collapsed"
     data-toggle="collapse" data-target="#navbar" aria-expanded="false"
     aria-controls="navbar">
     <span class="sr-only">Toggle navigation</span> <span
      class="icon-bar"></span> <span class="icon-bar"></span> <span
      class="icon-bar"></span>
    </button>
    <a class="navbar-brand" href="#">Spring estatico</a>
   </div>
   <div id="navbar" class="collapse navbar-collapse">
    <ul class="nav navbar-nav">
     <li class="active"><a href="#">Inicio</a></li>
     <li><a href="#about">Acerca de</a></li>
     <li><a href="#contact">Contacto</a></li>
    </ul>
   </div>
  </div>
 </nav>
 <div class="container">
  <div class="starter-template">
   <h1>Inicio</h1>
   <p class="lead">
    Proyecto de ejemplo de los contenidos estaticos.
   </p>
  </div>
 </div>
</body>
</html>
Se tiene que ver algo tal que así:

sábado, 2 de mayo de 2015

Integrar Jackson en Spring 4.1

Vamos a ver como podemos integrar la librería Jackson,
En la siguiente url encontraremos un proyecto con la configuración que hemos puesto en este blog https://github.com/blancoparis-tfc/SpringJson
La anotación @DpbLog es una anotación para poder trazear las llamadas al método, viene explicado en el articulo anterior. 
Apartados:

  • Configurar jackson en spring.
  • Funcionamiento de las vistas de un json en spring.
  • Soporte de jackson a XML
  • Personalizar jackson en spring.
  • Configurar JSR-330 y como establecer los formateo de las fechas.

Configurar jackson 2 con spring 4.1

Esta parte es bastante fácil, ya que simplemente tenemos que poner las librerías y estas automáticamente se integran en spring, con una configuración por defecto.


  • Añadimos la dependencia de jackson core.
  • Añadimos la dependencia de jackson databind
Es importante que estén las dos dependencias para que funcione correctamente.
 compile 'com.fasterxml.jackson.core:jackson-core:2.5.3'
 compile 'com.fasterxml.jackson.core:jackson-databind:2.5.3'

Objeto que vamos a serializar:
package org.dbp.controller.json;

import java.io.Serializable;

public class EjemploJson implements Serializable{

 

 private Long numero;
 private String cadena;
 public Long getNumero() {
  return numero;
 }
 public void setNumero(Long numero) {
  this.numero = numero;
 }
 public String getCadena() {
  return cadena;
 }
 public void setCadena(String cadena) {
  this.cadena = cadena;
 }
 @Override
 public String toString() {
  return "EjemploJson [numero=" + numero + ", cadena=" + cadena + "]";
 }
 
 
}


Ejemplo de uso en el controlador.
 @DbpLog
 @RequestMapping("ejemploJson")
 public @ResponseBody EjemploJson ejemploJson(){
  EjemploJson valdev=new EjemploJson();
  valdev.setNumero(1L);
  valdev.setCadena("cadena");
  return valdev;
 }
Este controlador nos devolverá el siguiente resultado:
{"numero":1,"cadena":"cadena"}

Vistas Json

Spring ahora nos proporciona un mecanismos que nos permite filtrar que partes de un objeto:

La idea es parecida a la de los grupos que se utilizan en el estándar de java para las validaciones. 
En el siguiente enlace encontrara la documentación del Json View  http://wiki.fasterxml.com/JacksonJsonViews
  • Para clasificar usaremos interfaces definidos.
  • Y luego los campos que nos interesa filtrar usaremos la anotación  @JsonView.
Ejemplo de objeto que vamos a serializar filtrado:

package org.dbp.controller.json;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonView;

public class EjemploJson implements Serializable{

 public interface Resumen{};

 @JsonView(Resumen.class)
 private Long numero;
 
 private String cadena;
 
 public Long getNumero() {
  return numero;
 }
 public void setNumero(Long numero) {
  this.numero = numero;
 }
 public String getCadena() {
  return cadena;
 }
 public void setCadena(String cadena) {
  this.cadena = cadena;
 }
 @Override
 public String toString() {
  return "EjemploJson [numero=" + numero + ", cadena=" + cadena + "]";
 }
 
}

Ahora vamos a ver como decirle al controlador  que nos pinte los campos de la vista , poniendo la misma anotación:
 @JsonView(Resumen.class)
 @DbpLog
 @RequestMapping("resumenJson")
 public @ResponseBody EjemploJson resumenJson(){
  return mockEjemplo();
 }

 private EjemploJson mockEjemplo() {
  EjemploJson valdev=new EjemploJson();
  valdev.setNumero(1L);
  valdev.setCadena("cadena");
  return valdev;
 }

Si no ponemos la anotación nos pone todos los campos.

Y nos devolverá el siguiente json como resultado:

{"numero":1}

Vamos a ver como utilizar estas vistas de manera conjunta, como la anotación @JsonView solo se puede poner una utilizaremos las herencias para asociar dos. De esta manera si ponemos la herencia hija, en el controlador activara todas las vistas que hereden.

Ejemplo de objeto que vamos a serializar filtrado:
package org.dbp.controller.json;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonView;

public class EjemploJson implements Serializable{

 public interface Resumen{};

 public interface Resumen2 extends Resumen{}
 @JsonView(Resumen.class)
 private Long numero;
 
 private String cadena;
 @JsonView(Resumen2.class)
 private String descripcion;
 
 
 public String getDescripcion() {
  return descripcion;
 }
 public void setDescripcion(String descripcion) {
  this.descripcion = descripcion;
 }
 public Long getNumero() {
  return numero;
 }
 public void setNumero(Long numero) {
  this.numero = numero;
 }
 public String getCadena() {
  return cadena;
 }
 public void setCadena(String cadena) {
  this.cadena = cadena;
 }
 @Override
 public String toString() {
  return "EjemploJson [numero=" + numero + ", cadena=" + cadena + "]";
 }
 
}

Ahora vemos como utilizarlo en el controlador

 @JsonView(Resumen2.class)
 @DbpLog
 @RequestMapping("resumen2Json")
 public @ResponseBody EjemploJson resumen2Json(){
  return mockEjemplo();
 }

 private EjemploJson mockEjemplo() {
  EjemploJson valdev=new EjemploJson();
  valdev.setNumero(1L);
  valdev.setCadena("cadena");
  valdev.setDescripcion("descripcion");
  return valdev;
 }

Y nos devolverá el siguiente json como resultado:
{"numero":1,"descripcion":"descripcion"}

SpringMVC tiene configurado por defecto a true la siguiente propiedad  MapperFeature.DEFAULT_VIEW_INCLUSION  , esto significa que los campos que no tengan la anotación se agregaran automáticamente

 Soporte xml

Aquí vamos a ver como la librería Jackson nos da soporte de xml:

Ventajas de activar la parte de xml de la librería de Jackson:
  • Nos permite utilizar las anotaciones de jackson y las de JAXB.
  • Podemos utilizar el mismo objeto para configurar un xml y json, sin tener que tener dos objetos o configuraciones separadas.
  • Es capaz de generar un xml, sin las anotaciones de jaxb.
Al activar la librería spring, al activar esta parte en jackson sustituirá a jaxb.
 Ahora vamos a ver los pasos que tenemos que dar para poder configurar-lo en el proyecto, simplemente al igual que jackson al incluir la librería se configurara por defecto.

 // Jackson soporte xml
 compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.3'
Como podemos indicarle a un controlador, que vamos a devolver un xml, esto es fácil, ya que solo le indicamos en el mapeo que vamos a producir un xml.
 @DbpLog
 @RequestMapping(value="ejemploXml",produces = "application/xml")
 public @ResponseBody EjemploJson ejemploXml(){
  return mockEjemplo();
 }
Y nos devolvera el siguiente xml como resultado:
<EjemploJson xmlns="">
<numero>1</numero>
<cadena>cadena</cadena>
<descripcion>descripcion</descripcion>
</EjemploJson>
Una vez indicado esto tenemos que indicar en todas las configuraciones si va a devolver un Json o un xml.

Como personalizar Jackson en Spring:

Para poder personalizar Jackson en spring, ahora podemos utilizar el objeto Jackson2ObjectMapperBuilder 
Vamos a establecer el formateo de las fechas al formato español 'dd-MM-yyyy' y identamos el json que devuelve el servidor. Ahora vamos a ver como activar la configuración de jackson:

  • identiOutput: Tabulamos la salida del json.
  • dateFormat: Le pondremos la fecha "dd-MM-yyyy"
Tenemos que pasarle los converts de jackson a spring, para que lo sepa esto siempre que tengamos que realizar la configuración.


 @Override
 public void configureMessageConverters(
   List> converters) {
  super.configureMessageConverters(converters);
  Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
     builder.indentOutput(true).dateFormat(new SimpleDateFormat("dd-MM-yyyy"));
     converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
     converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
 }
...

Configurar el JSR-330, un formato de fecha determinado

Ahora vamos a ver como poner por defecto un formato de fecha concreto, esto es muy tipico en cualquier proyecto, en España ya que el formato es distinto al ingles.

En este caso, vamos a seguir los siguientes pasos, para el caso LocalDate:
  • Crearemos una clase para deserializar.
  • Crearemos una clase para serializar.
  • Tendremos que crear un modulo propio, ya que el modulo de JSR330 no tiene ningún mecanismos para escalarlo.
  • Por ultimo lo tendremos que registrar.
Ojo, a la hora registrarlo tenemos que hacerlo después del build, ya que la operación de build lo que hace es volver a cargar los deserealizadores y serializadores  del JSR330 y el valido es el ultimo que llega.

 private  class LocalDateDeserializerEs  extends LocalDateDeserializer{
  private LocalDateDeserializerEs(){
   super(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
  }
 }
 
 private class LocalDateSerializerEs extends LocalDateSerializer{
  private  LocalDateSerializerEs(){
   super(false,DateTimeFormatter.ofPattern("dd/MM/yyyy"));
  }
 }
 
 private class JSR310ModuleEs extends SimpleModule{
  public JSR310ModuleEs() {
   super(PackageVersion.VERSION);
         addDeserializer(LocalDate.class,new LocalDateDeserializerEs());
         addSerializer(LocalDate.class, new LocalDateSerializerEs());
  }
 }

 @Override
 public void configureMessageConverters(
   List> converters) {
  super.configureMessageConverters(converters);
  Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
     builder
      .indentOutput(true)
      .dateFormat(new SimpleDateFormat("dd-MM-yyyy")
      );
     converters.add(new MappingJackson2HttpMessageConverter(
         builder
          .build()
          .registerModule(new JSR310ModuleEs())));
     converters.add(new MappingJackson2XmlHttpMessageConverter(
         builder.createXmlMapper(true)
          .build()
          .registerModule(new JSR310ModuleEs())));
 }
El resultado de esta configuración:

En JSON
 {
  "numero" : 1,
  "cadena" : "cadena",
  "descripcion" : "descripcion",
  "fecha" : "01-05-2015",
  "fechaLocal" : "01/05/2015",
  "fechaTime" : "2015-05-01T21:38:45.748"
}
En Xml

<EjemploJson>
<numero>1</numero>
<cadena>cadena</cadena>
<descripcion>descripcion</descripcion>
<fecha>02-05-2015</fecha>
<fechaLocal>02/05/2015</fechaLocal>
<fechaTime>2015-05-02T10:40:21.485</fechaTime>
</EjemploJson>
Podemos ver que la fecha que es un date, se formatea con los guiones la fechaLocal es un LocalDate y se formatea con los /. y el LocalDateTime, no lo hemos puesto un formateo y por eso sale asi. (Si seguimos los mismos pasos que al anterior podemos poner el que nos interese).
Nota: Al registrar un serializador mas de una vez sobre la misma clase, la ultima es la que prevalece, pero hay  que tener en cuenta que los de JSR330 se registran cuando se realiza el Build.

martes, 28 de abril de 2015

Configurar los logs Spring 4.0 + slf4j + logback

Ahora vamos a configurar los logs de nuestro proyecto.

  • Configuración del sistema de logs.
  • Marcar las diferentes peticiones request que recibe el sistema para poder asociarlas.

Elección de la librería de logs

En java actualmente se usan dos librerias una que realiza de patron de fachada de los logs, que nos independiza de la implementación del sistema de logs y una segunda que se encarga de la gestión de logs.

  • Primero seleccionaremos la librería que nos hará de fachada a la implementación. Actualmente hay dos librerias commons-loggins y slf4j.
Aquí la elección para mi es facil, slf4j, actualmente es algo mas eficiente, por otro lado nos da la posibilidad de evitar la concatenación en los logs, al pasar parámetros que esto mejora el performace y actualmente spring y otros frameworks la usan. Aparte tambien la forma que tiene de funcionar frente a la implementación, en este articulo lo esplica bastante bien (http://jayunit100.blogspot.com.es/2013/10/simplifying-distinction-between-sl4j.html).
  • Segundo utilizaremos una de las implementaciones, log4j, logback, Jul.
Aquí la elección, la tengo bastante clara utilizo logback, frente a log4j,  la razon es que por un lado una implementación bastante estable (llevo usándola varios años y no he dado ningún problema)  y lo ha creado parte de la gente que participo en la creación de log4j. En el siguiente enlace la gente de logback te cuentan sus ventajas (http://logback.qos.ch/reasonsToSwitch.html)
Ademas a nivel de libreria, esta mas cuidada que log4j por ejemplo la clase logger es de tipo final para que nadie la puede rescribir, y complique las migraciones, ademas con herramientas como MDC, no es necesario rescribir la clase de logger.


En resumen usaremos slf4j + logback.

Ojo: Importante en nuestra aplicación usaremos solo los mecanismos que nos proporciona slf4j, para no acoplar la aplicación a la implementación.

 Configurar el sistema de logs.

Ahora vamos a ver como configurar el sistema de logs, en este caso vamos a trabajar con la implementación seleccionado, en nuestro caso hemos optado por logback.

Logback, nos proporciona dos mecanismos, de configuración:
  • Un fichero xml. logback.xml
  • Un fichero tipo grooby. logback.grooby
A continuación os adjunto la configuración de ejemplo par que los logs salgan en cosola /src/main/resources/logback.xml
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

Ejemplo de uso

Por una lado creamos el logger, usando una factorio y por norma general se le pasa la clase en la que se va a utilizar.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
private static Logger logger = LoggerFactory.getLogger(InicioController.class);


Ahora vamos a ver como se utiliza el sistema de logger.
logger.info("Metodo {}","inicio");
Ejemplo de uso en un controlador de spring:
package org.dbp.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("inicio")
public class InicioController {

 private static Logger logger = LoggerFactory.getLogger(InicioController.class);
 
 @RequestMapping
 public String inicio(){
  logger.info("Metodo {}","inicio");
  return "inicio";
 }
 
}

Como marcar las peticiones.

Para poder seguir o asociar logs en un servidor web, es muy interesante marcar las peticiones del servidor con un número. De esta manera podemos saber todas las trazas que están asociadas a una única petición y ademas si en los errores asociados este número nos ayudara a buscar los detalles del error, en el logs de nuestra aplicación.

Para poder implementar esta historia utilizaremos 2 mecanimos, por una lado un interceptor de spring que sera en encargado de alimementar la marca que pondremos en todas las trazas de esa petición y por otro lado usaremos el MDC de slf4j, para guardar esa información (Tenemos que tener en cuenta que el MDC asocia las varibles al hilo de ejecución (utiliza en ThreadLocal).

A continuación os adjunto un diagrama explicando como funciona este mecanismo.




Creamos el interceptor que se va a encargar de esto:

Usaremos el interceptor, para crear la marca de tiempo y pasársela al sistema de logs, y cuando el controlador nos devuelva el control, el sistema se encarga de borrar la marca de tiempo. Para transmitir la información a slf4j usaremos el mecanismo MDC.

MDC, se apoya en una variable de tipo thearlocal, lo cual asocia los valores al hilo de ejecución, este implica que se puede reutilizar, por lo cual es recomendable una vez terminada el procesamiento de la request tenemos que eliminarlo. Es importante tener en cuenta ya que va condicionado por la JVM y el servidor web que utilicemos.
Guardaremos la marca de tiempo en la variable de MDC (MarcaTiempo)

package org.dbp.conf.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.MDC;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class LogInterceptor 
implements HandlerInterceptor{

 @Override
 public boolean preHandle(HttpServletRequest request,
   HttpServletResponse response, Object handler) throws Exception {
  MDC.put("MarcaTiempo", ""+System.currentTimeMillis());
  return true;
 }

 @Override
 public void postHandle(HttpServletRequest request,
   HttpServletResponse response, Object handler,
   ModelAndView modelAndView) throws Exception {
  MDC.remove("MarcaTiempo");
 }

 @Override
 public void afterCompletion(HttpServletRequest request,
   HttpServletResponse response, Object handler, Exception ex)
   throws Exception {
 }

}

Configurar logBack para utilizar la variable de MDC.

Ahora veremos como le indicamos a logBack, para que nos pinte la marca de tiempo. Simplemente
 tendremos que modificar el patrón de pintar la linea y para referencia a una variable del MDC, utilizaremos la siguiente sintaxis: %X{<nombre de la variable>}

<configuration>
  <appender class="ch.qos.logback.core.ConsoleAppender" name="STDOUT">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%X{MarcaTiempo}] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
  <root level="debug">
    <appender-ref ref="STDOUT">
  </appender-ref></root>
</configuration>

Configurar un aspecto, para el log de los métodos

Vamos a configurar un aspecto, para tener una herramienta que nos permite hacer log de los métodos que se utilizan.

Configurar las librerias:

Lo primero que vamos hacer es añadir al proyecto la libreia de aspectJ.

 compile 'org.aspectj:aspectjrt:1.8.5'
 compile 'org.aspectj:aspectjweaver:1.8.5'

Crear el aspecto en spring.

Vamos a definir como va a trabajar el aspecto, por lo cual tenemos que definir el mecanismo para que se lance, en este caso tenemos varias alternativas:

  • Marcar el lanzamiento por una anotación.
  • Establecer un conjunto de paquetes o métodos genericos.
En mi caso voy a utilizar la anotación para que el lanzamiento del aspecto sea declarativo, pero si quisieramos que se traquearan todas las invocaciones de los métodos optariamos por la segunda configuración.

Cómo hemos elegido usar una anotación, empezaremos por definir la anotación.
package org.dbp.conf.aop.log;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface DbpLog {

}
Ahora vamos a definir el aspecto:

  • Antes de llamar al método si  tiene la anotación @DbpLog pintamos un log de debug.
  • Despues de llamar al método si es un return y tiene la anotación @DbpLog pintar el valor devuelto.
  • Despues de llamar al método y tiene la anotación @DbpLog trakeamos el valor devuelto.
  • En caso de lanzar una excepción, mostramos los valores de entrada, el método y la excepción.
ackage org.dbp.conf.aop.log;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 
 * Configuración de los los aspecto para el sistema de logs.
 * 
 *  - Por un lado logeamos los métodos que esten anotados por @DpbLog.
 *  - Y Siempre que tengamos una excepción, este o no anotado en los siguientes paquetes: org.dbp.controller
 * 
 * @author david
 *
 */
@Aspect
public class LogAspect {

 private static Logger logger=LoggerFactory.getLogger(LogAspect.class);
 /**
  * 
  * Antes de ejecutar el método.
  * 
  * @param joinPoint Es el punto de union.
  */
 @Before("execution(* *(..)) && @annotation(org.dbp.conf.aop.log.DbpLog)")
 public void antes(final JoinPoint joinPoint){
  logger.debug(" Antes: [{}] argumentos [{}]"
    ,joinPoint.getSignature().toString()
    ,Arrays.toString(joinPoint.getArgs()));
 }
 /**
  * 
  * Despues de ejecutar un método que tiene return.
  * 
  * @param joinPoint Es el punto de union.
  * @param valdev El valor devuelto por el método.
  */
 @AfterReturning(
   pointcut="execution(* *(..)) && @annotation(org.dbp.conf.aop.log.DbpLog)"
   ,returning="valdev"
   )
 public void despuesReturn(final JoinPoint joinPoint,Object valdev){
  logger.debug(" [{}] valdev: [{}]"
     ,joinPoint.getSignature().toString()
     ,valdev);
 }
 /**
  * 
  * Despues de ejecutar un metodo que tiene void.
  * 
  * Nota: Se ejecutara si procede, despuest de la traza de debug.
  * 
  * @param joinPoint Es el punto de union.
  * 
  */
 @After("execution(* *(..)) && @annotation(org.dbp.conf.aop.log.DbpLog)")
 public void despues(final JoinPoint joinPoint){
  logger.debug(" Despues: [{}] argumentos [{}]"
    ,joinPoint.getSignature().toString()
    ,Arrays.toString(joinPoint.getArgs()));
 }
 /**
  * 
  * Se ejecutara siempre que tengamos una exceptión, para el paquete controller.
  * 
  * @param joinPoint Es el punto de union.
  * @param ex  La excpeción que se ha ejecutado.
  */
 @AfterThrowing(
   pointcut="execution(* org.dbp.controller.*.*(..))  "
   ,throwing="ex"
   )
 public void despuesExcepcion(final JoinPoint joinPoint,final Throwable ex){
  logger.warn(" [{}] argumentos [{}] "
    ,joinPoint.getSignature().toString()
    ,Arrays.toString(joinPoint.getArgs()));
  logger.error(" Error [{}] "
    ,joinPoint.getSignature().toString()
    ,ex);
 }
 
}

Ejemplo de uso de los logs:

En nuestro ejemplo lo vamos a ver en el controlador:
  • Vamos anotar un método y poner un log.
  • El otro lanza una excepción.
package org.dbp.controller;

import javax.servlet.http.HttpServletRequest;

import org.dbp.conf.aop.log.DbpLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("inicio")
public class InicioController {

 private static Logger logger = LoggerFactory.getLogger(InicioController.class);
 @DbpLog
 @RequestMapping
 public String inicio(){
  logger.info("Metodo {}","inicio");
  return "inicio";
 }
 

 
 @RequestMapping("excepcion/{param}")
 public String excepcion(HttpServletRequest  request,@PathVariable(value="param") String param) throws Exception{
  throw new Exception("Error de prueba");
 }
 
}
La invocación del primer método nos devolverá la siguiente traza.

La invocación del segundo método nos devolverá la siguiente traza.



Como podemos ver toda la traza de la petición request, esta asociada con un solo número lo cual nos indica todas las trazas que se han ejecutado en la misma petición.



sábado, 25 de abril de 2015

Crear un proyecto web con Spring

Hoy vamos a ver como crear desde cero un proyecto web  con spring y gradle. Para lo cual seguiremos los siguientes pasos:
En el siguiente enlace https://github.com/blancoparis-tfc/basicoSpring podéis encontrar el proyecto completo.

¿Herramienta para gestión y construcción del proyecto?

Para la gestión de las librerías y montaje del proyecto vamos a utilizar la herramienta gradle (Ojo también podemos usar maven) a fin de cuentas gradle va a usar los repositorios de maven :). 
¿Por que he seleccionado Gradle, en vez de maven? Es simple, por que ahora estoy aprendiendo gradle, pero para realizar esta tarea en principio nos valen las dos herramientas.
Ahora que tenemos seleccionada la herramienta vamos a ver que pasos tenemos que dar.

¿Decidimos que necesitamos?

Antes de empezar a picar una linea de código tenemos que tener claro que necesitamos. A continuación enumeramos los compomentes para empezar un proyecto web en spring.
  • Seleccionar los plugins de gradle que necesitamos:
    • 'java': Por que va a ser un proyecto java.
    • 'war': Por que va a ser un proyecto web.
    • 'eclipse': Lo vamos a integrar con el ide eclipse.
    • 'eclipse-wtp':Lo vamos a integrar con eclipse-wtp.
  • La versión de jdk (en nuestro caso vamos a seleccionar la versión JDK 1.8)
  • Definir el contenedor de servlet (Nuestro caso sera 3.0).
  • El repositorio, que vamos a utilizar para gestionar las dependencias.
  • La dependencias que vamos a necesitar.
    • La librería de spring para hacer una aplicación web (spring-webmc).
    • Las librerías para los logs (slf4j + logback).
    • La libreria para los test unitarios (junit)
Ahora voy a explicar paso a paso como configurar el proyecto en gradle.

Plugins: Ponemos los plugins que necesitamos:

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
apply plugin: 'eclipse-wtp'

La versión de la JDK 1.8:  Para indicar que jdk vamos a trabajar usaremos la variable sourceCompatibility. Y también aprovecharemos y definimos la versión de nuestra aplicación.

sourceCompatibility = 1.8
version = '1.0'
Configuración del proyecto web: Par que eclipse, sepa la versión del servlet (3.0), tenemos que indicarse lo explicita-mente en gradle (indicándole el facet que tiene que usar), por ejemplo en maven la integración con eclipse se apaña leyendo el fichero web.xml.

eclipse{
 wtp{
  facet{
  facet name: 'jst.web', version: '3.0'
  }
 }
}

Repositorio: Aquí le definimos que repositorio vamos a utilizar para buscar las dependencias. En el caso de maven es algo que no necesitamos definir.

repositories {
    mavenCentral()
}
Dependencias: Aqui vamos a definir las dependencias (Son las mismas que utilizamos en maven), http://mvnrepository.com/
dependencies {
 compile 'org.springframework:spring-webmvc:4.1.6.RELEASE'
 compile 'org.slf4j:slf4j-api:1.7.10'
 compile 'ch.qos.logback:logback-classic:1.1.2'
 providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
  testCompile group: 'junit', name: 'junit', version: '4.+'
}
Ojo: providedCompile: Usamos este contexto de  una dependencia para que a la hora de compilar use la librería, pero en la creación del proyecto no la ponga ya que la tenemos en el servidor web y puede entrar en conflicto. Compile: Se usa en la compilación y en la construcción. testCompile: Estas librerías no se usara en la compilación del proyecto, pero si en la compilación y ejecución de los test.
Ojo2: En eclipse, juntara en compilación las librerías de test y las normales y puede llevar alguna confusión ya que eclipse en principio no hace una diferencia en las dependencias entre entorno de test y de ejecución.
Configuración del fichero de gradle, como quedara:
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
apply plugin: 'eclipse-wtp'

sourceCompatibility = 1.8
version = '1.0'
eclipse{
 wtp{
  facet{
  facet name: 'jst.web', version: '3.0'
  }
 }
}
repositories {
    mavenCentral()
}

dependencies {
 compile 'org.springframework:spring-webmvc:4.1.6.RELEASE'
 compile 'org.slf4j:slf4j-api:1.7.10'
 compile 'ch.qos.logback:logback-classic:1.1.2'
 providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
  testCompile group: 'junit', name: 'junit', version: '4.+'
}

Creamos la estructura de directorios básica:

Ahora vamos a crear el directorio donde se guardaran los fuentes de nuestro proyecto.
  • "src\main\java": Aquí es donde crearemos los ficheros de java.
  • "src\main\resources": Donde pondremos los recursos del proyecto.
  • "src\main\webapp": Donde ubicaremos los ficheros para un proyecto web.

Configuración del proyecto.

En un proyecto web,  vamos a configurar donde se ubicaran los:
  • Controladores. (org.dbp.controller)
  • Los jsp (/WEB-INF/pages/)
Aparte le indicaremos a Spring que es un proyecto web mvc (con la anotación enabledWebMvc).

package org.dbp.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(
  basePackages={
    "org.dbp.controller" // Es donde se ubicaran los controladores
    }
  )
public class WebConfig {
 /**
  * 
  * Configuramos que las paginas se guarden en la carpeta pages
  * 
  * @return
  */
    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

Una vez establecida la configuración básica de spring, solo nos toca configurar en el web.xml el dispacher. Simplemente le indicamos donde se encuentra la clase de configuración.

Fichero /WEB-INF/web.xml
<web-app id="WebApp_ID" version="3.0" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
 <servlet>
  <servlet-name>dispacher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
   <param-name>contextClass</param-name>
   <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
  </init-param>
  <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>org.dbp.conf.WebConfig</param-value>
  </init-param>
 </servlet>

 <servlet-mapping>
  <servlet-name>dispacher</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>

</web-app>

Controlador de prueba:

Una vez configurado el proyecto vamos a crear nuestro controlador llamado inicio, que simplemente nos redirigirá a una página. 

Controlador org.dbp.InicioController
package org.dbp.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("inicio")
public class InicioController {

 @RequestMapping
 public String inicio(){
  return "inicio";
 }
 
}
La jsp /WEB-INF/pages/inicio.jsp
Inicio

Es un ejemplo simple de direccionamiento a una pagina en concreto.
http://localhost:8080/basicoSpring/inicio (Esta url tendría que devolvernos la palabra inicio.