Saltar al contenido

Categoría: Spring

Crear Excel con Apache POI y Spring Boot

Bueno, tuve que dejar un par de semanas de hacer post por que me acumule de trabajo y quería tocar este tema por que es algo que me parece muy útil para quien le toque ver temas referidos a la generación de excel con Spring boot o en general con java. Y para serles franco el código en este post no va a ser pequeño, por lo que hacer una demo que yo considero útil para varios posibles escenarios con los que se van a encontrar en algún trabajo y proyecto me tomo unas cuantas horas por lo que me demoro el desarrollo del post.

Espero que lo que revisemos y el código y video que deje les sea de provecho por si llegan a tener algún escenario como el que voy a plantear para iniciar con la explicación.

Escenario

Digamos que en su trabajo/freelo/proyecto personal, quieres realizar la generación de un excel. El modo más sencillo sería empezar a definir las columnas que va a tener y así ir dándole la forma al excel. Sin embargo, si queremos que este sea dinámico. Digamos que necesitamos un componente al cual le pasamos una estructura de datos y este nos genera un excel formateado y demás. Claro que el nivel de customización dependen de lo que se busque, pero un caso similiar tuve hace unos días en el trabajo y fue divertido por que me permitió aprender más sobre la librería en la cual me baso para esta demo, Apache POI, es de seguro ya conocida por mucho en el mundo de Java, teniendo en mente lo que acabo de plantear, veamos como esta distribuida nuestra demo.

Distribución del Proyecto

Distribución del Proyecto
Distribución del Proyecto

Como pueden ver en la imagen, tenemos las siguientes capas:

  • Controller: Exponemos nuestro endpoint
  • Model: Nos permitirá manejar de manera genérica la información de nuestro excel.
  • Service: Ejecutamos la lógica para la generación del excel.
  • Transversal: Son funciones que podremos usar a lo largo de la aplicación.
  • Util: He creado varias funciones que nos permitán manejar mejor ciertos casos que se pueden presentar en la generación de un excel (formato de decimales, fechas, etc).
  • Resources; Parte propia de spring, acá de ubica el yml de configuración. Sin embargo, también estoy poniendo el json del cual vamos a partir para generar el excel.

Revisemos ahora que tenemos en cada uno de los componentes:

Controller

End-point para obtener el reporte
End-point para obtener el reporte

Como pueden ver, estamos devolviendo a la petición GET un objeto del tipo Resource. Esto lo hacemos por que nuestro end-point retorna un array de bytes e indicamos en el header el formato del excel, en el key «Content-Disposition», además, de indicarlo en el content-type del response. En el siguiente post voy a explicar como se descargaría este excel desde una aplicación de angular sencilla.

Model

Información de las columnas
Información de las columnas
Información de las filas
Información de las filas

Sólo usaremos estas dos clases para manejar toda la información que queramos renderizar en nuestro excel, cuando revisemos las otras capas veremos como dinamicamente vamos generando el excel. Notese, que «Field» me permite mapear los campos que obtengo de base, por su nombre, descreipción y tipo de dato que como vemos es un enum. Estoy usando lombok para no llenarme de codigo de inicialización de las clases y demás.

Service

Método que se consume desde el controller
Método que se consume desde el controller

Este método es el que nos retorna el objeto Resource y por lo tanto es el se encarga de llamar a los otros métodos que nos permiten generar el excel. Antes de explicar que hace cada uno de estos métodos, comentar que «data» y «columns» básicamente están leyendo los json que tenemos en resources y los están parseando a un objeto con un método creado en utils que me permite hacer esto. Veamos que hacen los otros métodos:

generateFieldsReport:

Creación de la lista de Field
Creación de la lista de Field

Recorremos la lista de información de columnas para generar una lista de fields. Acá estamos usando el enum para determinar de que tipo de cada es cada columna de nuestro excel. Esto lo usaremos para el formato en un paso posterior.

buildCellTypes:

Obtenemos todos los tipos de datos que tendrá nuestro excel
Obtenemos todos los tipos de datos que tendrá nuestro excel

Obtenemos todos los tipos de datos que tendremos en nuestro excel.

buildDataLines:

Generamos un listado de array de string que es la información que ira en nuestro excel
Generamos un listado de array de string que es la información que ira en nuestro excel

En este método basicamente estamos obteniendo la información que va a llenar nuestro reporte de excel, en base al tipo de datos que ya obtuvimos estamos dándole el formato al cuerpo del excel en cada una de las columnas. Como se puede ver, estamos recibiendo la lista de maps que obtuvimos de la base de datos (nuestro json para nosotros).

createXlsxFileAsByteArray:

Generación del excel parte 1
Generación del excel parte 1
Generación del excel parte 2
Generación del excel parte 2

