Guía Técnica: Generación y Descarga de Documentos Word (.docx) con DocxHelper en GeneXus

Guía Técnica: Generación y Descarga de Documentos Word (.docx) con DocxHelper en GeneXus

1. Requisitos Previos e Instalación

1.1 Librerías Java (Apache POI)

Para que DocxHelper funcione correctamente, el entorno debe contar con las librerías de Apache POI. Asegurarse de tener los siguientes archivos .jar (versión 5.2.2 o superior) en el classpath del servidor/proyecto:
Subi los archivos a una carpeta de Google Drive para el que las necesite. Link de Descarga: 
https://drive.google.com/drive/folders/1E2Z1-K9ZQ_ur9SHQZd1BGq8rwO0X5Kya?usp=sharing

  • poi-5.2.2.jar

  • poi-ooxml-5.2.2.jar

  • poi-ooxml-lite-5.2.2.jar

  • poi-scratchpad-5.2.2.jar

    En mi caso las rutas serian:
    C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\GX18_GesRec_DSRDesarrollo\WEB-INF\lib
    D:\Proyectos\GX18\GX18_GesRec_PrdFuncional\JavaDB2iSeries002\Web\lib

    1.2 Formato de Plantillas Obligatorio (.docx)

    Las plantillas utilizadas deben ser obligatoriamente formato .docx real. Los formatos .doc, .dot, o .dotx fallarán.

    Script de Conversión Masiva (PowerShell): Si existen plantillas heredadas en formatos antiguos, ejecutar el siguiente script en una PC con Microsoft Word instalado para convertirlas por lotes a .docx.
    SCRIPT:
    ////////////////////////////////////////////////////////////////////////////////////////////////

    $word = New-Object -ComObject Word.Application
    $word.Visible = $false

    $path = “D:\PLANTILLAS” # ← CAMBIAR ESTA RUTA POR LA CARPETA DE PLANTILLAS

    Get-ChildItem -Path $path -Recurse -Include *.doc, *.dot, *.dotx | ForEach-Object {
    $inputPath = $_.FullName
    $outputPath = [System.IO.Path]::ChangeExtension($inputPath, “.docx”)

    try {
    $doc = $word.Documents.Open($inputPath)
    $doc.SaveAs([ref] $outputPath, [ref] 16) # 16 = formato DOCX
    $doc.Close()
    Write-Host “Convertido con éxito:” $inputPath
    }
    catch {
    Write-Host “Error al convertir:” $inputPath
    }
    }

    $word.Quit()
    ////////////////////////////////////////////////////////////////////////////////////////////////

    Notas sobre la conversión:

    • Los archivos originales NO se eliminan.

    • Los archivos .dot y .dotx (plantillas de Word) pasan a ser documentos normales.

    • Importante: Si alguna plantilla contenía macros, estas no se conservarán en el nuevo .docx.

      2. Paso a Paso: Lógica de Generación del Documento

      El proceso de generación debe realizarse utilizando rutas absolutas para evitar que Tomcat pierda la referencia del archivo.

      2.1 Obtener la ruta de la plantilla

      Se debe utilizar el procedimiento que devuelve la ruta física (PCrtFileWeb), descartando versiones anteriores (PCrtFile o PCrtFileV2) que no lo hacían.
      Fragmento de codigo a modo ejemplo:

      // Obtiene la ruta física de la plantilla en &PlantillaPath
      Call(PCrtFileWeb, &PlaCod, ”, &NomArcDes, ‘N’, &PlaAbr, &Archi, &CantCopias, &Ok, &Mensaje, &PlantillaPath)

      If &Ok <> ‘S’
           Msg(‘Error al obtener plantilla: ‘ + &Mensaje)
           Return
      EndIf

      2.2 Generación del nombre y manejo de concurrencia

      Para evitar que dos usuarios pisen el mismo archivo si generan un documento al mismo tiempo, se añade un timestamp al nombre del archivo de salida.
      Fragmento de codigo a modo ejemplo:

      &Now = ServerNow()
      &SufijoHora = Trim(Str(Year(&Now), 4, 0)) + Trim(Str(Month(&Now), 2, 0)) + Trim(Str(Day(&Now), 2, 0)) + Trim(Str(Hour(&Now), 2, 0)) + Trim(Str(Minute(&Now), 2, 0)) + Trim(Str(Second(&Now), 2, 0))

      // OBLIGATORIO: Usar ruta física absoluta del servidor (Tomcat)
      &DirectorioTomcat = !”C:\Program Files\Apache Software Foundation\Tomcat 10.1\static\publictempstorage\”
      &PathFinal = &DirectorioTomcat + Trim(&NomArcDes) + !”_” + &SufijoHora + !”.docx”

      2.3 Reemplazo de Tags con DocxHelper

      La lógica de reemplazo consta de dos fases críticas:

      1. Reemplazo Inicial (Creación): Lee de la &PlantillaPath original y genera el archivo nuevo en &PathFinal.

      2. Reemplazos Subsiguientes (Actualización): Leen de &PathFinal y sobrescriben el mismo &PathFinal.

        Fragmento de codigo a modo ejemplo:

      // 1. EL PRIMER REEMPLAZO: Crea el archivo final a partir de la plantilla
      DocxHelper.replaceText(&PlantillaPath, &PathFinal, ‘<<FECHA>>’, Trim(dtoc(&Today)))

      // 2. TODOS LOS DEMÁS REEMPLAZOS: Operan sobre el archivo recién creado
      &HoyLetras = Trim(str(Day(&Today))) + ‘ de ‘ + Trim(cmonth(&Today)) + ‘ de ‘ + Trim(str(year(&Today)))
      DocxHelper.replaceText(&PathFinal, &PathFinal, ‘<<FECHALETRAS>>’, Trim(&HoyLetras))
      DocxHelper.replaceText(&PathFinal, &PathFinal, ‘<<HORA>>’, Trim(Time()))
      // … continuar con el resto de las variables …

      3. Paso a Paso: Descarga del Archivo (HTTP Response)

      ⚠️ REGLA DE ARQUITECTURA CRÍTICA: La manipulación de &HttpResponse para forzar la descarga NUNCA debe hacerse dentro de un evento de un Web Panel. Hacerlo corromperá el HTML de la pantalla. Todo el código de generación y descarga debe estar en un Procedure (Procedimiento) configurado de la siguiente manera:

      • Main program: True

      • Call protocol: HTTP

      3.1 Configuración de Cabeceras y Descarga

      Al final del Procedure, una vez generado el .docx, se inyecta el binario en la respuesta HTTP:

      If &PlaImp = ‘Y’ OR &PlaAbr = ‘Y’
      &OutputFile.Source = &PathFinal // Asignamos la ruta absoluta

      If &OutputFile.Exists()
      &NombreArchivoDescarga = &OutputFile.GetName() + !”.docx”

      // Configuramos cabeceras para forzar descarga de Word
      &HttpResponse.AddHeader(!”Content-Type”, !”application/vnd.openxmlformats-officedocument.wordprocessingml.document”)
      &HttpResponse.AddHeader(!”X-Frame-Options”, !”deny”)
      &HttpResponse.AddHeader(!”X-Content-Type-Options”, !”nosniff”)

      // Instrucción para el navegador: “Descarga esto”
      &HttpResponse.AddHeader(!”Content-Disposition”, !”attachment;filename=” + Trim(&NombreArchivoDescarga))

      // Enviamos el archivo físico
      &HttpResponse.AddFile(&OutputFile.GetAbsoluteName())
      Else
      msg(‘Error crítico: No se pudo encontrar el documento generado en la ruta: ‘ + &PathFinal)
      EndIf
      EndIf

      3.2 Invocación desde el Web Panel

      Para ejecutar este procedimiento desde la pantalla del usuario sin romper la interfaz, se debe utilizar el método .Link().
      Fragmento de codigo a modo ejemplo:
      Event ‘DescargarDocumento’
      // Se invoca al procedure pasándole los parámetros necesarios
      &UrlDescarga = PimpCedNew.Link(&ORGCOD, &TDeNume, &TDeSec, &ICPCod, &PlaCod, ‘N’, ‘Y’, ‘Y’)

      // Navegamos a esa URL, el navegador detectará los headers y bajará el archivo
      Link(&UrlDescarga)
      EndEvent

      ////////////////////////////////////////////////////////////////////////////////////////
      Espero que les alla sido util y cualquier cosa mi codigo completo esta en el archivo PImpCedNew, el cual es llamado desde CerDeuWW.

     

Deja un comentario 0

Your email address will not be published. Campos requeridos marcados *