Skip to main content

📊 Alpura Back Java — Servicio y Librería General de Reportes (v1.0)

Documentación técnica y arquitectura del Servicio General de Reportes y DataSources Dinámicos (alpura-back-java-msa-reports) y su ecosistema de librerías asociadas (back-java-lib-report-model).

Este servicio provee un motor centralizado, escalable y multi-tenant para la ejecución de consultas dinámicas en múltiples bases de datos, renderizado de reportes en múltiples formatos (PDF, Excel, CSV, HTML), gestión de plantillas y almacenamiento automático en la nube (Alfresco / OCI Object Storage).


🛠️ Stack Tecnológico y Requisitos​

  • Java JDK: 21 (Temurin LTS recomendado)
  • Spring Boot: 3.4.4
  • Alpura BOM: 1.0.4
  • Acceso a Datos Dinámico: Spring Starter JDBC + NamedParameterJdbcTemplate + HikariCP
  • Motores de Reporte:
    • PDF: OpenHTMLtoPDF 1.0.10 (openhtmltopdf-pdfbox + openhtmltopdf-svg-support) + Thymeleaf Template Engine
    • Excel: Apache POI 5.4.0 (poi y poi-ooxml) con soporte de plantillas, estilos stripes y tablas dinámicas
    • HTML & CSV: JSoup 1.17.1 + Streams de texto estandarizados
  • Almacenamiento Distribuido: alpura-back-java-lib-file:5.0 (Alfresco Private / OCI Public Object Storage)
  • Mensajería / Eventos: back-java-lib-queues (Google Cloud Pub/Sub para ejecución asíncrona)
  • Bases de Datos Compatibles: PostgreSQL, Oracle (ojdbc8 19.14), H2 Database

📐 Diagrama de Arquitectura de Reportes​

El siguiente diagrama detalla la arquitectura multicapa del servicio, el flujo de datos desde la recepción de la solicitud REST/PubSub hasta la ejecución SQL en DataSources dinámicos y la generación final del archivo:


🗄️ 1. Motor de DataSources Dinámicos (Multi-Tenant Pools)​

El sistema incluye un mecanismo avanzado para gestionar DataSources en tiempo de ejecución, permitiendo conectar dinámicamente a múltiples bases de datos sin modificar archivos de configuración local.

Componentes Principales​

  1. DynamicDataSourceRegistry: Registro en memoria con ConcurrentHashMap que administra pools de conexiones HikariCP por cada DataSource configurado.
  2. DynamicDataSourceService: Carga configuraciones de bases de datos desde la tabla data_source (DataSourceDO), prueba conexiones y administra refrescos en caliente.
  3. DynamicJdbcTemplateFactory: Factory thread-safe que proporciona un JdbcTemplate para ejecutar queries según el dataSourceId.
  4. DynamicDataSourceInitializer: CommandLineRunner que precarga todos los DataSources al iniciar el microservicio.

Parámetros HikariCP Preconfigurados​

maximum-pool-size: 10
minimum-idle: 2
connection-timeout: 30000 # (30 segundos)
idle-timeout: 600000 # (10 minutos)
max-lifetime: 1800000 # (30 minutos)

Endpoints REST de Administración (DynamicDataSourceController)​

MétodoEndpointDescripción
GET/api/v1/datasources/{id}/testPrueba la conectividad con un DataSource específico.
POST/api/v1/datasources/{id}/refreshRecarga las credenciales/configuración de un DataSource en caliente.
POST/api/v1/datasources/refresh-allRecarga todos los DataSources desde la base de datos.
GET/api/v1/datasources/statisticsDevuelve el total de DataSources activos y métricas de pools.
GET/api/v1/datasources/{id}/healthEstado de salud de la conexión individual.

🔍 2. Motor de Consultas Dinámicas (Dynamic Query Engine)​

Permite construir y ejecutar sentencias SQL estructuradas en formato JSON, garantizando seguridad contra inyección SQL al compilar internamente a NamedParameterJdbcTemplate.

Tipos de Consultas Soportadas​

A. Consulta de Tabla (TABLE)​