Finalmente, en esta capa, el método en el que ya trabajamos con Apache POI, acá generaremos el excel y lo convertiremos a un array de bytes. Empezamos creando un objeto del tipo «SXSSFWorkbook», dentro de este definimos un «Sheet» que es la hoja sobre la que trabajaremos, le ponemos el nombre que queramos. Las siguientes lineas me sirven para darle el formato de fecha a los campos que correspondan, lo defino a este nivel por que si se van creando conforme se recorren las filas de excel, se genera una excepción si nuestro excel tiene mas de 10 mil filas, dado que si definimos más de 10 mil objetos del tipo «CellStyle» en un mismo excel apache poi lanza una excepción. Empezamos a recorrer nuestro «dataLines» que si mal no recuerdan es donde se pusimos todo el contenido de nuestro excel y uno a uno vamos a hacer validaciones sobre cada fila, en la primera iteración no hacemos mayores validaciones por que es la cabecera solo seteamos esta cabecera y le damos cierto formato, a partir de aqui si nos vamos a valer de un switch por el tipo de datos para darle el formato de corresponda. Para finalizar, escribimos toda la información de nuestro workbook en nuestro objecto «ByteArrayOutputStream» y retornamos nuestro método con un «toByteArray()».

Ya en este punto, tenemos el bytes de array para devolver en el end-point. Las demás funciones utilitarias que se usan en el proyecto (leer el json, formatear decimales, fechas, etc) no las voy a explicar en el post por que sería extenderlo más y de por si ya a quedado muy amplio.

REPO GITHUB

Saludos

Deja un comentario

Spring Boot con Docker

Bueno, cada ves es más frecuente que los proyectos tengan todo un pipeline de devops para sus releases. He incluso, que en los lugares donde trabajan o en los proyectos que desarrollen tengan integrado ambientes con docker en los mismos proyectos. De manera tal, que puedan tener un ambiente de trabajo en el que se tenga la certeza que no se tiene algún factor adicional y que todos están trabajando en el mismo ambiente.

Tal ves resulte un poco dificil de comprender por que es esto importante. Pero creanme cuando les digo que puede ser un dolor de cabeza levantar algunas aplicaciones. En este post quería mostrar como podemos configurar nuestro ambiente de desarrollo con spring boot usando devtools.

Pensando en esto, es que me plantee la pregunta como integrar spring boot con docker. La meta de este post sería tener un proyecto web api con spring boot que que nos permita tener un ambiente configurado y desplegado en nuestro container. Y que al hacer cambios en nuestro proyecto, podamos ver los cambios en nuestra imagen docker sólo con la realización de un build.

Empezamos usando spring initializer para generar un proyecto base, sólo le pondremos las siguientes dependencias:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

Creamos un controlador en nuestro proyecto, sólo la demo.

Controlador para probar la actualización

Indicamos el puerto en el que queremos que nuestra aplicación funcione, esto lo hacemos poniendo en el «application.yml» la siguiente propiedad:

server:
  port: 8055

Sólo añadiendo la dependencia de devtools, tenemos acceso a ciertas funcionalidades en nuestra aplicación. Como por ejemplo, que nuestra aplicación mumestre los cambios que realizamos sin necesidad des volver a parar el debugging e iniciarlo, es algo parecido al live-realoading que tenemos con webpack. Provemos esto, y luego nos metemos de lleno a la configuración de con docker.

Probando el api inicialmente
Build al cambio que hemos realizado
Probamos el api nuevamente, visualizamos el cambio

Acá viene la magia de spring, para poder dockerizar nuestra aplicación sólo debemos de ejecutar un comando en la carpeta raiz de nuestro proyecto.

mvnw spring-boot:build-image

Esto, nos generará una imagen docker en nuestro equipo (obviamente antes debemos de tener instalado docker) con el nombre que hemos definido para nuestro proyecto. Para la demo sería del modo siguiente:

Nombre proyecto

De modo, que si ejecutamos el comando «docker ps», tendríamos un resultado similar a este:

Imagen creada

Es posible que la primera ves que ejecutan este proceso tome un poco de tiempo, dado que esta bajando la imagen base por primera ves.

Para poder correr nuestro proyecto en la imagen docker, tenemos que ejecutar el siguiente comando.

docker run --tty --publish 8055:8055 demo:0.0.1-SNAPSHOT

Hasta este punto, tenemos nuestro proyecto dockerizado. Pero que pasa con el live reloading? Bueno, nos toca realizar algunos pasos adicionales. Primero, en nuestro archivo de configuración yml debemos añadir la siguiente configuración.

spring:
  devtools:
    remote:
      secret: wgutierrez

Luego de esto, debemos de añadir una configuración adiciona en nuestro POM, veamos como estaba antes, y como debería de quedar.

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

Tenemos que añadir una configuracion al plugin para que no excluya dev tools.

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!--PARA PODER ACTUALIZAR EL PUBLICADO SOLO COMPILANDO-->
                <configuration>
                    <excludeDevtools>false</excludeDevtools>
                </configuration>
            </plugin>
        </plugins>
    </build>

Y finalmente, debemos añadir una nueva configuración para nuestro run/debug.

Configuración del run/debug

Es importante, mencionar que la clase:

org.springframework.boot.devtools.RemoteSpringApplication

La usamos por que nos permite tener un filewatcher, que detacta los cambios en nuestro proyecto y los replica en nuestro container. Además, tenemos también que indicar la url con el puerto que hemos configurado en nuestro proyecto.

