Los desarrolladores de sitios y aplicaciones móviles a menudo necesitan controlar la preparación de páginas PDF para imprimirlas o enviarlas a los clientes por correo.
Los archivos PDF tienen control total sobre la visualización de texto y gráficos en la página. Desafortunadamente, las bibliotecas para generar archivos PDF de población dinámica no se incluyen en las herramientas estándar de PHP, JS (Web), Java o Swift (Android e iOS, respectivamente). En este artículo quiero contarles sobre la solución de código abierto para generar archivos PDF.
JasperReports es una biblioteca Java de código abierto para generar archivos poblados dinámicamente. Tiene muchas herramientas para crear formularios de informes complejos, incluso en formato PDF, pero también hay otros formatos disponibles: RTF, DOCX, HTML, XLS, XLS, CSV y XML. En otras palabras, es suficiente desarrollar un formulario, hacer un diseño, y será posible exportarlo a cualquiera de los formatos anteriores.
También hay buenas bibliotecas, como PDFLib (versión comercial) para PHP y su versión de código abierto de PDFLib-Lite. Es cierto que la biblioteca es bastante costosa, y la versión lite se distribuye solo en el código fuente, y cuando se instala en el entorno de desarrollo, esta limitación puede convertirse en un problema.
PDFbox es otra biblioteca Java de código abierto para trabajar con documentos PDF. Le permite crear nuevos documentos PDF, administrar documentos existentes con la capacidad de extraer contenido de ellos. Pero no tiene una interfaz de usuario (interfaz de usuario), a diferencia de JasperReports.
Creo que JasperReports es especialmente útil en grandes proyectos relacionados con informes y no solo en formato PDF. Tiene todo lo que necesita para implementarlo en su proyecto: creación simple de formularios de informes complejos, interfaz de usuario para un diseño conveniente, aplicación de servidor e integración simple con el frente.
En el artículo trataré los siguientes temas:
- Instale el entorno de desarrollo y la aplicación del servidor.
- Cree un archivo PDF poblado automáticamente desde la base de datos.
- Integración de la aplicación del servidor con el front-end para obtener el PDF creado.
Para comenzar a usar JasperReports en su proyecto, debe descargar dos aplicaciones: JaspersoftStudio, en lo sucesivo lo llamaremos
entorno de trabajo , y JasperServer, llamaremos a la
aplicación del servidor .
JaspersoftStudio es un entorno de desarrollo basado en Eclipse con la biblioteca Java JasperReports incorporada, donde se desarrollan archivos PDF dinámicos o estáticos: por ejemplo, tickets, recibos, contratos, gráficos analíticos y otros.
JasperServer es una aplicación de servidor donde los archivos se implementan y almacenan desde JaspersoftStudio. Se puede acceder desde una aplicación móvil o web. JasperServer tiene una interfaz de usuario, con la que puede ver informes, crear cuentas para diferentes usuarios y darles el acceso adecuado. También puede configurar la lista de correo para enviar por correo electrónico (Programador).
Configurar el entorno de trabajo y la aplicación del servidor
Puede descargar e instalar aplicaciones utilizando los enlaces anteriores. Después de la configuración de dos aplicaciones, es necesario establecer una conexión desde el entorno de trabajo a la aplicación del servidor.
Servidores → Crear conexión de servidor JasperReports → Especifique el nombre del servidor preferido,
URL , nombre de usuario y contraseña. Haga clic en
Probar conexión para verificar que se haya establecido la conexión con el servidor. Si ve
Exitoso , vaya más allá.

Cree un PDF que se llene dinámicamente y publíquelo
Instalamos el entorno de desarrollo, el servidor y establecimos una conexión entre ellos. Ahora creemos un archivo PDF primitivo que se llena dinámicamente, que cuando se inicia (genera) tomará datos de PostgreSQL y lo instalará en una aplicación de servidor.
En primer lugar, debe fijar la fuente de datos (en nuestro caso, PostgreSQL) al entorno de trabajo, desde donde el PDF tomará los datos. Entonces comencemos a desarrollar nuestro primer archivo PDF.
Adaptadores de datos → Crear adaptador de datos → Conexión JDBS de base de datos y especificar los datos de conexión:
- Controlador JDBC : PostgreSQL (org.postgresql.Driver). Si no hay un controlador para su DBMS, puede instalar el controlador necesario en la pestaña Driver Classpath.
- URL JDBC : consta de su host, puerto y nombre de la base de datos.
- Nombre de usuario y contraseña : pase de registro desde su cuenta DBMS.

Hacemos clic en el botón
Prueba que ya nos es familiar y luego de una conexión exitosa (Exitosa) con la base de datos -
Finalizar .
A partir de esta base de datos, el PDF se completará en el entorno de producción. Dado que también estamos planeando implementar nuestro primer archivo PDF en el servidor, atornillemos la misma fuente de datos a la aplicación del servidor:
Fuentes de datos → Agregar recurso → Fuente de datos y repita todo desde el punto anterior.
Ahora estás listo para crear el PDF. Las fuentes en JasperReports se almacenan en formato JRXML: este es XML con etiquetas y atributos cableados con los que funciona la API JasperReports.
Haga clic en
Archivo → Nuevo → Informe Jasper → Blanco A4 → Especifique el nombre del archivo JRXML → Finalizar .

Después de crear un nuevo proyecto, verá la siguiente imagen:

Siete bloques diferentes: cada bloque tiene su propio comportamiento que es diferente de los demás. Puede leer más sobre esto en la
documentación . Al hacer clic en Fuente, puede ver la estructura de estos bloques:
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Example" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="ae9517f6-ff0b-41bb-a8dc-82196190e940"> <queryString> <![CDATA[]]> </queryString> <background> <band splitType="Stretch"/> </background> <title> <band height="79" splitType="Stretch"/> </title> <pageHeader> <band height="35" splitType="Stretch"/> </pageHeader> <columnHeader> <band height="61" splitType="Stretch"/> </columnHeader> <detail> <band height="125" splitType="Stretch"/> </detail> <columnFooter> <band height="45" splitType="Stretch"/> </columnFooter> <pageFooter> <band height="54" splitType="Stretch"/> </pageFooter> <summary> <band height="42" splitType="Stretch"/> </summary> </jasperReport>
Entonces, eliminemos cinco bloques adicionales y dejemos solo dos: Título y Detalle. El botón
Eliminar (Windows) o
Retroceso (OS X) nos ayudarán con esto.
Ahora agregue dos elementos. Puede agregar un nuevo elemento de dos maneras: registre el contenedor en la estructura XML (botón
Fuente ) o arrastre el elemento deseado desde la ventana superior derecha de
Pallette - Texto estático, donde habrá nombres de campo y Campo de texto, dentro del cual rellenaremos los campos variables extraídos de la base de datos:
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Example" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="ae9517f6-ff0b-41bb-a8dc-82196190e940"> <queryString> <![CDATA[]]> </queryString> <background> <band splitType="Stretch"/> </background> <title> <band height="30" splitType="Stretch"> <staticText> <reportElement x="0" y="0" width="100" height="30" uuid="7b697ed9-f52a-483c-965e-f0b2dc6130c1"/> <text> <![CDATA[Static Text]]> </text> </staticText> </band> </title> <detail> <band height="169" splitType="Stretch"> <textField> <reportElement x="0" y="0" width="100" height="20" uuid="41002e0b-ddb2-4e4b-a049-10810ab51208"/> <textFieldExpression> <![CDATA["Text Field"]]> </textFieldExpression> </textField> </band> </detail> </jasperReport>
La consulta en la base de datos se puede escribir en la etiqueta
queryString o hacer clic en el botón de
diálogo Editor de conjuntos de datos y consultas . Después de eso, se abrirá una nueva ventana donde deberá seleccionar una fuente de datos (1), escribir una consulta (2) y declarar variables de campo. El botón
Leer campos (3) leerá todos los campos automáticamente a solicitud
válida . Para ver los datos, haga clic en
Vista previa de datos (4).

Genial Tenemos cuatro campos de tipo String, ahora podemos realizar casi cualquier manipulación con ellos. Por ejemplo, simplemente los enumeramos y escribimos una pequeña lógica.
Imprimimos los nombres de los campos obligatorios en los elementos de Texto estático y los colocamos en el contenedor Título. Indicaremos campos variables en los elementos de Campo de texto en el contenedor Detalle, ya que se multiplicarán. Nuestro PDF mostrará el nombre, la ciudad y la dirección de correo electrónico. Para no aburrirse por completo, escribamos una lógica simple en el elemento Campo de texto, usando el cuarto campo: el sexo del cliente, Sexo.
Hacemos lo siguiente: si el cliente es una mujer, se agregará la Sra. Delante del nombre, si el hombre es el Sr. Para hacer esto, use el operador ternario de Java:
<textFieldExpression> <![CDATA[$F{sex}.equals( "male" )?"Mr. "+$F{name}:"Mrs. "+$F{name}]]> </textFieldExpression>
Al hacer clic en
Vista previa al lado del botón
Fuente , puede ver el resultado:

Como puede ver en la captura de pantalla, el PDF se ensambló con éxito: tomó todos los valores y aplicó la lógica, desprestigiando correctamente a Mrs. y el señor
También obtendremos el parámetro de entrada Ciudad para que sea posible filtrar los datos por ciudad. Esto se puede hacer haciendo clic en
Parámetros → Crear parámetro en la ventana Esquema, o agregando una nueva etiqueta de
parámetro con el
nombre y
los atributos de
clase :
<parameter name="City" class="java.lang.String"/>
Solo queda agregar el parámetro a la consulta SQL:
SELECT Id, name, sex, city, email FROM users WHERE city = $P{City}
Pasamos el valor San Francisco al parámetro Ciudad (en el siguiente párrafo le diré cómo hacerlo) y hacemos clic en
Vista previa de datos para ver el resultado.
El PDF se recopiló filtrando con éxito los datos. Vamos mas lejosComo ya tenemos un archivo PDF que se llena dinámicamente, podemos subirlo al servidor para una mayor integración con nuestras aplicaciones front-end. Para hacer esto, haga clic en el botón
Publicar informe en el servidor JasperReports → haga doble clic para abrir el servidor → Seleccione la carpeta del servidor donde descargar el PDF (en nuestro caso,
informes ) →
Siguiente → Fuente de datos del repositorio → seleccione la fuente de datos que se creó anteriormente en la aplicación del servidor →
Finalizar .
Integración Frontend
La API JasperReports incluye su propia implementación RESTful para la interacción cliente-servidor:
REST v2 . Si no le conviene, puede usar un protocolo simple de acceso a objetos:
SOAP .
Consideraremos REST v2.
Los cuatro métodos principales para las acciones CRUD (Crear-Leer-Actualizar-Eliminar) están disponibles: GET (obtener), POST (agregar, cambiar, eliminar), PUT (agregar, reemplazar), BORRAR (eliminar). Toda la información detallada está disponible en la documentación en los enlaces anteriores.
Consideraremos el método GET más común y relevante para este artículo.
http://<host>:<port>/jasperserver[pro]/rest_v2/reports/path/to/report.<format>?<arguments>
Arriba hay una solicitud
síncrona , con la que puede obtener la salida del archivo (PDF terminado) en una solicitud-respuesta (puede encontrar la llamada asincrónica
aquí ).
Creo que todo está claro con el host y el puerto, y
/ reports / path / to / report es el URI del archivo al que se llama. Como desplegamos la fuente del archivo PDF (Example.jrxml) en la carpeta del servidor de informes, la versión completa del URI será: / reports / reports / Example.
formato es un formato (en nuestro caso, PDF).
Los argumentos son parámetros.
Arriba, agregamos el parámetro Ciudad, y lo pasaremos en la solicitud con el valor San Francisco para filtrar los datos de esta ciudad.
Si la llamada no proviene de una zona autorizada, debe agregar dos parámetros / atributos más:
j_username y
j_password (pase de registro para autorización). Por defecto, el nombre de usuario y contraseña en el servidor es
jasperadmin .
Por lo tanto, obtenemos la siguiente URL:
http://localhost:8080/jasperserver/rest_v2/reports/reports/Example.PDF?city=San Francisco&j_username=jasperadmin&j_password=jasperadmin
Entonces obtenemos un PDF ya generado. Por ejemplo, cuando llama a esta URL a través de la barra de direcciones del navegador, el archivo debe descargarse automáticamente.
Es posible que deba mostrar una imagen PDF. Por ejemplo, si el cliente solo quiere ver el archivo, puede mostrar el documento en formato PNG, si desea descargarlo, luego en PDF.
Usando Java como ejemplo usando la biblioteca PDFbox, veremos cómo puede generar y elegir un archivo PDF desde una aplicación externa, y luego convertirlo a PNG.
A continuación se muestra la clase
PullPDF con un método que toma una URL como argumento.
import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URL; import java.util.Base64; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.tools.imageio.ImageIOUtil; public class PullPDF { public String ConvertPDF2PNG(String valuefromParam) throws IOException { BufferedInputStream input_file = new BufferedInputStream(new URL(valuefromParam).openStream()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { PDDocument document = PDDocument.load(input_file); PDFRenderer pdfRenderer = new PDFRenderer(document); for (int page = 0; page < document.getNumberOfPages(); ++page) { BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB); ImageIOUtil.writeImage(bim, "png", baos); baos.flush(); byte[] encodedBytes = Base64.getEncoder().encode(baos.toByteArray()); valuefromParam = new String(encodedBytes); } } catch (Exception e) { } return valuefromParam; } }
Puede obtener el mismo resultado utilizando, por ejemplo, Spring Framework. Pero traté de mostrar una forma universal que se puede aplicar tanto en Android como en la web al trabajar con Java.
Conclusión
Si desea automatizar la generación de un cheque simple para una tienda en línea y tiene un tiempo limitado para crearlo, le recomiendo usar las herramientas nativas de su proyecto o el marco familiar. Dado el tiempo dedicado a instalar JasperReports, la familiarización con la documentación para el desarrollo de formularios de informes más complejos puede no estar justificada. En otros casos, JasperReports es una buena solución de código abierto para la automatización de informes.