Páginas

martes, 3 de julio de 2012

RAD JEE+Hibernate+Spring+JPA+Maven2+Generics

Vamos a montar un pequeño proyecto "Biblioteca" con un par de tablas, Autor y Libro relacionadas 1:N "un autor tiene varios libros". Lo montamos con diseño en tres capas con:

Hibernate
Spring
JPA
Maven2

JEE 1.6
Genericos Java
MySQL

La idea es trabajar lo mínimo, con lo que utilizaremos una clase BaseDaoJpa para la capa de acceso a datos y una clase GestorBaseImpl. Estas clases y sus correspondientes interfaces: IBaseDao e IGestorBase, las tenemos de proyectos anteriores o las podríamos tener en los arquetipos Maven2 que montásemos para construtir los esqueletos de nuestros proyectos.

Las clases son:

Capa de presentación:

AppTest.java. Clase con el código de la mini-aplicación. Vamos a entender este main como una posible capa de presentación. Se podría ver por ejemplo como un aplicativo Swing.

package org.dune.app;

import java.util.ArrayList;
import java.util.List;

import org.dune.model.Autor;
import org.dune.model.Libro;
import org.dune.negocio.IGestorAutor;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {

    public static void main(String[] args) {

        //Carga del contexto
        final ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml");

        //Recogemos el gestor de Autores
        final IGestorAutor gestAutores = (IGestorAutor)ctx.getBean("gestorAutor");

        //Damos de alta un autor
        final Autor a = new Autor();
        a.setNombre("nombre");
        a.setApellido1("apellido1");
        a.setApellido2("apellido2");
        final Autor autorGrabado = gestAutores.save(a);

        //Damos de alta algunos libros
        final List<Libro> lstLibros = new ArrayList<Libro>();
        final Libro lib1 = new Libro();
        lib1.setTitulo("titulo1");
        lib1.setAutor(autorGrabado);
        final Libro lib2 = new Libro();
        lib2.setTitulo("titulo1");
        lib2.setAutor(autorGrabado);
        lstLibros.add(lib1);
        lstLibros.add(lib2);
        autorGrabado.setLibros(lstLibros);
        gestAutores.save(autorGrabado);
       
    }
}


Capa de negocio:

IGestorAutor.java. Interfaz de los servicios de gestión de autores.

package org.dune.negocio;

import org.dune.model.Autor;

public interface IGestorAutor extends IGestorBase<Autor, Long> {

}

GestorAutorImpl.java. Implementación de los servicios de gestión de autores.

package org.dune.negocio.impl;

import org.dune.dao.IAutorDao;
import org.dune.model.Autor;
import org.dune.negocio.IGestorAutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("gestorAutor")
public class GestorAutorImpl extends GestorBaseImpl<Autor, Long> implements IGestorAutor {

    private IAutorDao autorDao;
   
    @Autowired
    public GestorAutorImpl(IAutorDao autorDao) {       
        super(autorDao);
        this.autorDao = autorDao;
    }
}

IGestorBase.java. Interfaz base extendido por los restantes interfaces de servicios ofertados en la capa de negocio.

package org.dune.negocio;

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

import org.dune.dao.IBaseDao.Orden;

public interface IGestorBase<T, PK extends Serializable> {

    public T get(PK id);

    public List<T> getAll();
  
    public List<T> getAllNoBaja(Date fechaBaja);

    public void remove(PK id);

    public T save(T obj);
  
    public List<T> saveAll(List<T> l);

    public List<T> getPaginado(int startPosition, int maxResult);

    public List<T> getPaginadoOrdenado(int startPosition, int maxResult, String campo, Orden direccion);

}

GestorBaseImpl.java. Clase base de la que extienden todos los implementadores de servicios ofertados en la capa de nogocio.

package org.dune.negocio.impl;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dune.dao.IBaseDao;
import org.dune.dao.IBaseDao.Orden;
import org.dune.negocio.IGestorBase;
import org.springframework.transaction.annotation.Transactional;

public class GestorBaseImpl<T, PK extends Serializable> implements IGestorBase<T, PK> {
   
    protected final Log log = LogFactory.getLog(getClass());
    protected IBaseDao<T, PK> baseDao;

    public GestorBaseImpl(IBaseDao<T, PK> baseDao) {
        this.baseDao = baseDao;
    }

    @Transactional
    public T get(PK id) {
        return baseDao.get(id);
    }

    @Transactional
    public List<T> getAll() {
        return baseDao.getAll();
    }
   
    @Transactional
    public List<T> getAllNoBaja(Date fechaBaja) {
        return baseDao.getAllNoBaja(fechaBaja);
    }