De este modo, me parece que tenemos el panorama más claro sobre como podemos tener un proyecto spring boot con docker. Dejo el link y el repo del video.

REPO GITHUB

Saludos.

Deja un comentario

SQS en AWS con Spring Boot – Parte II

En el post pasado, revisamos que es una cola cuando hablamos de desarrollo, en que casos nos puede servir y que alternativas encontramos en el mercado para poder usarlas. Puntualmente, hicimos una demo de el uso de esta herramientas con SQS que es un servicio ofrecido por AWS. Sin embargo, buscando no extender el post y la demo demasiado conforme iba avanzando el post anterior, decidí que era mejor dividirlo en dos partes. En la primera, revisamos como crear desde AWS un usuario con los permisos necesarios para conectarse a una cola, en código con un proyecto hecho con spring boot conectarnos a esta y poder enviar mensajes.

En esta segunda parte, revisaremos como podemos suscribirnos a una cola, y estar a la escucha de nuevos mensajes.

Para poder conseguir esto, y no estar llenandonos de proyectos voy a usar el mismo proyecto en spring boot de la ves pasada, con la diferencia que creare algunos nuevos componentes, la idea basicamente es consumir una api desde un controlador, esta encola el mensaje y en un listener recibirlo e imprimirlo en consola.

Veamos que hemos añadido en nuestro proyecto inicial.

POM

Nuevas dependencias en el POM
Nuevas dependencias en el POM

JmsConfiguration

Clase de configuración del JMS
Clase de configuración del JMS

SqsListener

Clases del SqsListener
Clases del SqsListener

Con lo añadido en nuestro POM, tenemos acceso a clases de configuración que nos permitirán configurar un listener para las colas que ya tenemos definida en SQS. Si vemos a detalle la clase de configuración que hemos creado, tenemos lo siguiente:

Configuración en el JmsListener
Configuración en el JmsListener

En esta clase, como podemos ver, estamos creando un factory para las conexiones a AWS esto en el método «sqsConnectionFactory» y adicionalmente, configuramos nuestro listener factory para estar a la escucha de nuestra cola definida en AWS.

Como ven, tenemos que indicar que esta clase es de configuración con @Configuration, además de indicarse que habilite el JMS con @EnableJms. Sólo para aclarar por si hubiera alguna duda, JMS son las siglas de Java Message Service que es una clase definida en la librería JMS que nos permite realizar la creación y suscripción de mensajes a través de una cola.

Y finalmente, tenemos que crear nuestro listener, esto lo hacemos del siguiente modo:

SqsListener
SqsListener

Creamos una clase y dentro creamos un método void con las siguientes anotaciones «@JmsListeners» que tiene dentro un «@JmsListener». Es necesario dentro de esta última anotación indicarle cual es el nombre de la cola que vamos a estar a la escucha en nuestro listener.

Hagamos una prueba de todo junto.

Primero realizamos el consumo de nuestro controlador con una mensaje cualquiera.

Consumiendo el API
Consumiendo el API

Recibimos el mensaje en nuestro controlador.

Recibiendo el mensaje en el controlador
Recibiendo el mensaje en el controlador

El mensaje es enviado a nuestra cola previamente configurada en SQS.

Se genera el mensaje correctamente
Se genera el mensaje correctamente

Mensaje encolado en SQS.

Mensaje en SQS
Mensaje en SQS

Ahora, segundos despues de que se encoló el mensaje, debería llegar a nuestro listener que esta escuchando la misma cola «SqsTest».

Recibimos el mensaje
Recibimos el mensaje
Log del mensaje
Log del mensaje

Con esta prueba concluye este post. El código lo subire como una actualización al proyecto anterior. Espero que les sirva, como ven es sencillos tener un manejo de colas funcional con sólo un poco de código. Dejo el link del repo y el video.

REPO GITHUB

Saludos.

2 comentarios

SQS (Manejo de Colas) en AWS con Spring Boot – Parte I

Hola, hace ya algún tiempo desde el último post, la verdad es que la cuarentena nos a permitido a todos tener más tiempo con la familia, pero también a los que nos dedicamos al desarrollo de software nos hemos cargado de trabajo. En mi caso, especialmente por que mi familia tiene un colegio y he tenido que asumir la migración a la enseñanza virtual.

Bueno, vamos al tema que nos reclama este post, en el proyecto en el que me encuentro trabajando he tenido la oportunidad de meterme a bucear por distintos servicios de AWS que estamos usando en la arquitectura. Este proceso a sido desafiante y de mucho aprendizaje, y quiero plasmar en una serie de posts mi exploración a los servicios de AWS. Empezando por el servicio de SQS que es basicamente un encolador de mensajes, sólo que es la alternativa que nos ofrece AWS. Deben ya de conocer algún servicio similar a estos, que yo recuerde ahora uno con el que hice una pruebas era RabbitMQ, que era un software open source que tenías que instalar en tu pc o en el servidor en el que lo quisieras usar y te permitia generar las colas y suscribirte a ellas, y realizaba el manejo de los mensajes que ibas encolando.

Me parece importante detallar un poco bajo que condiciones es necesario usar este servicio. Usualmente, cuando tenemos varios microservicios (puede entendeser como varias APIs), entrar a detallar de las caraterísticas que la hacen un microservicio va a extender mucho el post así que dejemoslo ahí. Pero cuando queremos que estos se comuniquen, podemos directamente hacer una solicitud http entre ellas y de ese modo la solicitud sería instantanea. Sin embargo, que sucede si son miles de peticiones, si alguna se cae o si se satura el microservicio que estamos consumiendo, como tener un control en la llegada de estas peticiones.

Teniendo en cuenta esto, es que entran a tallar soluciones de encolación de mensajes. Dado que nos permiten enviar mensajes (peticiones) a una cola que tengamos definido (inclusive definirla en tiempo de ejecución) y luego el suscriptor a esa cola va a ir desencolando los mensajes y procesandolos uno a uno. Del modo más básico esto es lo que se consigue usando este tipo de herramientas y amazon nos provee este servicio con SQS.

Entonces, ya teniendo claro para que podemos usarlo, veamos como se implementó. Primero debemos de tener una cuenta de AWS creada, en este punto quiero aclarar que si bien todos los recursos que voy a crear puede ser hechos desde un json y luego deployados con cloudformation en AWS o desde el AWSCLI, yo voy a usar la web de amazon por que me parece que es la forma más simple de hacerlo y a propositos de esta demo me sirve más. Con la cuenta que debemos tener, es necesario ir a IAM y crear un usuario que tenga asignado el siguiente rol:

Creacion de usuario
Indicar permisos

Luego no olviden copiar el access-key y secret-key que nos va a brindar IAM. Ahora veamos el proyecto en spring que hemos creado.

Usaremos las siguiente dependencias, en el POM:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-aws-messaging</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
Estructura del proyecto

He dividido de módo básico en capas el proyecto, quedando del siguiente modo:

  • Controller: Y sabemos para que es esta capa.
  • Service: Para ejecutar la lógica que necesitemos.
  • Configuration: Para realizar la configuracion inicial de aws.
  • Infraestructure: Acá ejectuamos las acciones en las librerias externas que usemos.

Nuestro controlador, es un endpoint que recibe una path variable que sera lo que encolaremos.

Controller

En nuestro service, llamamos a nuestra capa infraestructure para pasarle nuestro mensaje y que realice en encolado, estamos devolviendo un objeto anonimo, que indica si se registro correctamente, el mensaje que se a encolado y el uuid que nos retorna aws cuando generamos el encolado.Veamos que hace el método marcado.

Service

Como pueden ver, preparamos el objeto que vamos a encolar, estamos usando un ObjectMapper para convertir el objeto que recibimos (en nuestro caso un string) a un formato json y esto encolarlo. En este punto, también indicamos cual es la URL a la cual se dedbe encolar, la cual obtuvimos en el service por injección de dependencia directamente desde nuestro archivo yml.

Infraestructure

Revisemos que configuración tenemos en nuestro «AwsConfiguration». Como pueden ver, por injección de dependencia obtenemos el accesskey y secretkey que hemos generado al iniciar todo y los seteamos en el «BasicAWSCredentials» que luego usamos para generar un objeto del tipo «AmazonSQS», que es el que nos permite encolar la información entre otras cosas.

AwsConfiguration

Mientras realizaba el desarrollo del post, me di cuenta que hacer el listener de esta cola en este post iba a hacer que sea demasiado extenso. Por lo que termine decidiendo que en el próximo entrare a cubrir este detalle. Espero que les sriva y si tienen alguna duda pueden contactarme por alguno de los medios que he dejado, ver el video o revisar la documentacion oficial de AWS que es muy buena y completa.

Documentación Oficial

REPO GITHUB

Saludos

Deja un comentario

Buenas Practicas Logging

En este post, me dedicaré a explicar que buenas practicas en logging se deben seguir cuando desarrollamos una aplicación web, que quede claro que este es un enfoque personal, que he podido formular con cierta experiencia.

Por otro lado, es necesario comentar que si bien es cierto el ejemplo en cuestión, lo voy a realizar usando Spring boot, la información que se debe obtener para enriquecer el log, puede variar de acuerdo a la tecnología que se va a usar (Net Core, Framework, Node, etc).

Empecemos primero, explicando un poco sobre los niveles de logging que se tienen y en qué caso es necesario usar uno u otro.

Niveles de Logging

Como se puede ver en la imagen, el logging no solo sirve para capturar errores (lo cual es fundamental en el proceso de desarrollo y para el posterior soporte a las aplicaciones), sino también para determinar que feature es el más usado, información de configuración de la aplicación, entre otras.

Por otro lado, el logging se puede desarrollar en múltiples appenders (este nombre es usado en log4j o log4net), como una buena práctica es necesario que como mínimo se realice el grabado del log en dos appenders, siendo una de estos la base de datos y el otro un archivo de texto, en una ruta en específico (pudiendo ser dentro de la solución desplegada). Basicamente en este post me enfocaré en explicar la información que se debe guardar en un log de error (FATAL y ERROR). La información que vamos a considerar es la siguiente:

  • Fecha y hora del log
  • Nivel del log (FATAL, WARNING, etc)
  • Mensaje
  • Stack de la excepción
  • Payload (en caso que la consulta sea un GET, DELETE se debe obtener la información enviada en el url, de ser un POST, UPDATE, PATCH El body)
  • Callsite (el endpoint que es consumido que en el cual se termina generando el error)
  • La acción bajo la cual se produce el error (nombre del método en el controlador)
  • El usuario con el cual se produjo el error.
  • El nombre del método en el cual se generó el error (de la capa de lógica de negocio)
  • El nombre de la aplicación en la cual se generar el error (varía de solución en solución)

Claro, que de acuerdo a qué librería se este usando para realizar este grabado del log es posible tener todo tipo de appenders, uno que me llama mucho la atención es el que nos permite enviar esta información a herramientas como elastic search y luego al integrarlo con otras herramientas como grafana para generar reportes.

En nuestra aplicación demo, nos valdremos que ciertas características del framework para poder tener acceso a la información antes detallada.

HandlerInterceptorAdapter

Al implementar esta clase abstracta y hacer un override al método preHandle tenemos acceso en el pipeline del framework, además de anotarla como «Component». Como podemos ver en la siguiente imagen.

Implementación del override del preHandle

Como podemos ver, nos valemos del HttpServletRequest para tener acceso a mucha información necesaria para enriquecer nuestro logging, detallemos cada uno de los puntos que nos servirán:

  • La url a la cual se está consultando la obtenemos con el método «getRequestURI».
  • Para obtener el nombre del método, nos valemos de una pequeña lógica que obtiene el indice del último luego del «/» y con esto hace un substring para poder obtener el último texto.
  • Para el hostname de la máquina, nos valemos de la librería «java.net.InetAddress».
  • Es necesario validar si la petición es del tipo «GET» para de este modo obtener los query params que se esten enviando. Si este fuera el caso usamos «getQueryString» para este fin.
  • Obtenemos un parámetro denominado «username» que se está enviando en cada una de las peticiones, sea cual sea el método http, esto con la finalidad de guardar el usuario al cual está vinculado el log. Para esto tenemos opción de guardarlo en sesión en el caso nuestra solución sea del tipo MVC, pero al tener un Web API no es posible. Podrían usar un interceptos en angular (de ser este su caso) para que a cada una de las peticiones le adicione este parámetro.

Con esto, cubrimos en cierto aspecto la información que necesitamos para nuestro logging. Sin embargo, tenemos que considerar también las solicitudes http del tipo POST, y que por lo tanto tienen un body.

RequestBodyAdviceAdapter

Nos valdremos de esta clase abstracta, y especificamente en nuestra implementación haremos el override de «supports» y de «affterBodyRead» como podemos ver en la siguiente imagen:

Override de métodos en la implementación de HandlerInterceptorAdapter

Además, es necesario decorar la clase con la etiqueta «ControllerAdvice». Veamos que información obtenemos de este método:

  • El payload del body, el cual obtenemos del Object que se recibe de «afterBodyRead», en mi caso se hace un «toString» dado que en las clases implementadas se está haciendo un override a esté metodo para darle la forma de json, como podemos ver en la siguiente imágen.
Override del «toString» en la clase

Además, es muy importante en nuestro logging tener grabadas en nombre del método en el cual se realizo la caída del sistema. Este método puede estar en el stack de la excepción, pero para tenerlo directamente me estoy valiendo de una característica propia del framework, la cual se denomina «aspects» en spring, en algún otro post me dedicaré a explicar los tipos que hay y como se ejecutan en detalle, en este post sólo presentaré como se están usando.

Aspects

Spring nos brinda una herramienta muy potente, la cual es denominada programación orientada aspectos, lo cual en pocas palabras, puede facilitarnos la vida en múltiples escenarios y evitarnos repetir código innecesariamente. Veamos la siguiente imagen:

Implementación de un aspecto

Se creo un aspecto y se decoro con las etiquetas «Aspect» y «Component» para que se registre por el framework, lo que nos permite un aspecto es que esta sección de código de ejecute en ciertas condiciones. Para el caso, se llevará a cabo en la siguiente sintaxis:

«* com.project.loggingdoitright.service.implementation.*.*(..)»

Lo cual nos indica que el aspecto coberturará todos los métodos que se encuentren en el paquete «implementation» que tengan cualquier nombre (veamos los *.*), que tengan cualquier tipo de entrada (veamos los dos puntos dentro de los paréntesis) y el asterisco inicial, indica que coberturará cualquier tipo de devolución. Como variable de entrada de nuestros aspectos tenemos a la clase «JoinPoint», la cual posee varia información interesante, para lo que necesitamos usaremos «getSignature().getName()» que nos brinda el nombre del método en el cual se registra el error y el cual llama nuestro aspecto.

Finalmente, para realizar el grabado del log y generar un identificador único del log, el cual debe ser proporcionado al usuario del aplicativo. Para esto, usamos algo que ya se explicado antes. Un «ControllerAdvice», el cual actua como interceptor de los errores.

Finalmente, veamos como queda nuestro registro del log.

Divido la fila asi, para que se pueda visualizar mejor.

Finalmente, puede visualizar el video correspondiente a este post, donde se detalla paso a paso el funcionamiento de la aplicación, así como su prueba consumiento las APIs desde postman.

Espero que les haya sido de ayuda, como siempre dejo el código del proyecto en el repositorio.

REPO: GITHUB

Saludos.

Deja un comentario

JWT en Spring Boot y Spring Security

Hace poco tiempo participe en una hackaton con unos amigos, y cuando empezamos a desarrollar ya la aplicación luego de haber analizado lo que se buscaba solucionar, yo me valí de una plantilla en spring que había estado trabajando en mi tiempo libre, era la primera ves que la ponía a prueba en un escenario real y el sentido era que ahorraramos tiempo en configurar cosas que siempre son necesarias en todos los aplicativos. Para resumir un poco esta parte, la plantilla se porto como debía. Esta experiencia me lleva a realizar este post, en el que voy a explicar como se configura spring security y la autenticación en base de datos, además de que configurar para poder usarlo con una aplicación SPA del lado del frontend, como puede ser Angular, React, Vue.js entre otras.

Como deben de saber spring security es la librería de spring que nos brinda una visión dogmática de como se debería de implementar la seguridad en una aplicativo. Esto, claro siguiente todo un marco de buenas prácticas que muy probablemente si quisiéramos implementarla de 0, tranquilamente puede ser un proyecto entero sólo para esto. Gracias a esto, es que nos permite ahorrarnos mucho tiempo y nos brinda la seguridad de que estamos siguiendo un marco de buenas prácticas. Para nuestro caso, usaremos json web token (jwt) el cual es una de las alternativas que tenemos para implementar la autenticación.

Nuestra aplicación demo consta de distintas capas, ampliamente explicadas en post anteriores, tenemos un archivo de configuración «application.yml», en la sección «security» hemos definido cierta información importante, entre las cuales está:

  • La url del enpoint de autenticación.
  • El tiempo máximo de expiración de un token.
  • La llave secreta que se usará para poder generar el JWT.

Se ha definido un paquete de configuración, y dentro de este un paquete de jwt, en el cual se tienen distintas clases necesarias para configurar, como es obvio en el pom del archivo se están añadiendo las dependencias de spring security.

Dependencia en el POM
Clases de configuración

Tenemos un controlador llamada «SecurityController», en el cual tenemos los diferentes endpoint:

  • Authenticate [POST]: Nos permite iniciar sesión en el sistema, retorna el token.
  • Refresh [GET]: Permite refrescar el token que se ha generado, antes de que expire.
  • Create [POST]: Permite crear un usuario.

Tenemos en la capa service de nuestro aplicativo un «SecurityService» que es donde se realiza la lógica necesaria para autenticarse, refrescar el token y el crear un nuevo usuario, Por otro lado, en el repository, respetando el principio de single responsability tenemos tres clases (Person, Session y User) para el acceso a la base de datos.

El esquema de base de datos que vamos a usar es el siguiente:

Modelo E-R usado

Vamos a usar una clase a modo de helper, donde tendremos varios métodos utilitarios que nos van a permitir obtener información del token que generemos e incluso generarlo. Esta clase se llamará «JwtUtil».

Métodos en JwtUtil

Luego es necesario crear una clase que extienda de «OncePerRequestFilter», en el cual podamos hacer un override al método «doFilterInternal», en le cual haremos un filtro a las peticiones que recibamos para determinar si poseen token o no y que acciones se deberían tomar. Esta clase la llamaremos «JwtTokenAuthorizationOncePerRequestFilter» y luego veremos donde debemos configurarla para que este filtro se lleve a cabo.

Clase JwtTokenAuthorizationOncePerRequestFilter

También es necesario crear un clase que extienda de «AuthenticationEntryPoint» para poder hacer un override del método «commence», el cual será llamado cuando se determine que ser esta intentando acceder a un endpoint que requiere que se le pase un header de authorization. Esta clase, llevará el nombre de «JwtUnAuthorizedResponseAuthenticationEntryPoint».

Clase JwtUnAuthorizedResponseAuthenticationEntryPoint

Finalmente, toda la magia ocurre en nuestra clase SecurityConfiguration, la cual extiende de «WebSecurityConfigurerAdapter», en esta realizamos múltiples configuraciones que son propias de spring security, Entraremos al detalle de algunas en el post, pero en el video me daré más tiempo para explicar la configuración de esta clase. Uno de los override es al método «configure», considerando que este método en la clase de la que estamos extiendo tiene varios overloads, el que explicaré en el post es el que posee como parametro de entrada un «HttpSecurity», en debemos realizar las siguientes configuraciones:

  • Deshabilitar el CSRF
  • Indicar que authentication entrypoint (acá usamos nuestra entrypoint personalizado).
  • Indicamos que no usaremos sesiones, esto cambiando la configuración de «sessionCreationPolicy».
  • Configuramos el CORS, para que permita todos los tipos de peticiones (GET, POST, DELETE, UPDATE, etc).
  • Añadimos el filtro que personalizamos anteriormente, esto con el «addFilterBefore».
Clase SecurityConfiguration

Finalmente, revisemos nuestro «SecurityController»:

SecurityController

Realizemos algunas pruebas en postman de los distintos métodos.

  • Usuario: wgutierrez
  • Contraseña: $2a$10$3zHzb.Npv1hfZbLEU5qsdOju/tk2je6W6PnNnY.c1ujWPcZh4PL6e

Petición:

Solicitud al Authenticate endpoint

Respuesta:

Respuesta el Authenticate endpoint

Como se puede ver, se nos ha generado un token, si vamos a una página como jwt.io y ponemos el token que ha sido generado, tenemos la siguiente información:

Información del token generado

Los métodos de refresh y creación, pueden verlos a más detalle en el video que como de costumbre cuelgo con los post. Espero que les haya sido de ayuda, si tienen alguna duda les dejo el correspondiente repositorio en github, y los medios de contacto correspondientes.

REPO: GITHUB

Saludos.

Deja un comentario

Crear web con Thymeleaf y Spring boot

Esta semana, me consultaron por las alternativas que se tienen en Spring para implementar el patrón MVC del lado del frontend, de las múltiples formas que se tienen, la que más me llama la atención es thymeleaf dado que es lo más cerca a código html puro. En este post quiero explicar como podemos crear un proyecto con spring, en el que useamos thymeleaft para el desarrollo de las vistas, añadiendo contenido estático (js, css) a nuestra web y consumiendo una base de datos como postgres usando jdbc.

Como indico en el parrafo anterior, en este post usaremos las siguientes herramientas:

  • Spring initializr
  • Spring JDBC
  • Spring Web Started
  • Thymeleaf
  • Lombok
  • PostgreSQL

Nuestro proyecto en cuestión, consiste en la realización de una página web donde podemos visualizar los logs que se generen en una aplicativo, siendo estos de los distintos tipos que existen. El proyecto en cuestión es uno personal que tengo en mente y pienso desarrollarlo en conjunto con una serie de post, se me hace interesante por que me permitirá agrupar el logging de diversar aplicaciones. Soy consciente que actualmente existen herramientas que brindan esta información con dashboards muy completos entre otras ventajas. Pero, no me negarán que existe una mistica especial en crear algo uno mismo desde cero. Además quiero que en esta aplicación también se pueda visualizar las consultas que se efectuan al motor de postgres, siendo este un simil al SQL Profiler que tenemos en SQL Server, he buscado exhaustivamente alguna alternativa que me permita conseguir esto y no la he encontrado, motivo por el cual me plantee generar una por mi mismo, siendo consciente que muy probablemente no tenga todas las características inicialmente que podemos encontrar en la herramientas de microsoft. Volviendo al post que nos reclama, iniciaremos creando un proyecto de la siguiente manera:

Creación del proyecto con Intellij IDEA
Selección de las dependencias

Con el proyecto creado, replicamos la estructura ya antes mencionada para el repository, service y controller. Me dedicaré a explicar como se configuran los archivos estáticos y la demás configuración correspondiente a la integración con thymeleaft.

Debemos copiar los archivos que vamos a usar en la siguiente ruta de nuestro proyecto:

Ubicación de los archivos estáticos

Para nuestros archivos html, creamos una carpeta shared en la que pondremos archivos como el header o el footer de nuestra aplicación, esto será usado como fragment en nuestras demás vistas. Para este primer post, sólo creare el «index» de nuestra aplicación en donde desarrollare una solicitud para llenar un combo con información de base de datos y la realización de un post.

Ubicación de los HTML del proyecto

En el header, importaremos las dependencias css y js. Además de realizar ciertas configuraciones para poder usarlo como fragment en nuestras demás vistas.

Importar estilos con thymeleaft:

<link rel="stylesheet" 
          th:href="@{/lib/plugins/daterangepicker/daterangepicker.css}">

Importar javascript con thymeleaft:

<script th:src="@{/lib/plugins/jquery/jquery.min.js}"></script>

Configurar una sección HTML en el header para ser llamada como fragment:

Configuración como fragment

Como se puede ver, se indica que es un fragment y se le asigna un nombre por el cual será llamada, el html en cuestión es un loader a ser usado en las demás páginas html cuando carguen.

En el controlador, cuando trabajemos con MVC, es necesario usar la notación «@Controller» en lugar de «RestController» que usabamos cuando trabajamos con APIS. el primer controller a crear es el index y posee la siguiente estructura.

Creación del controller que dirije al index

Como se ve, es un controller del tipo string, y debe retornar el nombre del html, para nuestro caso «logger». Es necesario que nuestro index tenga el tipo de entrada «Model» que es una clase propia del framework que nos permite indicarle a la vista los atributos con los cuales trabajará. Como podemos ver, estoy declarando un atributo con el nombre «search» que es del tipo «SearchLog» que es una entidad que posee los siguientes campos:

Entidad SearchLog

Los campos que estén dentro de nuestro formulario html, deben tener los mismos valores definidos para nuestra entidad «SearchLog». Además, se añaden otros dos atributos, que contienen las listas de nombres de las máquinas en las cuales se generaron los logs y los nombres de las aplicación de las cuales se tiene log registrados. En la vista «logger», se tiene la siguiente configuración:

