Template Springboot
Propósito y Alcance
Latam Development Stack Template Spring Integration fue creado para facilitar la creación de componentes Java, cuya finalidad sea implementar lógica de negocio. El template se limita a:
- Integración con componentes Pub/Sub, para publicación y recuperación de mensajes.
- Integración con componentes Google Cloud Storage.
- Integración con base de datos PostgreSQL.
- Integración con Redis para almacenar datos en memoria.
- Integración con Servicios Rest (OpenFeign).
- Integración con Apache Kafka.
El template Spring Integration considera librerías de seguridad e imágenes base autorizadas por la compañía.
Arquitectura
Esta aplicación cuenta con una arquitectura hexagonal, la cual cuenta con tres capas:
- Capa de Infraestructura: es la capa responsable del funcionamiento de la aplicación (configuraciones, conexiones a recursos externos).
- Capa de Aplicación: es la capa encargada de implementar los puntos de entrada a la aplicación.
- Capa de Dominio: es la capa encargada de implementar el modelo y la lógica de negocio.
Java package: El uso de packages debe tener la arquitectura hexagonal, y además, contener un package base con la
siguiente nomenclatura: com.latam.[it_element].[caracteristica_del_componente].
- Ejemplo:
com.latam.ltmds.intg(Nota: los fuentes del proyecto usancom.latam.lataminit_itelement.lataminit_use_case)
Tecnologías y Dependencias
- Lenguaje: Java 21
- Framework: Spring Boot 3.4.5
- Base de Datos: PostgreSQL
- Mensajería:
- Google Cloud Pub/Sub (
com.google.cloud:spring-cloud-gcp-starter-pubsub:6.1.1) - Apache Kafka (
org.springframework.kafka:spring-kafka:4.0.0-M1)
- Google Cloud Pub/Sub (
- Almacenamiento: Google Cloud Storage (
com.google.cloud:spring-cloud-gcp-starter-storage) - Cache: Redis (
redis.clients:jedis:5.0.2,org.springframework.data:spring-data-redis:4.0.0-M1) - Comunicación REST: OpenFeign (
org.springframework.cloud:spring-cloud-starter-openfeign:4.2.0) - Servidor Web Embebido: Tomcat (via
spring-boot-starter-tomcat) - Logging: Latam Logging Library (
com.latam:latam-logging-library:1.0.17), Logstash Logback Encoder (net.logstash.logback:logstash-logback-encoder:8.0) - Build Tool: Gradle
- Otras: Lombok, Spring Boot Actuator, Spring Integration, Jakarta Annotations, SpotBugs Annotations, Commons IO.
Configuración Local
Prerrequisitos
- JDK 21
- Gradle
- IntelliJ IDEA Community (Recomendado)
- Acceso a JFrog Artifactory para creación de API Key
- Git
Pasos de Configuración
-
Clonar el repositorio: Sigue los siguientes pasos
-
Configurar credenciales de Artifactory: Accede a Artifactory LATAM con tu cuenta G Suite. En "Authentication Settings", genera un API Key (Artifactory Settings). Crea un archivo
gradle.propertiesen la raíz del proyecto (este archivo está excluido por.gitignore, no lo comitees) con tus credenciales de JFrog:ARTIFACTORY_BASE_URL=https://artifactoryrepo1.appslatam.com/artifactory/ARTIFACTORY_GRADLE_CORP_REPO=corp-libs-gradle-releaseARTIFACTORY_USERNAME=<tu_usuario_artifactory>ARTIFACTORY_PASSWORD=<tu_api_key_artifactory>Más información en Gradle Local.
-
Compilar el proyecto: Desde la consola, en la raíz del proyecto:
./gradlew clean build -
Ejecutar la aplicación: Una vez compilado exitosamente (mensaje
BUILD SUCCESSFUL):./gradlew bootRunLa aplicación estará disponible (por defecto) en
http://localhost:8080/template-intg.
Despliegue
Despliegue con Java 21
Modifica la línea de pipeline en Jenkinsfile:
pipelineLatam("gke-krane-java21")
Despliegue con Native Image (GraalVM)
- Modifica la línea de pipeline en
Jenkinsfile(según la convención del README, podría ser algo como):(Nota: ElpipelineLatam("gke-krane-native-java21")Jenkinsfileactual no muestra esta opción; adaptar según sea necesario.) - En la carpeta
deploy/env, agrega archivos.yamlpara cada ambiente (dev, intg, prod) con el contenido:
(Archivo (nombre_ambiente).yaml)native: true - En el archivo
gradle/config.gradle, activa la generación del JAR:jar {enabled = true}
Para más información, consultar Migración SpringBoot v3.
Endpoints de la API
La aplicación expone los siguientes endpoints REST bajo el base path /template-intg.
Autenticación: La mayoría de los endpoints pueden requerir autenticación vía google_id_token,
serviceaccount_jwt, o azure_id_token como Bearer tokens en la cabecera Authorization.
Gestión de Vuelos (Flights)
| Método | Path | Descripción | Ejemplo de Request (Body) |
|---|---|---|---|
| GET | /v1/api/flights | Lista todos los vuelos (paginado). Permite query params: origin, destination, current_page. | N/A |
| POST | /v1/api/flights | Crea un nuevo vuelo. | FlightDTO (ver com.latam.lataminit_itelement.lataminit_use_case.application.request.FlightDTO) |
| GET | /v1/api/flights/{number} | Obtiene un vuelo por número. | N/A |
| PUT | /v1/api/flights/{number} | Actualiza un vuelo por número. | FlightDTO |
| DELETE | /v1/api/flights/{number} | Elimina un vuelo por número. | N/A |
Mensajería Pub/Sub
| Método | Path | Descripción | Query Params |
|---|---|---|---|
| POST | /v1/api/pubsub | Envía un mensaje a la cola Pub/Sub. | messageSend (String) |
Gestión de Archivos (Cloud Storage)
| Método | Path | Descripción | Query Params |
|---|---|---|---|
| GET | /v1/api/files/files | Lista los objetos de un bucket. | N/A |
| POST | /v1/api/files | Sube un archivo (multipart/form-data) a un bucket. | file (MultipartFile) |
| DELETE | /v1/api/files | Elimina un archivo de un bucket. | fileName (String) |
| GET | /v1/api/files | Descarga un archivo de un bucket. | fileName (String) |
Cache con Redis
| Método | Path | Descripción | Query Params | Ejemplo de Request (Body) |
|---|---|---|---|---|
| POST | /v1/api/redis | Crea un objeto en la caché de Redis. | collection (String) | JSON (cualquier objeto) |
| GET | /v1/api/redis | Devuelve la colección de datos guardada. | collection (String) | N/A |
| GET | /v1/api/redis/{key} | Devuelve el objeto asociado a la clave. | collection (String) | N/A |
| PUT | /v1/api/redis/{key} | Actualiza el objeto asociado a la clave. | collection (String) | JSON (cualquier objeto) |
| DELETE | /v1/api/redis/{key} | Elimina el objeto asociado a la clave. | collection (String) | N/A |
Servicios REST (OpenFeign)
| Método | Path | Descripción | Query Params |
|---|---|---|---|
| GET | /v1/api/rest | Envía petición a un servicio REST configurado. | origin, destination, current_page |
Mensajería Kafka
| Método | Path | Descripción | Query Params |
|---|---|---|---|
| POST | /v1/api/kafka (Nota: README dice /v1/api/kafka/send, pero código usa /v1/api/kafka) | Envía un mensaje a la cola de Kafka. | messageSend (String) |
Componentes Específicos
Pub/Sub
-
Configuración: Modifica
src/main/resources/application.yaml:gcp:topic:name: ae-dev-example# Reemplazar con tu topic name (o ${TOPIC_NAME:${{ TOPIC-NAME }}})subscription:name: ae-dev-example-subscription# Reemplazar con tu subscription name (o ${SUSCRIPTION_NAME:${{ SUSCRIPTION-NAME }}})Asegúrate de tener la variable de ambiente
GOOGLE_APPLICATION_CREDENTIALSconfigurada localmente. -
Implementación: Consulta
PubSubController.java(encom.latam.lataminit_itelement.lataminit_use_case.application.rest) yPubSubReceiver.java,PubSubPublisher.java(encom.latam.lataminit_itelement.lataminit_use_case.infrastructure.pubsub). -
Deshabilitar:
- Elimina la dependencia
com.google.cloud:spring-cloud-gcp-starter-pubsubdegradle/dependencies.gradle. - Elimina los archivos Java relacionados:
PubSubController.java,PubSubService.java,PubSubPublisher.java,PubSubReceiver.java. - Elimina las propiedades de
gcp.topicygcp.subscriptiondeapplication.yaml.
- Elimina la dependencia
Storage (Google Cloud Storage)
- Configuración: Modifica
src/main/resources/application.yaml:Asegúrate de tener la variable de ambientegcp:bucket:name: ae-dev-us-example # Reemplazar con tu bucket name (o ${BUCKET_NAME:${{ BUCKET-NAME }}})GOOGLE_APPLICATION_CREDENTIALSconfigurada localmente. - Implementación: Consulta
FileController.java(encom.latam.lataminit_itelement.lataminit_use_case.application.rest) yFileService.java(encom.latam.lataminit_itelement.lataminit_use_case.domain.service). - Deshabilitar:
- Elimina la dependencia
com.google.cloud:spring-cloud-gcp-starter-storagedegradle/dependencies.gradle. - Elimina los archivos Java relacionados:
FileController.java,FileService.java. - Elimina la propiedad
gcp.bucket.namedeapplication.yaml.
- Elimina la dependencia
Redis
- Configuración: Modifica
src/main/resources/application.yaml:redis:hostname: localhost # Reemplazar con tu hostname de Redis (o ${REDIS_HOSTNAME:${{ REDIS-HOSTNAME }}})port: 6379 # Reemplazar con tu puerto de Redis (o ${REDIS_PORT:${{ REDIS-PORT}}}) - Implementación: Consulta
RedisController.java(encom.latam.lataminit_itelement.lataminit_use_case.application.rest),RedisService.java(encom.latam.lataminit_itelement.lataminit_use_case.domain.service),RedisRepository.java(encom.latam.lataminit_itelement.lataminit_use_case.infrastructure.redis), yRedisConfig.java(encom.latam.lataminit_itelement.lataminit_use_case.infrastructure.config). - Deshabilitar:
- Elimina las dependencias
redis.clients:jedisyorg.springframework.data:spring-data-redisdegradle/dependencies.gradle. - Elimina los archivos Java relacionados:
RedisConfig.java,RedisController.java,RedisException.java,RedisPort.java,RedisRepository.java,RedisService.java. - Elimina el
ExceptionHandlerparaRedisExceptionenApiExceptionHandler.java. - Elimina las propiedades
redis.hostnameyredis.portdeapplication.yaml.
- Elimina las dependencias
Servicios REST (OpenFeign)
- Configuración: Modifica
src/main/resources/application.yaml:rest-service:endpoint: "http://${APPLICATION}-template-spring-dal-service.${APPLICATION}-${ENVIRONMENT:dev}.svc.cluster.local/api/dal"# Reemplazar con tu endpoint (o ${REST_ENDPOINT:${{ REST-ENDPOINT}}}) - Implementación: Consulta
RestServiceController.java(encom.latam.lataminit_itelement.lataminit_use_case.application.rest),RestService.java(encom.latam.lataminit_itelement.lataminit_use_case.domain.service),RestClient.java(encom.latam.lataminit_itelement.lataminit_use_case.domain.repository), yFlightRestFeignClientConfiguration.java(encom.latam.lataminit_itelement.lataminit_use_case.infrastructure.config). - Deshabilitar:
- Elimina la dependencia
org.springframework.cloud:spring-cloud-starter-openfeigndegradle/dependencies.gradle. - Elimina los archivos Java relacionados:
RestClient.java,RestServiceController.java,FlightRestFeignClientConfiguration.java,RestService.java. - Elimina la anotación
@EnableFeignClientsdeApplication.java. - Elimina la propiedad
rest-service.endpointdeapplication.yaml.
- Elimina la dependencia
Kafka
- Configuración: Modifica
src/main/resources/application.yaml:kafka:broker:address: localhost:29092 # Reemplazar con tu broker address (o ${BROKER_ENDPOINT:${{ BROKER-ADDRESS }}})topic: kafka-topic # Reemplazar con tu topic (o ${KAFKA_TOPIC:${{ KAFKA-TOPIC }}})producer:name: kafka-producer # (o ${PRODUCER_NAME:${{ PRODUCER-NAME }}})consumer:name: kafka-consumer # (o ${CONSUMER_NAME:${{ CONSUMER_NAME }}})group: kafka-group # (o ${CONSUMER_GROUP:${{ CONSUMER_GROUP }}})# También considera las properties de seguridad de Kafka en application.yaml si son necesarias:# spring.kafka.properties.sasl.*, spring.kafka.properties.security.protocol, etc. - Implementación: Consulta
KafkaController.java(encom.latam.lataminit_itelement.lataminit_use_case.application.rest),KafkaService.java(encom.latam.lataminit_itelement.lataminit_use_case.domain.service),KafkaProducer.java,KafkaConsumerListener.java(encom.latam.lataminit_itelement.lataminit_use_case.infrastructure.kafka), yKafkaConfig.java(encom.latam.lataminit_itelement.lataminit_use_case.infrastructure.config). - Deshabilitar:
- Elimina la dependencia
org.springframework.kafka:spring-kafkadegradle/dependencies.gradle. - Elimina los archivos Java relacionados:
KafkaController.java,KafkaConsumerListener.java,KafkaProducer.java,KafkaService.java,KafkaPort.java,KafkaConfig.java. - Elimina las propiedades de
kafka.broker,spring.kafka.properties, etc., deapplication.yaml.
- Elimina la dependencia
Pruebas
Este proyecto incluye configuraciones para pruebas automatizadas con JMeter. El README del proyecto original proporciona instrucciones detalladas.
Cómo usar JMeter
- Navega a la carpeta
tests/jmeter/bin(si existe y está poblada) y ejecutajmeter.bat(Windows) ojmeter.sh(Linux/macOS). - En JMeter, ve a "File" -> "Open" y selecciona un plan de pruebas de la carpeta
tests/Template spring-intg test plan(si existe). - Haz clic en la flecha verde para ejecutar el plan de pruebas.
- Visualiza los resultados.
Importante (según el README original):
- Para pruebas de Kafka, JMeter puede requerir una instalación local de Kafka.
- Para Pub/Sub y Storage de GCP, asegúrate de tener los permisos adecuados.
El proyecto también utiliza JUnit 5 y Mockito para pruebas unitarias y de integración, ejecutadas con Gradle:
./gradlew test
Los reportes de Jacoco se generan en build/reports/jacoco/test/html/.
Consideraciones de Seguridad
- Gestión de Credenciales: Las credenciales sensibles (como claves de API, passwords de base deatos) deben
gestionarse a través de secretos en el entorno de despliegue (e.g., Kubernetes Secrets) y no deben ser comiteadas
en el repositorio. El archivo
gradle.propertieslocal es un ejemplo de cómo manejar credenciales de desarrollo localmente sin subirlas al repositorio. - Variables de Entorno: Utilizar variables de entorno para configurar aspectos sensibles de la aplicación en los diferentes entornos (dev, intg, prod).
- Cloud Endpoints Security: Para APIs expuestas a través de Google Cloud Endpoints, configurar las definiciones
de seguridad apropiadas (JWT, API Keys) como se especifica en
deploy/endpoints/openapi.yaml.erb.