Permite especificar tabla origen, alias, JOINs, filtros WHERE condicionales, campos SELECT con alias, agrupación (GROUP BY) y ordenamiento (ORDER BY).

{
"from": {
"type": "TABLE",
"table": "tb_tickets_recoleccion",
"alias": "t"
},
"joins": [
{
"type": "INNER JOIN",
"table": "tb_ranchos",
"alias": "r",
"on": "t.fk_rancho_id = r.pk_id"
}
],
"where": [
{
"field": "t.fk_estatus_id",
"operator": "=",
"value": "ESTATUS_PARAM",
"valueType": "PARAM"
},
{
"field": "t.activo",
"operator": "=",
"value": true,
"valueType": "LITERAL",
"condition": "AND"
},
{
"type": "EXPRESSION",
"expression": "t.fecha_creacion >= CAST(:fechaInicio AS DATE)",
"condition": "AND"
}
],
"select": [
{ "field": "t.pk_id", "alias": "ticketId" },
{ "field": "r.tx_nombre", "alias": "nombreRancho" },
{ "field": "t.dn_litros", "alias": "litrosRecoleccion" }
],
"groupBy": ["t.pk_id", "r.tx_nombre", "t.dn_litros"],
"orderBy": [
{ "field": "t.fecha_creacion", "direction": "DESC" }
]
}

B. Consulta de Función Stored Procedure (FUNCTION)​

Ejecuta funciones/procedimientos en PostgreSQL pasándole parámetros posicionales o por nombre:

{
"from": {
"type": "FUNCTION",
"schema": "public",
"name": "fn_obtener_resumen_viajes",
"alias": "f",
"params": [":idRuta", ":fechaOperacion::DATE"]
},
"select": [
{ "field": "f.col_ruta_id", "alias": "rutaId" },
{ "field": "f.col_total_litros", "alias": "totalLitros" }
]
}

🖨️ 3. Motores Generadores de Reportes (Multi-Format)​

El servicio utiliza el patrón Factory (ReportGeneratorFactory) para resolver en tiempo de ejecución la implementación de IReportGenerator adecuada según el formato solicitado (ReportFormatEnum):

public interface IReportGenerator {
byte[] generateReport(ReportVO report, Object data, Map<String, Object> params);
ReportFormatEnum getSupportedFormat();
}

A. Generador PDF (PdfReportGenerator)​

  • Utiliza Thymeleaf para procesar plantillas HTML con variables contextuales.
  • Convierte el HTML renderizado a documento PDF mediante OpenHTMLtoPDF (PdfRendererBuilder).
  • Soporta incrustación de fuentes vectoriales (ej. DejaVuSans.ttf, OpenSans), gráficos SVG y diseño adaptable CSS.

B. Generador Excel (ExcelReportGenerator)​

  • Utiliza Apache POI 5.4.0 para procesar plantillas .xlsx pre-diseñadas.
  • Mapea marcadores dinámicos e inserta tablas de datos mediante TableProcessor.
  • Soporta características avanzadas:
    • Preservación de formato de celda y snapshot de estilos (CellSnapshot, StripeStyleRecord).
    • Expansión automática de filas y ajuste dinámico de rangos de fórmulas (TableExpansionRecord).
    • Formato condicional y bandas alternadas (stripes).

C. Generadores CSV & HTML (CsvReportGenerator, HtmlReportGenerator)​

  • Exportación ligera de datos delimitados por coma (CSV) optimizada para streams de gran volumen.
  • Generación de código HTML estructurado para vista previa rápida en navegadores web.

☁️ 4. Gestión de Plantillas y Almacenamiento​

El microservicio se integra nativamente con la librería de archivos de Alpura (alpura-back-java-lib-file:5.0):

  1. Gestión de Plantillas (ITemplateService): Almacena y versiona plantillas HTML (para PDF) y plantillas .xlsx (para Excel) vinculadas a cada tipo de reporte en la base de datos.
  2. Almacenamiento del Reporte Generado (FileServiceImpl):
    • Transfiere automáticamente el reporte renderizado hacia la infraestructura configurada:
      • Contenido Privado: Se envía a Alfresco mediante IFileGateway.
      • Contenido Público: Se sube a un bucket en Oracle Cloud Object Storage (OCI).
    • Retorna una URL firmada / identificador único (AlfrescoFileVO) en la respuesta REST.