Llamada al fragment:

Llamada al fragment head desde el logger

Como se puede observar, hago un insert del fragment, indicando la ubicación del archivo que lo contiene y el nombre que le indicamos.

Configuración del form:

Configuración del form

En este «form» es importante notas que se está indicando la acción a la cual debe dirigir «/search», el objecto que contiene que lleva el nombre «search» y si ven el post lineas arriba es el nombre que le indicamos en el model e indicar que es del tipo post. Por otro lado los campos contenidos en el form, poseen los nombres exactos que se definieron en la entidad y finalmente, para la lista que se devuelve, se itera sobre esta y se esta indicando en el valor y el texto a desplegar el mismo valor que es el nombre.

En el controlador tenemos que definir un método post con nombre «search», quedando de la siguiente manera:

Controlador «search»

Es necesario definir como entrada de nuestro controlador un «@ModelAttribute» que debe ser del mismo tipo que definimos en nuesto model y del que posee nuestro form, para que pueda ser mapeado correctamente. Finalmente, llenamos los datos en nuestra entidad.

Llenado de datos en nuestro formulario

Presionamos el botón «search» y deberíamos llegar a nuestro método post con variable de entrada «SearchLog» y los campos que hemos ingresado.

Llegada de la información al controlador correctamente

Como podemos ver, es relativamente sencillo configurar y empezar a trabajar con thymeleaft, en otros post explicare la integración que podemos realizar con spring secutiry y sessions usando esta herramienta. Espero que les haya servido, como en los otros post dejo el link al repositorio de github del proyecto y el video.

REPO: GITHUB

Saludos.

Deja un comentario

Grabar log de errores en db y archivo con Spring Boot

Llevo ya algunas semanas revisando cursos sobre Spring, como he mencionado en publicaciones anteriores, el trabajo me lleva a desarrollar más en tecnologías de Microsoft. Sin embargo, conforme voy aprendido más de spring, me interesa más por lo pontente que es y el beneficio que brinda al evitar la repetición de código que no le suma nada a la lógica de negocio o »  boilerplate code «.

El post de hoy, lo centrare en el grabado de logging cuando tenemos una aplicación hecha con spring boot, como saben el log es fundamental dado que un buen log nos permite resolver los problemas de nuestro aplicativo sin mucha demora, en un post posterior explicare lineamientos para generar un buen log y buenas practicas en el mismo. Sin embargo me interesa hacer un post de esto acá porque he tenido que revisar mucho la documentación para poder configurar el log como lo necesitaba en spring y no pude encontrar ningún lugar donde expliquen detenidamente como poder realizar esto.

El log que grabaremos se realizará en base de datos (postgres) y un archivo de texto (.txt), se pueden tener multiples tipos (niveles) de log, que nos permiten medir la usabilidad de los features, los errores y las caidas fatales del sistema, para la demo me enfocare en los errores y explicare como en spring podemos capturar todos los errores que se generen, grabarlos en base de datos y el archivo de texto y al usuario mostrarle un mensaje de texto genérico y un código vinculado a nuestro registro de error.

APLICATIVO

Estoy usando Intellij IDEA como IDE para el desarrollo de esta demo, y la aplicación se divide en repository, service y controller. Considerando que el repository y service tenemos una implementación para las interfaces que definimos. Además, en repository tenemos una capa para hacer el mapping a entidades de lo recibido por la base de datos.

Project files de Spring boot

Para grabar los logs, usar log4j2 que es una librería de amplia trayectoria y bien documentada, para configurarla en la sección de resources de nuestra aplicación es necesario crear un archivo de configuración, este puede ser un xml, json o un properties. En mi caso cree un «log4j2.properties» .

Archivo de configuración del log

En el properties de spring es necesario indicarle que tenemos un archivo de configuración de log con las siguientes sentencias:

Configuración en el application.properties para el log

En el log4j2.properties que hemos creado es necesario indicar la siguiente configuración.

Configuración del log en log4j2.properties

En esta estamos indicando el indicando al configuración de la base de datos, es necesario indicar cada columna de la tabla que hemos destinado para los logs en base de datos con los valores que se van a considerar para cada columna. También está la configuración para el archvo de texto, finalmente se indica que ambos appender deben ser utilizados y el nivel mínimo del log.

También es posible indicar en el log variables configuradas por nosotros, para mi caso es necesario saber el endpoint que se está consumiendo, el nombre del método del endpoint, el nombre del método donde el error ocurrio, un guid para vincular el error a un identificador único entre otros valores. Esto podemos conseguirlo seteando variables como propiedades del sistema y luego leyendo en nuestro log4j2.propierties.

Seteo de variables como propiedades del sistema
Obtenemos la propiedad del sistema en log4j2.properties

Una explicación didáctica de esta configuración así como algunas cosas que no pongo en el post para no hacerlo muy extenso lo encuentran en el video. Quedan muchos puntos por detallar más que desarrolloraré en otros posts, espero que les haya sido de utilidad y como siempre dejo los links al repositorio para que revisen ustedes el código.

REPO: GITHUB

Saludos.

1 comentario