jueves, 9 de agosto de 2007

Generación e impresión de informes en formato PDF desde Java con software libre

Hola Mundo!
Bueno, como se puede apreciar, quiero comenzar con este blog con buen humor y con un tema que, a mi parecer, resulta muy interesante. Hace unos días me topé con la tediosa labor de abordar el desarrollo de una aplicación java que fuera capaz de generar informes en formato PDF, y lo más difícil, imprimirlos. Tras muchos calentamientos de cabeza (sobre todo con el asunto de la impresión bajo Java) y muchísimas horas googleando llegué a encontrar la solución a este problema, y lo que es mejor aún, a través del uso de software libre ;-) . Seguidamente detallo el proceso.
Lo primero que necesitamos es descargar la herramienta de generación de informes DataVision (http://datavision.sourceforge.net). Esta herramienta, aunque sencilla, es de gran flexibilidad y se integra a la perfección con Java. Una vez descargada la descomprimimos y accedemos al directorio que se ha generado. Llegados aquí vemos varios archivos, los más importantes datavision.bat y datavision.sh. Ejecutaremos el que corresponda en función a nuestro sistema operativo y nos aparecerá un cuadro de diálogo inicial en el que se nos muestran las opciones iniciales:


Aquí le diremos a DataVision que deseamos crear un nuevo informe, por lo que pinchamos sobre el botón Start a New Report. Con ello este cuadro de diálogo se cerrará para dejar paso a una ventana que, a priori, nos puede intimidar ya que parece que nos pide gran cantidad de información. No hemos de asustarnos ya que ese no es el objetivo de esta última ventana, sino que lo que nos requiere es información acerca de la conexión con el DBMS (Servidor de Bases de Datos Relacionales). Habremos de cumplimentar dicha información:

Para el que ande un poco perdido:
Nombre de Clase del Controlador: Nombre de la clase que sirve como driver para JDBC. En mi caso, como estoy utilizando el SGBDR MySQL, utilizo la clase com.mysql.jdbc.Driver que previamente descargué de http://www.mysql.org. Por cierto, nunca hay que olvidar añadir el paquete jar que contiene dicha clase a la variable de entorno CLASSPATH. Información de la Conexión: Es la cadena de conexión JDBC. La que he usado yo es jdbc:mysql://localhost/blog. Ya que estoy accediendo, a través de JDBC, a la base de datos blog de un servidor MySQL que tengo instalado en mi máquina local.
Nombre de la Base de Datos, Nombre de Usuario y Contraseña: Bueno, con respecto a esto creo que hay poco que decir.
Proporcionados los datos correctos pulsamos sobre el botón Aceptar y, si todo ha ido bien, nos aparecerá la siguiente ventana:


En ella nos aparecen las secciones del informe y una barra de menú, a través de la cual se puede acceder a las distintas opciones. Si no estamos familiarizados con las secciones de un informe podemos consultar la documentación de DataVision (en formato HTML). En mi caso voy a realizar el informe para una tabla de alumnos, de los que almaceno su DNI, nombre, sexo y fecha de nacimiento.
Podemos comenzar añadiendo al encabezado del informe un título, como por ejemplo: Informe sobre los alumnos. Para ello seleccionamos Insertar->Texto. Pinchamos la sección Encabezado del reporte y escribimos el texto. Si deseamos modificar el formato del texto no tenemos más que acceder a Formato->Formato de campo. Ahora vamos a insertar lo que verdaderamente nos importa: los datos de nuestra tabla. Para hacer esto pulsamos en Insertar->Campo de Base de datos. Nos parece una nueva ventana en la cual accedemos a la tabla que deseemos y arrastramos los campos necesarios sobre la sección Detalle del informe. Una vez situados, si es necesario, podemos acceder al menú Formato el cual nos posibilita poner a punto ciertos aspectos tales como la alineación y el tamaño. Finalmente, en el pie de pagina vamos a insertar dos campos especiales: numero de página y nombre del autor. Para ello procedemos de forma similar a la que hemos hecho para insertar los campos de la tabla. Si hemos seguido estas indicaciones el aspecto final del informe es el siguiente:


Para guardar este informe y que pueda ser accedido a través de Java vamos a pulsar sobre Archivo->Guardar. Elegimos la ruta donde queremos almacenarlo y le nombraremos, por ejemplo, alumnos.xml. Antes de guardar el fichero también es interesante acceder al menú Archivo->Tamaño de papel y modificar el valor dado, ya que lo más normal es generar el informe para tamaño A4.
Llegados hasta aquí ya estamos listos para generar nuestro informe en formato PDF desde Java. A continuación se muestra un sencillo programa que genera el informe anterior en PDF y establece el nombre del autor del informe en tiempo de ejecución:

import jimm.datavision.*;
import jimm.datavision.layout.pdf.PDFLE;
import java.sql.Connection;
import java.sql.DriverManager;
import java.io.FileOutputStream;
import java.io.File;

public class Ejemplo{
public static void main(String[] args){
Report r = new Report();
Connection con = null;

try{
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost/blog",
"root", "passwd");

r.setDatabaseConnection(con);
}
catch(Exception e){
System.err.println(e.getMessage());
System.exit(-1);
}

FileOutputStream pdf = null;
File xml = null;

try{
pdf = new FileOutputStream("C:\\alumnos.pdf");
xml = new File("C:\\alumnos.xml");
}
catch(Exception e){
System.err.println(e.getMessage());
System.exit(-2);
}

try{ r.read(xml); }
catch(Exception e){ System.exit(-3); }

r.setAuthor("Juan Ángel Gascón Moya");
r.setLayoutEngine(new PDFLE(pdf));
r.runReport();
}
}
Para poder compilar este programa es necesario tener en el CLASSPATH los ficheros jar que contiene el directorio bin de DataVision y el driver del DBMS. Como se aprecia en el fuente DataVision nos proporciona una clase, Report, que es la que vamos a utilizar para generar nuestros informes. Una vez creado un objeto de dicha clase debemos de proporcionarle la información necesaria para que sea capaz de acceder a la base de datos. Existen varias maneras, pero en este ejemplo se ha optado por llamar al método setDatabaseConnection(java.sql.Connection) el cual recibe como parámetro un objeto Connection que esté inicializado. Lo siguiente que hay que hacer es indicarle al objeto Report cuál es el fichero XML que generamos anteriormente con DataVision. Para hacer esto utilizamos el método read(java.io.File). Dicha operación recibe un objeto de tipo File que ya esté inicializado con el fichero XML al que se va a acceder. Ahora hemos de establecer el formato con el que deseamos que se genere el informe, por eso hacemos uso del método setLayoutEngine(jimm.datavision.layout.LayoutEngine). DataVision nos permite generar informes en múltiples formatos como HTML, texto separado por comas, XML, LaTeX... En nuestro caso como vamos a crear un informe en formato PDF utilizamos la clase jimm.datavision.layout.pdf.PDFLE. El único constructor de esta clase recibe como argumento un objeto de la clase abstracta java.io.OutputStream. En este caso concreto se ha utilizado un objeto FileOutputStream que indica el fichero PDF que se va a generar. También se puede apreciar que se ha establecido en tiempo de ejecución el nombre del autor del informe. Es importante que los métodos como este, que establecen ciertas propiedades del informe, sean llamados tras la ejecución del método read(java.io.File) ya que en otro caso no surtirán ningún efecto. En la última línea se hace una llamada al método runReport() el cual es el encargado de realizar la generación del informe a partir de los datos que previamente le hemos proporcionado. Además de este método existe el método run() que realiza exactamente la misma función, pero en un hilo (thread) a parte.
Pues bien lo único que nos queda es compilar y luego ejecutar este programa para obtener nuestro informe en formato PDF. Como ya se ha dicho antes, es muy importante que todos los ficheros jar utilizados estén en el CLASSPATH. Si hacemos uso de un buen entorno de desarrollo nuestra labor se verá bastante simplificada. Como opinión personal recomiendo el IDE netbeans (http://www.netbeans.org) el cual considero como un excelente entorno de desarrollo para java, y además es software libre.

Bueno, hasta aquí hemos llegado para realizar la generación de informes en formato PDF, pero ahora viene la parte más complicada: imprimir un archivo PDF desde java. Digo que esta parte es complicada y el que halla tenido que abordar el tema de impresión desde java, y en especial, la impresión de ficheros en formato PDF sabe porque lo digo. Para realizar esta labor vamos a hacer uso de, como no, software libre: PDFBox (http://www.pdfbox.org/).

Los propios autores de PDFBox lo definen como una librería open source para java trabajar con documentos PDF. Además incluye un conjunto de programas (hechos en java, por supuesto) para trabajar con ficheros PDF desde la línea de comando. Estos programas van desde encriptadores y extractores de texto hasta conversores de PDF a imagen y, el más importante en el tema que abordamos, impresores de PDF. Concretamente el programa que nos permite imprimir un fichero PDF desde el prompt de nuestra línea de comando es el PrintPDF. Este comando, además de las opciones que se desee incluir, recibe un único argumento: el documento PDF a imprimir. Si deseamos imprimir el informe PDF generado anteriormente operaremos de la siguiente forma:
  • Una vez descargado PDFBox lo descomprimimos.
  • Accedemos a través de una terminal al directorio lib.
  • Lanzamos el comando para imprimir. En mi caso, que me he descargado la versión 0.7.3 y estoy utilizando windows, lo hago de la siguiente manera:
 prompt> java -cp ..\external\FontBox-0.1.0-dev.jar;
.\PDFBox-0.7.3.jar; org.pdfbox.PrintPDF
c:\alumnos.pdf
Nótese que además de incluir el fichero jar de PDFBox en el CLASSPATH también he añadido el paquete FontBox ya que es requerido por el anterior. También hay que tener cuidado si estamos en Linux ya que el separador que debemos de usar para la variable de entorno es : en lugar del ; que se utiliza en Windows. Al lanzar el comando nos aparecerá una ventana similar a esta:


A partir de aquí podremos imprimir el documento. Las formas de integrar esta funcionalidad en nuestra aplicación java son varias. Podemos usar directamente el comando mediante Runtime.getRuntime().exec(java.lang.String), o, como al ser open source el código fuente, está incluido, podemos adaptar el programa PrintPDF a nuestra aplicación codificándolo como una clase. Esto es una decisión personal del programador por lo que no indagaré más en este asunto.

Y ya poco más que decir. Tanto DataVision como PDFBox son compatibles con apache ant (http://ant.apache.org). Esto hace mucho más fácil la modificación y recompilación del fuente. También, quiero decir que en este artículo he expuesto una mínima parte, tanto de DataVision como de PDFBox. Ambas aplicaciones constan de multitud de clases y librerías, además son muchas sus funcionalidades. Por ello animo a cualquiera que tenga interés en este software que pase por las webs de estas respectivas aplicaciones y consulte su documentación.

Espero que este artículo halla sido de utilidad y estoy abierto a cualquier comentario. Un saludo.

No hay comentarios: