📊 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 (
poiypoi-ooxml) con soporte de plantillas, estilos stripes y tablas dinámicas - HTML & CSV: JSoup 1.17.1 + Streams de texto estandarizados
- PDF: OpenHTMLtoPDF 1.0.10 (
- 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
DynamicDataSourceRegistry: Registro en memoria conConcurrentHashMapque administra pools de conexiones HikariCP por cada DataSource configurado.DynamicDataSourceService: Carga configuraciones de bases de datos desde la tabladata_source(DataSourceDO), prueba conexiones y administra refrescos en caliente.DynamicJdbcTemplateFactory: Factory thread-safe que proporciona unJdbcTemplatepara ejecutar queries según eldataSourceId.DynamicDataSourceInitializer:CommandLineRunnerque 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étodo | Endpoint | Descripción |
|---|---|---|
GET | /api/v1/datasources/{id}/test | Prueba la conectividad con un DataSource específico. |
POST | /api/v1/datasources/{id}/refresh | Recarga las credenciales/configuración de un DataSource en caliente. |
POST | /api/v1/datasources/refresh-all | Recarga todos los DataSources desde la base de datos. |
GET | /api/v1/datasources/statistics | Devuelve el total de DataSources activos y métricas de pools. |
GET | /api/v1/datasources/{id}/health | Estado 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
.xlsxpre-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).
- Preservación de formato de celda y snapshot de estilos (
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):
- 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. - 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).
- Contenido Privado: Se envía a Alfresco mediante
- Retorna una URL firmada / identificador único (
AlfrescoFileVO) en la respuesta REST.
- Transfiere automáticamente el reporte renderizado hacia la infraestructura configurada:
🔌 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
- Evitar Consultas N+1: Utilizar las cláusulas
JOINexplícitas del motor de consultas en lugar de ejecutar subconsultas reiteradas. - 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. - Liberación y Refresh de DataSources: Si las credenciales de una base de datos cambian en la base central, invocar
/api/v1/datasources/{id}/refreshsin necesidad de reiniciar los contenedores. - Almacenamiento en Nube: Para reportes pesados o de procesamiento batch, configurar
"uploadToCloud": truepara evitar saturación de memoria por transferencia de cadenas Base64 en la red.