    @Transactional
    public void remove(PK id) {
        baseDao.delete(id);
    }

    @Transactional
    public T save(T obj) {
        return baseDao.save(obj);
    }
   
    @Transactional
    public List<T> saveAll(List<T> l) {
        return baseDao.saveAll(l);
    }

    @Transactional
    public List<T> getPaginado(int startPosition, int maxResult) {
        return baseDao.getPaginado(startPosition, maxResult);
    }

    @Transactional
    public List<T> getPaginadoOrdenado(int startPosition, int maxResult, String campo, Orden direccion) {
        return baseDao.getPaginadoOrdenado(startPosition, maxResult, campo, direccion);
    }

}


Capa de acceso a datos:

IAutorDao.java. Interfaz de la capa de acceso a datos para la tabla Autores.

package org.dune.dao;

import org.dune.model.Autor;

public interface IAutorDao extends IBaseDao<Autor, Long> {
  
}

AutorDaoJpa.java. Implementación JPA de la capa de acceso a datos para la tabla Autores.

package org.dune.dao.jpa;

import org.dune.dao.IAutorDao;
import org.dune.model.Autor;
import org.springframework.stereotype.Repository;


@Repository
public class AutorDaoJpa extends BaseDaoJpa<Autor, Long> implements IAutorDao {

    public AutorDaoJpa() {
        super(Autor.class);
    }
}

IBaseDao.java. Interfaz base extendido por los restantes interfaces de la capa de acceso a datos.

package org.dune.dao;

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

public interface IBaseDao<T, PK extends Serializable> {

    public static enum Orden {
        ASC,
        DESC;
    };

    public T get(PK id);

    public List<T> getAll();
  
    public List<T> getAllNoBaja(Date fechaBaja);
  
    public T save(T t);

    public List<T> saveAll(List<T> l);
  
    public void delete(PK id);

    public List<T> getPaginado(int startPosition, int maxResult);

    public List<T> getPaginadoOrdenado(int startPosition, int maxResult, String campo, IBaseDao.Orden direccion);
}

BaseDaoJpa.java. Clase base de la que extienden todos los implementadores de la capa de acceso a datos.

package org.dune.dao.jpa;

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

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.jpa.JpaTemplate;

import org.dune.dao.IBaseDao;

public class BaseDaoJpa<T, PK extends Serializable> implements IBaseDao<T, PK> {

    protected final Log log = LogFactory.getLog(getClass());

    private Class<T> persistentClass;
  
    private JpaTemplate jpaTemplate;
  
    public BaseDaoJpa(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    @Autowired
    public void setEntityManager(EntityManager entityManager) {
        this.jpaTemplate = new JpaTemplate(entityManager);
    }
  
    public JpaTemplate getJpaTemplate() {
        return jpaTemplate;
    }
  
    public T get(PK id) {

        final T t = (T) getJpaTemplate().find(persistentClass, id);

        if (t == null) {
            throw new ObjectRetrievalFailureException(persistentClass, id);
        }
        return t;
    }

    @SuppressWarnings("unchecked")
    public List<T> getAll() {

        final StringBuilder query = new StringBuilder("from ").append(persistentClass.getName()).append(" c ");

        return (List<T>) getJpaTemplate().find(query.toString());
    }
  
    @SuppressWarnings("unchecked")
    public List<T> getAllNoBaja(Date fechaBaja) {

        final StringBuilder query = new StringBuilder("from ").append(persistentClass.getName()).append(" c").append(" where nvl(c.fechaBaja, to_date('31129999', 'DDMMYYYY')) > ?1");

        return (List<T>) getJpaTemplate().find(query.toString(), fechaBaja);
    }  

    public void delete(PK id) {
        getJpaTemplate().remove(get(id));
    }

    public T save(T t) {
        return (T) getJpaTemplate().merge(t);
    }
  
    public List<T> saveAll(List<T> l) {
        if (l != null) {
            for (T t : l) {
                getJpaTemplate().merge(t);
            }
        }
        return l;
    }

    @SuppressWarnings("unchecked")
    public List<T> getPaginado(int startPosition, int maxResult) {

        final StringBuilder sql = new StringBuilder("select c from ").append(persistentClass.getSimpleName()).append(
                " c");
        final Query query = getJpaTemplate().getEntityManager().createQuery(sql.toString());
        query.setFirstResult(startPosition);
        query.setMaxResults(maxResult);

        return (List<T>) query.getResultList();
    }

    @SuppressWarnings("unchecked")
    public List<T> getPaginadoOrdenado(int startPosition, int maxResult, String campo, IBaseDao.Orden direccion) {

        final StringBuilder sql = new StringBuilder("select c from ").append(persistentClass.getSimpleName())
                .append(" c order by c.").append(campo).append(" ").append(direccion);
        final Query query = getJpaTemplate().getEntityManager().createQuery(sql.toString());
        query.setFirstResult(startPosition);
        query.setMaxResults(maxResult);

        return (List<T>) query.getResultList();
    }
}


Mapeos:

Autor.java. Clase que mapea la tabla Autor

package org.dune.model;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="AUTOR")
public class Autor {

