Verificando autenticación…

Saltar al contenido principal

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 usan com.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)
  • 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

  1. Clonar el repositorio: Sigue los siguientes pasos

  2. 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.properties en 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-release
    ARTIFACTORY_USERNAME=<tu_usuario_artifactory>
    ARTIFACTORY_PASSWORD=<tu_api_key_artifactory>

    Más información en Gradle Local.

  3. Compilar el proyecto: Desde la consola, en la raíz del proyecto:

    ./gradlew clean build
  4. Ejecutar la aplicación: Una vez compilado exitosamente (mensaje BUILD SUCCESSFUL):

    ./gradlew bootRun

    La 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)

  1. Modifica la línea de pipeline en Jenkinsfile (según la convención del README, podría ser algo como):
    pipelineLatam("gke-krane-native-java21")
    (Nota: El Jenkinsfile actual no muestra esta opción; adaptar según sea necesario.)
  2. En la carpeta deploy/env, agrega archivos .yaml para cada ambiente (dev, intg, prod) con el contenido: Configuración Native por Ambiente (Archivo (nombre_ambiente).yaml)
    native: true
  3. 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étodoPathDescripciónEjemplo de Request (Body)
GET/v1/api/flightsLista todos los vuelos (paginado). Permite query params: origin, destination, current_page.N/A
POST/v1/api/flightsCrea 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étodoPathDescripciónQuery Params
POST/v1/api/pubsubEnvía un mensaje a la cola Pub/Sub.messageSend (String)

Gestión de Archivos (Cloud Storage)

MétodoPathDescripciónQuery Params
GET/v1/api/files/filesLista los objetos de un bucket.N/A
POST/v1/api/filesSube un archivo (multipart/form-data) a un bucket.file (MultipartFile)
DELETE/v1/api/filesElimina un archivo de un bucket.fileName (String)
GET/v1/api/filesDescarga un archivo de un bucket.fileName (String)

Cache con Redis

MétodoPathDescripciónQuery ParamsEjemplo de Request (Body)
POST/v1/api/redisCrea un objeto en la caché de Redis.collection (String)JSON (cualquier objeto)
GET/v1/api/redisDevuelve 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étodoPathDescripciónQuery Params
GET/v1/api/restEnvía petición a un servicio REST configurado.origin, destination, current_page

Mensajería Kafka

MétodoPathDescripciónQuery 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_CREDENTIALS configurada localmente.

  • Implementación: Consulta PubSubController.java (en com.latam.lataminit_itelement.lataminit_use_case.application.rest) y PubSubReceiver.java, PubSubPublisher.java (en com.latam.lataminit_itelement.lataminit_use_case.infrastructure.pubsub).

  • Deshabilitar:

    1. Elimina la dependencia com.google.cloud:spring-cloud-gcp-starter-pubsub de gradle/dependencies.gradle.
    2. Elimina los archivos Java relacionados: PubSubController.java, PubSubService.java, PubSubPublisher.java, PubSubReceiver.java.
    3. Elimina las propiedades de gcp.topic y gcp.subscription de application.yaml.

Storage (Google Cloud Storage)

  • Configuración: Modifica src/main/resources/application.yaml:
    gcp:
    bucket:
    name: ae-dev-us-example # Reemplazar con tu bucket name (o ${BUCKET_NAME:${{ BUCKET-NAME }}})
    Asegúrate de tener la variable de ambiente GOOGLE_APPLICATION_CREDENTIALS configurada localmente.
  • Implementación: Consulta FileController.java (en com.latam.lataminit_itelement.lataminit_use_case.application.rest) y FileService.java (en com.latam.lataminit_itelement.lataminit_use_case.domain.service).
  • Deshabilitar:
    1. Elimina la dependencia com.google.cloud:spring-cloud-gcp-starter-storage de gradle/dependencies.gradle.
    2. Elimina los archivos Java relacionados: FileController.java, FileService.java.
    3. Elimina la propiedad gcp.bucket.name de application.yaml.

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 (en com.latam.lataminit_itelement.lataminit_use_case.application.rest), RedisService.java (en com.latam.lataminit_itelement.lataminit_use_case.domain.service), RedisRepository.java (en com.latam.lataminit_itelement.lataminit_use_case.infrastructure.redis), y RedisConfig.java (en com.latam.lataminit_itelement.lataminit_use_case.infrastructure.config).
  • Deshabilitar:
    1. Elimina las dependencias redis.clients:jedis y org.springframework.data:spring-data-redis de gradle/dependencies.gradle.
    2. Elimina los archivos Java relacionados: RedisConfig.java, RedisController.java, RedisException.java, RedisPort.java, RedisRepository.java, RedisService.java.
    3. Elimina el ExceptionHandler para RedisException en ApiExceptionHandler.java.
    4. Elimina las propiedades redis.hostname y redis.port de application.yaml.

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 (en com.latam.lataminit_itelement.lataminit_use_case.application.rest), RestService.java (en com.latam.lataminit_itelement.lataminit_use_case.domain.service), RestClient.java (en com.latam.lataminit_itelement.lataminit_use_case.domain.repository), y FlightRestFeignClientConfiguration.java (en com.latam.lataminit_itelement.lataminit_use_case.infrastructure.config).
  • Deshabilitar:
    1. Elimina la dependencia org.springframework.cloud:spring-cloud-starter-openfeign de gradle/dependencies.gradle.
    2. Elimina los archivos Java relacionados: RestClient.java, RestServiceController.java, FlightRestFeignClientConfiguration.java, RestService.java.
    3. Elimina la anotación @EnableFeignClients de Application.java.
    4. Elimina la propiedad rest-service.endpoint de application.yaml.

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 (en com.latam.lataminit_itelement.lataminit_use_case.application.rest), KafkaService.java (en com.latam.lataminit_itelement.lataminit_use_case.domain.service), KafkaProducer.java, KafkaConsumerListener.java (en com.latam.lataminit_itelement.lataminit_use_case.infrastructure.kafka), y KafkaConfig.java (en com.latam.lataminit_itelement.lataminit_use_case.infrastructure.config).
  • Deshabilitar:
    1. Elimina la dependencia org.springframework.kafka:spring-kafka de gradle/dependencies.gradle.
    2. Elimina los archivos Java relacionados: KafkaController.java, KafkaConsumerListener.java, KafkaProducer.java, KafkaService.java, KafkaPort.java, KafkaConfig.java.
    3. Elimina las propiedades de kafka.broker, spring.kafka.properties, etc., de application.yaml.

Pruebas

Este proyecto incluye configuraciones para pruebas automatizadas con JMeter. El README del proyecto original proporciona instrucciones detalladas.

Cómo usar JMeter

  1. Navega a la carpeta tests/jmeter/bin (si existe y está poblada) y ejecuta jmeter.bat (Windows) o jmeter.sh (Linux/macOS).
  2. En JMeter, ve a "File" -> "Open" y selecciona un plan de pruebas de la carpeta tests/Template spring-intg test plan (si existe).
  3. Haz clic en la flecha verde para ejecutar el plan de pruebas.
  4. 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.properties local 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.