arquitectura base de una aplicacion java python .net

Arquitectura Simple con Java Parte 1 – DAO


En este inicio de proyecto donde iremos subiendo y evolucionando nuestro proyecto de Java, hasta llegar a algo robusto.

Nuestro primer punto de partida será la capa de DAO (Data Access Object), esta capa no es solamente conexión a una base de datos, sino podemos traer datos de otros sistemas legados o proveedores externos a nuestro sistema.

Para entender correctamente lo que aquí se hace debe tener nociones básicas de spring, beans,contexto y java.

arquitectura base de una aplicacion java python .net

Arquitectura base de un sistema

Está es una conceptualización de una arquitectura básica para lo que vamos a desarrollar, evolutivamente.

Entorno:

  • MacBook Pro 13”
  • Core i5
  • 8 GB RAM
  • Eclipse (Oxygen.2 Release 4.7.2)
  • Lombok v1.16.20 “Dancing Elephant”
  • Maven 3.5.0
  • JDK8

En el proyecto:

  • Spring Framework : 4.3.14.RELEASE
    • spring-core
    • spring-context
    • spring-tx
    • spring-test
  • MapStruct: 1.2.0.Final
  • Lombok: 1.16.20
  • JUnit: 4.12

Aquí el vídeo mostrando el funcionamiento de esta capa:

Para esta parte cree 3 proyectos con maven para tener la siguiente estructura

  • Dtos (data transfer object – Objeto de Transferencia de Datos)
  • Utilidades
  • UsuariosDao

Cada uno de los proyectos los ejecute con el siguiente comandó de maven:

mvn archetype:generate -DgroupId=mx.rafex.blog.back.dtos \
-DartifactId=Dtos \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

mvn archetype:generate -DgroupId=mx.rafex.blog.back.utils \
-DartifactId=Utils \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

mvn archetype:generate -DgroupId=mx.rafex.blog.back.daos \
-DartifactId=UsersDaos \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

1. bash 2018-03-08 4 p. m.16-45-02

Y a mano cree el siguiente pom, quedando así la estructura:

  • Dtos (Carpeta)
  • Utilidades (Carpeta)
  • UsuariosDao (Carpeta)
  • pom.xml (Archivo)

arquitectura-java-simple 2018-03-08 4 p. m.16-43-37

El contenido del pom.xml es:

eclipse-workspace - BackRafex:pom.xml - Eclipse 2018-03-08 4 p. m.16-21-05

Este pom será el padre y me ayudara a compilar todos los proyectos evitando que tenga que hacerlo uno por uno.

si ejecutamos un mvn clean install en la terminal verán algo así:

1. bash 2018-03-08 4 p. m.16-29-20

Ya que los hemos creado hay que importarlos a eclipse (o el IDE de su preferencia). En la opción de importar de Eclipse, es seleccionar Maven > Existing Maven Projects

Import 2018-03-08 4 p. m.16-47-14

Después seleccionamos la carpeta dónde esta el pom principal y lo veremos de la siguiente manera (cuando descarguen el código de github deberán importarlo de esta manera).

Import Maven Projects 2018-03-08 4 p. m.16-49-04

Ya que tenemos esto explicaré a continuación parte del código.

Aun que los proyectos están “divididos” en proyectos estan juntos por el contexto, ¿Qué quiere decir esto?

los une el nombre del paquete

mx.rafex.blog.back

Y aparte en el contexto de spring en la siguiente etiqueta de xml en el archivo que esta src/test/resources/test-context.xml

eclipse-workspace - UsuarioDaos:src:test:resources:test-context.xml - Eclipse 2018-03-18 2 a. m.2-57-52
Esto hace un escaneo de componentes apartir de ahí

¿Por qué creé el contexto de spring en src/test/resources ?

Precisamente para probar solamente esta parte de DAO que hemos creado, porque en la aplicación final el contexto será cargado en la API Rest que crearemos más adelante.

Para modificar los datos de la conexión es a través del archivo properties que esta en src/test/test.properties

Las consultas de SQL están divididas en dos archivos

mx.rafex.blog.back.daos.sql.mapers.UsuarioConsultas << Aquí solo es texto de la consulta

mx.rafex.blog.back.daos.sql.mapers.UsuarioSqlMaper << La interfaz que usará MyBatis para lanzar las consultas (select,insert,update,etc…)

arquitectura-java-simple:UsuarioSqlMaper.java at parte-1 · rafex:arquitectura-java-simple 2018-03-09 1 p. m.13-08-36

Lo anterior es usando las notaciones de MyBatis que con ellas de manera simple hacemos consultas a la base de datos.

Y la capa de DAO sería

mx.rafex.blog.back.daos.usuarios.IUsuarioDao

Esta es la definición de contrato, que es muy útil cuando trabajamos con más gente podemos subir el código hasta aquí y decirle que el va a usar esta interfaz mientras desarrollamos la implementación

mx.rafex.blog.back.daos.usuarios.impl.UsuarioDao

Aquí va la implementación, la cual es muy simple. A continuación solo explicaré un método y los demás son muy similares.


public UsuarioDaoDto crear(final UsuarioDaoDto usuario) {
 final UsuarioSqlDto usuarioSqlDto = UsuarioDtoMaper.INSTANCE.convertir(usuario);
 final Integer resultado = usuarioSqlMaper.insert(usuarioSqlDto);

if ((resultado != null) && BooleanUtils.toBoolean(resultado)) {
 return UsuarioDtoMaper.INSTANCE.convertir(usuarioSqlDto);
 }

return null;
 }

El principio es el siguiente entre capas deben usar sus DTO’s por la naturaleza propia que pueden llegar a tener, aun que hay lugares que les encanta subir y bajar el mismo DTO entre todas las “capas”. Esa practica no la profeso, pero se puede, a mi experiencia es mejor usar los DTO’s de la capa que corresponde por si requerimos que tenga un “comportamiento” particular a la capa entonces al usar DTO’s entre capas implica “más trabajo” porque hay que crear clases de conversión o mapeo y que muchos las ven como que no agregan valor y son muy laboriosas.

En nuestro proyecto son estas lineas:

final UsuarioSqlDto usuarioSqlDto = UsuarioDtoMaper.INSTANCE.convertir(usuario);
return UsuarioDtoMaper.INSTANCE.convertir(usuarioSqlDto);

Para ello podemos apoyarnos de herramientas como MapStruct, que nos facilitara hacer este “trabajo” de mapeo creando solo una interfaz que en este proyecto esta:

mx.rafex.blog.back.utilidades.mapeos.usuarios.UsuarioDtoMaper


package mx.rafex.blog.back.utilidades.mapeos.usuarios;

import java.util.List;

import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

import mx.rafex.blog.back.dtos.daos.sql.usuarios.UsuarioSqlDto;
import mx.rafex.blog.back.dtos.daos.usuarios.UsuarioDaoDto;

@Mapper
public interface UsuarioDtoMaper {

UsuarioDtoMaper INSTANCE = Mappers.getMapper(UsuarioDtoMaper.class);

@Mappings({ @Mapping(source = "id", target = "identificador") })
 UsuarioDaoDto convertir(UsuarioSqlDto usuario);

@InheritInverseConfiguration
 UsuarioSqlDto convertir(UsuarioDaoDto usuario);

List convertirListaUsuarioSqlDto(List usuario);

List convertirListaUsuarioDaoDto(List usuario);

}

Y lo que hará es que al compilar creara la implementación que la podemos ver a continuación:

UsuarioDtoMaperImpl.class - Java Decompiler 2018-03-09 1 p. m.13-37-32

Y así es como nos ahorramos el “trabajo” del mapeo.

Entonces en resumen nuestro método recibe el DTO de la capa de DAO, lo transforma en un DTO de la capa de MyBatis para ejecutar el método de “insert” que este regresa el identificador de la fila insertada en la base de datos y luego mapeamos el DTO de MyBatis al DTO de DAO y listo.

Ahora la parte de los TEST, pues es simple al usar el arquetipo de Maven QuickStart genero una estructura similar a esto:

project
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- $package
| `-- App.java
`-- test
`-- java
| `-- $package
`-- AppTest.java

en los test hay que usar unas notaciones “especiales” por el tema de que estamos usando spring y requerimos levantar un contexto para que funcione correctamente.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:test-context.xml" })

La segunda notación es dónde especificamos de dónde va a cargar el contexto, aparte hay que extender de la clase AbstractJUnit4SpringContextTests para poder traer el applicationContext y poder usar nuestros beans hechos en spring.


@Test
public void validarQueElBeanNoSeaNulo() {
final IUsuarioDao bean = (IUsuarioDao) applicationContext.getBean("usuarioDao");
Assert.assertNotNull("Error al crear el contexto y el bean es nulo", bean);
}

@Test
public void obtenerTodosLosUsuarios() {
final IUsuarioDao bean = (IUsuarioDao) applicationContext.getBean("usuarioDao");

final List listaUsuarios = bean.obtenerTodos();

Assert.assertNotNull(listaUsuarios);
Assert.assertFalse("Hubo un error al traer los usuarios", listaUsuarios.isEmpty());
for (final UsuarioDaoDto usuario : listaUsuarios) {
System.out.println(usuario.toJson());
}
}

La anotación @Test será lo que ocuparemos de JUnit y la clase Assert para poder validar los resultados. Como pueden ver los test son para probar únicamente esta capa de DAO, validando que realmente funciona la interacción con la base de datos así como la transformación de objetos (mapeos) y la poca lógica que tiene esta capa.

El tiempo estimado de todo esto para un Jr serían 6 hrs., para un Sr serían 2 hrs.

Espero que esta primera parte haya quedado explicada y si tienen dudas con gusto las resolveré en los comentarios o correo electrónico. Y recuerden continuara…

Pueden ver que compila y los test funcionan en Travis-ci

Descargas:

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

w

Conectando a %s