🔌 5. Guía de Integración REST & Contratos de Payload​

Generación de Reporte Síncrono (POST /api/v1/reports/generate)​

Request Payload (ReportRequestVO)​

{
"reportCode": "REP_LITROS_RANCHOS",
"format": "PDF",
"dataSourceId": 1,
"parameters": {
"fechaInicio": "2026-09-01",
"fechaFin": "2026-09-17",
"estatusId": 1
},
"uploadToCloud": true,
"cloudDirectory": "/reportes/recoleccion/2026"
}

Response Payload (ReportResponseVO)​

{
"status": "SUCCESS",
"message": "Reporte generado correctamente",
"reportCode": "REP_LITROS_RANCHOS",
"format": "PDF",
"fileName": "REP_LITROS_RANCHOS_20260917_153000.pdf",
"fileBase64": "JVBERi0xLj... (contenido cuando uploadToCloud = false)",
"cloudFileDetail": {
"nodeId": "workspace://SpacesStore/a1b2c3d4-5678-90ab",
"downloadUrl": "https://objectstorage.us-ashburn-1.oraclecloud.com/p/...",
"mimeType": "application/pdf",
"sizeBytes": 145892
},
"executionTimeMs": 342
}

📦 6. Cómo Incluir la Librería de Modelos en tu Microservicio​

Para utilizar las clases de modelo y clientes DTO del centro de reportes en tu microservicio Java:

Configuración en pom.xml​

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alpura</groupId>
<artifactId>bom</artifactId>
<version>1.0.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- Librería de Modelos de Reportes Alpura -->
<dependency>
<groupId>com.alpura</groupId>
<artifactId>back-java-lib-report-model</artifactId>
</dependency>
</dependencies>

💡 Ejemplos Prácticos de Código​

Ejemplo 1: Ejecutar una consulta usando DynamicJdbcTemplateFactory​

@Service
@RequiredArgsConstructor
public class DashboardMetricasService {

private final DynamicJdbcTemplateFactory jdbcTemplateFactory;

public List<Map<String, Object>> obtenerKpisPorDataSource(Long dataSourceId) {
// Obtener el JdbcTemplate dinámico asociado a la base de datos destino
JdbcTemplate jdbcTemplate = jdbcTemplateFactory.getJdbcTemplate(dataSourceId);

String sql = "SELECT region, SUM(litros) as total_litros FROM tb_recoleccion GROUP BY region";
return jdbcTemplate.queryForList(sql);
}
}

Ejemplo 2: Probar la salud de un DataSource antes de ejecutar una operación​

@Service
@RequiredArgsConstructor
public class VerificacionConexionService {

private final DynamicDataSourceService dynamicDataSourceService;

public void ejecutarValidacion(Long dataSourceId) {
boolean conexionOk = dynamicDataSourceService.testConnection(dataSourceId);
if (!conexionOk) {
throw new IllegalStateException("El DataSource con ID " + dataSourceId + " no responde.");
}

// Continuar con el proceso de negocio...
}
}

📌 Buenas Prácticas y Recomendaciones​

  1. Evitar Consultas N+1: Utilizar las cláusulas JOIN explícitas del motor de consultas en lugar de ejecutar subconsultas reiteradas.
  2. Filtrar por Parámetros Parametrizados: Usar siempre "valueType": "PARAM" para los datos que provienen del usuario o cliente REST, evitando "valueType": "LITERAL" con cadenas concatenadas.
  3. Liberación y Refresh de DataSources: Si las credenciales de una base de datos cambian en la base central, invocar /api/v1/datasources/{id}/refresh sin necesidad de reiniciar los contenedores.
  4. Almacenamiento en Nube: Para reportes pesados o de procesamiento batch, configurar "uploadToCloud": true para evitar saturación de memoria por transferencia de cadenas Base64 en la red.