    protected Long id;
    protected String nombre;
    protected String apellido1;
    protected String apellido2;
    protected List<Libro> libros;
   
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    public Long getId() {
        return id;
    }
   
    public void setId(Long id) {
        this.id = id;
    }

    @Column(name="NOMBRE")
    public String getNombre() {
        return nombre;
    }

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

    @Column(name="APE1")
    public String getApellido1() {
        return apellido1;
    }

    public void setApellido1(String apellido1) {
        this.apellido1 = apellido1;
    }

    @Column(name="APE2")
    public String getApellido2() {
        return apellido2;
    }

    public void setApellido2(String apellido2) {
        this.apellido2 = apellido2;
    }

    @OneToMany(mappedBy = "autor", cascade = CascadeType.ALL)
    public List<Libro> getLibros() {
        return libros;
    }

    public void setLibros(List<Libro> libros) {
        this.libros = libros;
    }
}

Libro.java. Clase que mapea la tabla Libro

package org.dune.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="LIBRO")
public class Libro {

    protected Long id;
    protected String titulo;
    protected Autor autor;
   
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
   
    @Column(name="TITULO")
    public String getTitulo() {
        return titulo;
    }

    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }

    @ManyToOne
    @JoinColumn(name = "AUTOR")
    public Autor getAutor() {
        return autor;
    }

    public void setAutor(Autor autor) {
        this.autor = autor;
    }
}

Como elementos de configuración tendremos tres ficheros:

applicationContext.xml.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/biblioteca"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"            <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="true" />
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
            </bean>
        </property>
    </bean>
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <tx:annotation-driven/>   
<context:annotation-config base-package="org.dune" />
<context:component-scan base-package="org.dune" />
</beans>

persistence.xml.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
   
    <persistence-unit name="PERSISTENCE_UNIT" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>org.dune.model.Autor</class>
        <class>org.dune.model.Libro</class>      
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
        </properties>
    </persistence-unit>
</persistence>

pom.xml.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.dune</groupId>
  <artifactId>Test</artifactId>
  <version>1.0</version>
  <dependencies>
      <dependency>
          <groupId>es.ine.sgtic.comun.lib.spring</groupId>
          <artifactId>spring-2.5.0-lib</artifactId>
          <version>1.0</version>
          <type>pom</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.spring.2.5.0.j2ee</groupId>
          <artifactId>persistence</artifactId>
          <version>9.0</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.myfaces.1.2.5</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.1.1</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.spring.2.5.0.hibernate</groupId>
          <artifactId>hibernate-annotations</artifactId>
          <version>3.3.0.ga</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.comun.util.utilidades</groupId>
          <artifactId>ine-util-cripto</artifactId>
          <version>2.0</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.mysql.5.0.4</groupId>
          <artifactId>mysql-connector-java-5.0.4-bin</artifactId>
          <version>5.0.4</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.comun.lib.hibernate</groupId>
          <artifactId>hibernate-3.2.5.GA-lib</artifactId>
          <version>1.0</version>
          <type>pom</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.jboss</groupId>
          <artifactId>jboss-common</artifactId>
          <version>1.2.1.ga</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.spring.2.5.0.dom4j</groupId>
          <artifactId>dom4j</artifactId>
          <version>1.6.1</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.jboss</groupId>
          <artifactId>concurrent</artifactId>
          <version>4.2.2.ga</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.jboss</groupId>
          <artifactId>javassist</artifactId>
          <version>4.2.2.ga</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.spring.2.5.0.jakarta-commons</groupId>
          <artifactId>commons-collections</artifactId>
          <version>3.2</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.spring.2.5.0.cglib</groupId>
          <artifactId>cglib-nodep</artifactId>
          <version>2.1_3</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
      <dependency>
          <groupId>es.ine.sgtic.lib.spring.2.5.0.j2ee</groupId>
          <artifactId>jta</artifactId>
          <version>1.1</version>
          <type>jar</type>
          <scope>compile</scope>
      </dependency>
  </dependencies>
</project>

No hay comentarios:

Publicar un comentario