sub reports tutorial

18
JasperReports, iReport y Subreportes Francesc Ros és A lbiol Novie mbr e 2004 v. 1.0 INTRODUCCIÓN Y JUSTIFICACIÓN Últimamente, han aparecido en los fórums de javaHispano diversas preguntas sobre un mismo tema: la incorporación de subreportes en JasperReports. Hasta la fecha, no he tenido que usar subreportes, pero siempre hay una primera vez y, finalmente, me he tenido que enfrentar a ello. Lo primero que hice fue buscar información al respecto y me topé con la cruda realidad: Hay poca o no me alcanza para lo que quiero hacer. En la documentación de JasperReports, y más concretamente en el documento Tutorial (http://jasperreports.sourceforge.net/tutorial/index.html ), aparece un apartado que lleva por título “Subreports”, pero al acceder a él me encuentro con tres líneas y un aviso en rojo: Documentation pending.... Afortunadamente, en las demos de JasperReports aparece un ejemplo que proporciona varias ideas al respecto. Acto seguido, voy a ver qué hay en mi interficie gráfica favorita para la generación de reportes: iReport-Designer for JasperReports (http://ireport.sourceforge.net/ ). Allí encuentro más información al respecto. En el manual, sólo dice que iReport soporta subreportes, pero encuentro un par de tutoriales 1 sobre el tema. El primero, How to create a subreport (http://ireport.sourceforge.net/subreport_tutorial.zip ), de Shailesh Kadam, es del 2003 y lo encuentro un poco incongruente. Se basa en dos tablas, una de empleados y otra de direcciones, y nos dice que un empleado puede tener cero o más direcciones asociadas. La verdad es que no sé cómo asocia direcciones a un empleado, ya que no hay ningún campo que enlace ambas tablas ni tabla alguna que enlace empleados y direcciones. Además, si existiera el enlace, no haría falta el uso de subreportes para mostrar las direcciones asociadas a un empleado. Un simple grupo nos resolvería el problema. El segundo es un vídeo creado por unos usuarios hawaianos (http://ireport.sourceforge.net/swf/Subreport_viewlet_swf.htm ) y parece más reciente. Una vez más, nos encontramos con un ejemplo basado en una relación maestro-detalle: disponemos de una tabla de países y otra de estados o provincias de cada país. El tutorial muestra la mecánica bastante bien, pero el ejemplo, a mi entender, no es del todo bueno porque puede resolverse usando grupos. El objetivo de este tutorial es, pues, intentar cubrir la falta de documentación sobre el uso de subreportes en JasperReports. No pretendo en ningún momento que este tutorial se convierta en un tutorial de JasperReports ni de iReport. Doy por supuesto que el lector conoce el funcionamiento de ambos productos y que sólo desea profundizar en el uso de subreportes. Tampoco quiero cubrir todas las posibilidades de los subreportes. Me centraré en un ejemplo 1 Parece ser que la Real Academia de la Lengua Española todavía no acepta la palabra tutorial (-es). Sin embargo, yo la uso porque entiendo que un tutorial es un subtipo de manual y no hallo otra palabra en castellano que pueda usar. 1 de 18

Upload: gabriel-diaz-gabriel

Post on 04-Jul-2015

1.233 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Sub Reports Tutorial

JasperReports, iReport y SubreportesFrancesc Rosés Albiol

Noviembr e 2004v. 1.0

INTRODUCCIÓN Y JUSTIFICACIÓNÚltimamente, han aparecido en los fórums de javaHispano diversas preguntas sobre un mismotema: la incorporación de subreportes en JasperReports.

Hasta la fecha, no he tenido que usar subreportes, pero siempre hay una primera vez y, finalmente,me he tenido que enfrentar a ello.

Lo primero que hice fue buscar información al respecto y me topé con la cruda realidad: Hay poca ono me alcanza para lo que quiero hacer.

En la documentación de JasperReports, y más concretamente en el documento Tutorial(http://jasperreports.sourceforge.net/tutorial/index.html), aparece un apartado que lleva por título“Subreports”, pero al acceder a él me encuentro con tres líneas y un aviso en rojo: Documentationpending.... Afortunadamente, en las demos de JasperReports aparece un ejemplo que proporcionavarias ideas al respecto.

Acto seguido, voy a ver qué hay en mi interficie gráfica favorita para la generación de reportes:iReport-Designer for JasperReports (http://ireport.sourceforge.net/). Allí encuentro másinformación al respecto. En el manual, sólo dice que iReport soporta subreportes, pero encuentro unpar de tutoriales1 sobre el tema.

El primero, How to create a subreport (http://ireport.sourceforge.net/subreport_tutorial.zip), deShailesh Kadam, es del 2003 y lo encuentro un poco incongruente. Se basa en dos tablas, una deempleados y otra de direcciones, y nos dice que un empleado puede tener cero o más direccionesasociadas. La verdad es que no sé cómo asocia direcciones a un empleado, ya que no hay ningúncampo que enlace ambas tablas ni tabla alguna que enlace empleados y direcciones. Además, siexistiera el enlace, no haría falta el uso de subreportes para mostrar las direcciones asociadas a unempleado. Un simple grupo nos resolvería el problema.

El segundo es un vídeo creado por unos usuarios hawaianos(http://ireport.sourceforge.net/swf/Subreport_viewlet_swf.htm) y parece más reciente. Una vez más,nos encontramos con un ejemplo basado en una relación maestro-detalle: disponemos de una tablade países y otra de estados o provincias de cada país. El tutorial muestra la mecánica bastante bien,pero el ejemplo, a mi entender, no es del todo bueno porque puede resolverse usando grupos.

El objetivo de este tutorial es, pues, intentar cubrir la falta de documentación sobre el uso desubreportes en JasperReports.

No pretendo en ningún momento que este tutorial se convierta en un tutorial de JasperReports ni deiReport. Doy por supuesto que el lector conoce el funcionamiento de ambos productos y que sólodesea profundizar en el uso de subreportes.

Tampoco quiero cubrir todas las posibilidades de los subreportes. Me centraré en un ejemplo

1 Parece ser que la Real Academia de la Lengua Española todavía no acepta la palabra tutorial (-es). Sin embargo, yola uso porque entiendo que un tutorial es un subtipo de manual y no hallo otra palabra en castellano que pueda usar.

1 de 18

Page 2: Sub Reports Tutorial

concreto que, creo y deseo, sirva de inspiración al lector para usar subreportes.

ESCENARIONuestro escenario va a ser un proceso de matrícula a una serie de cursos. Una persona se matricula auno o más cursos y debe saber qué le va a costar en total. La inscripción en un curso supone el pagode una matrícula inicial y una serie de mensualidades.

Nuestro informe debe generar una simulación de la factura de la matrícula y, además, mostrar elprecio de cada mensualidad, el total de mensualidades a pagar y el importe total de mensualidades.

Para ello, hemos diseñado una base de datos con la siguiente estructura:

El significado de la mayor parte de las columnas de las tablas se puede deducir fácilmente de sunombre. Quizá la tabla menos clara sea la de Cursos. Comento, pues, las columnas que la forman:

Columna ComentarioID Es la clave primaria. Un entero autoincrementadoNOMBRE Contiene los nombres de los cursos (p.e. Curso 1, Curso 2, etc.)MATRICULA Contiene los precios de las matrículas de los distintos cursosMENSUALIDAD Contiene los precios de cada una de las mensualidades a pagar por cada

cursoMENSUALIDADES Contiene el número de mensualidades a pagar por cada curso

Tabla 1: Descripción de la tabla Cursos

Obsérvese que el informe que deseamos no se corresponde con el típico maestro-detalle. En realidadestamos hablando de dos informes en uno.El primero nos va a mostrar los datos de la persona, en este caso sólo nombre y apellidos, y losgastos detallados que va a tener que pagar en concepto de matrículas.

El segundo nos va a mostrar cuánto va a tener que pagar al mes por cada uno de los cursosmatriculados, durante cuántos meses y el importe total por curso.

Como la descripción de una imagen nunca le hace justicia, veamos, pues, qué es lo que realmentequeremos obtener en nuestro informe:

2 de 18

Figura 1: Esquema de tablas

Page 3: Sub Reports Tutorial

Nuestro reporte tiene cuatro partes diferenciadas:

1. Un título: “Presupuesto de cursos”

2. Información sobre la persona: “ARAGÓN LÓPEZ, Pedro”

3. Información sobre la matrícula

4. Información sobre las mensualidades

Las partes 1, 2, y 3 configuran el reporte maestro y la 4, mensualidades, es el subreport.

REPORTES Y SUBREPORTESUn reporte es un informe resultado del proceso, más o menos complejo, de datos que puedenproceder de diversas fuentes. Lo más frecuente, en el ámbito informático, es que los datos procedande una base de datos.

No hay diferencia entre un reporte y un subreporte. Todo reporte pasa a convertirse en subreporte encuanto forma parte de otro reporte.

Este concepto es importante, ya que nos indica que no hay que hacer nada especial para diseñar unsubreporte. Se diseña de la misma manera que un reporte cualquiera.

En este tutorial, llamaremos reporte maestro a aquél que contiene algún otro reporte, y a los reportes

3 de 18

Figura 2: Aspecto del informe final

Page 4: Sub Reports Tutorial

que forman parte del maestro, los llamaremos subreportes.

ESTRATEGIA DISEÑOComo he comentado más arriba, no hay diferencia entre reporte y subreporte ya que ambos sonreportes, sin embargo para conseguir el informe que deseamos, hemos de enlazarlos.

Así pues, el grueso de este tutorial se centrará en cómo establecer el enlace entre el reporte maestroy el subreporte.

Nuestra estrategia es sencilla:

1. Diseñar el reporte maestro un elemento vacío de subreporte

2. Diseñar el subreporte como un reporte más

3. Definir los enlaces entre el reporte maestro y el subreporte

Después de llevar a cabo los puntos 1 y 2 debemos ser capaces de visualizar por separado reporte ysubreporte usando iReport.

La siguiente imagen muestra el resultado de la visualización de nuestro reporte maestro antes deligarlo al subreporte:

Y la que sigue nos muestra la visualización del subreporte por separado:

4 de 18

Figura 3: Vista previa del reporte maestro

Page 5: Sub Reports Tutorial

DISEÑO DE REPORTE MAESTRO Y SUBREPORTENo es mi intención, como ya he comentado, extenderme demasiado en la descripción de los diseñosdel reporte y subreporte. El tutorial incluye los fuentes de los reportes y de la clase Java que losmuestra, así que sólo comentaré los puntos más significativos.

Reporte maestro

ConsultaEl reporte maestro nos muestra la información existente en nuestra base de datos sobre la matrículade una persona en concreto. Para obtener dicha información, usamos la siguiente consulta SQL:

SELECT P.ID, P.NOMBRE AS NOMBRE, P.APELLIDOS, C.NOMBRE AS CURSO,C.MATRICULA FROM PERSONAS P, CURSOS C, PERSONA_CURSOS PC WHERE P.ID = $P{PERSONA_ID} AND PC.ID_PERSONA = P.ID AND PC.ID_CURSO = C.ID

Obsérvese que para identificar a la persona sobre la que queremos realizar el reporte usamos unparámetro: $P{PERSONA_ID}.2

Este parámetro deberá ser pasado por nuestro programa a la instancia denet.sf.jasperreports.engine.JasperReport para que en el momento de llenado delreporte, éste sepa de qué persona debe obtener los datos.

Obsérvese, también, que a la columna C.NOMBRE de la tabla CURSO, le asignamos el alias CURSO.Dicha columna contiene el nombre del curso.

CamposLos campos se generan a partir de la consulta SQL. La siguiente tabla presenta una descripción

2 Es conveniente crear el parámetro PERSONA_ID antes de crear la consulta, ya que si no existe, no puede serreferenciado en la consulta.

5 de 18

Figura 4: Vista previa del subreporte

Page 6: Sub Reports Tutorial

somera de los mismos:

Campo DescripciónAPELLIDOS Los apellidos de la personaCURSO El nombre del cursoID El identificador único de la personaMATRICULA El precio de la matrícula del cursoNOMBRE El nombre de la persona

Tabla 2: Descripción de los campos

Estructura: BandasTrabajamos con cuatro de las bandas que nos ofrece JasperReports:

• Title• Título del reporte: “Presupuesto de cursos”

• Group Header• El texto estático “MATRÍCULA”

• El campo ID, que se usa como dato de corte para el grupo. Este campo será invisible.

• La variable PERSONA: resultado de la concatenación de los campos APELLIDOS yNOMBRE, pasando los apellidos a mayúsculas y separándolos del nombre por una coma

• Los textos estáticos “Concepto”, “Base Imponible”, “IVA 16%” y “Total”

• Detail• Los campos de texto asociados a los campos CURSO y MATRICULA• La variable IVA, resultado de multiplicar el campo MATRICULA por 0,16• La variable MATR_SUBTOT, resultado de sumar el campo MATRICULA a la variable IVA

• Group Footer• El texto estático “TOTAL MATRÍCULAS”

• La variable MATR_TOTAL_IVA, resultado de sumar los valores de la variable IVA paracada registro

• La variable MATR_TOTAL, resultado de sumar los valores de la variable MATR_SUBTOTpara cada registro

• El texto estático “MENSUALIDADES”

• El elemento SUBREPORT

• Page Footer• La fecha y el número de página

Estructura: GrupoComo nuestro reporte hace referencia a una sola persona, no tiene mucho sentido crear un grupo yaque sólo podemos agrupar a nuestra persona con ella misma.

6 de 18

Page 7: Sub Reports Tutorial

Sin embargo, nos conviene crearlo desde el punto de vista de la facilidad de presentación. Si no lotuviéramos, deberíamos emplear la banda Column Footer para presentar los totales de matrícula y elsubreporte de mensualidades. El resultado sería que dicha banda nos presentaría los resultados alfinal de la página y quedaría poco estético.3

Para evitar este efecto no deseado, he optado por usar un grupo. Los grupos proporcionan la bandaGroup Footer interesante para nuestro ejemplo porque nos permite ubicar en ella, a nuestraconveniencia, tanto los totales de matrícula como el subreporte.

Subreporte

ConsultaEl subreporte nos presentará información sobre las mensualidades que una persona en concretodeberá pagar por cada uno de los cursos matriculados. Para obtener dicha información, usaremos lasiguiente consulta SQL:

SELECT C.NOMBRE AS CURSO, C.MENSUALIDAD, C.MENSUALIDADESFROM PERSONAS P, CURSOS C, PERSONA_CURSOS PCWHERE P.ID = $P{PERSONA_ID} AND PC.ID_PERSONA = P.ID AND PC.ID_CURSO = C.ID

Como en la consulta del reporte maestro, también aquí usamos un parámetro, $P{PERSONA_ID}para identificar a la persona.4

A diferencia de éste, como veremos más adelante, el valor del parámetro no se lo proporcionaránuestro programa, sino que lo tomará directamente del reporte maestro.

CamposLa siguiente tabla describe someramente los campos que se desprenden de la consulta SQL delsubreporte:

Campo DescripciónCURSO Nombre del cursoMENSUALIDAD Importe de cada mensualidad de un cursoMENSUALIDADES Número de mensualidades a abonar

Tabla 3: Campos a partir de la consulta SQL

Estructura: bandasLa estructura de bandas en el subreporte es mucho más sencilla que en el reporte. Sólo usaremosdos:

• Column Header• Los textos estáticos “Concepto”, “Mensualidad”, “Mensualidades” y “Total”

• Detail• Los campos de texto asociados a los campos CURSO, MENSUALIDAD y

3 Es muy posible que esto no sea así y que haya alguna manera de evitar el efecto no deseado de la Column Footer,pero yo la desconozco y creo que es poco relevante para el objetivo principal de este artículo.

4 Como como hemos visto en la descripción el reporte maestro, aquí también es conveniente crear el parámetroPERSONA_ID antes de definir la consulta.

7 de 18

Page 8: Sub Reports Tutorial

MENSUALIDADES• La variable SUBTOTAL_MENSUALIDADES, resultado de multiplicar los valores del

campo MENSUALIDAD por los del campo MENSUALIDADES

Inclusión del subreporte en iReportLa inclusión de un subreporte en un reporte usando iReport supone lo mismo que incluir un campode texto o un texto estático. Simplemente hay que pulsar el botón de Subreport tool de la barra deherramientas y después arrastrar el ratón en la banda que nos interese hasta conseguir el tamañodeseado para nuestro subreporte.

La siguiente imagen muestra la parte de la barra de herramientas que incluye el botón desubreportes:

ENLACE REPORTE MAESTRO – SUBREPORTEHemos visto hasta ahora cómo diseñar el reporte maestro y el subreporte y cómo reservar un espaciopara éste en el reporte maestro.

Fijémonos en el detalle. En realidad hemos reservado un espacio en el reporte maestro. Éste no sabeabsolutamente nada del subreporte que tiene que presentar.

Pensemos en lo que necesitaría saber el reporte maestro para poder presentar el subreporte.

¿Quién es? ¿Dónde está?Lo primero que se nos ocurre es que necesita tenerlo para poderlo cargar en el espacio que le hemosreservado.

Fijémonos que la manera más cómoda de pasárselo es mediante un parámetro. Nuestro programacreará una instancia de java.util.Map que contendrá la información necesaria para que elreporte maestro cargue el subreporte.

Una estrategia sería definir un parámetro de tipo String que nuestro programa rellenará con elpath completo de nuestro reporte. En alguno de los ejemplos que he consultado, han optado por estasolución. Sin embargo, yo le veo un problema si lo que pretendo es que el subreporte forme partedel archivo jar que contendrá nuestra aplicación.

Lo que haremos, pues, es definir en el reporte maestro un parámetro, al que llamaremosSUBREPORT, de tipo net.sf.jasperreports.engine.JasperReport.

Para ello, abriremos la vista de parámetros del menú View y accederemos a la ventana de definiciónde parámetros. En esta ventana, pulsaremos el botón New para acceder al diálogo que nos permitirádefinir nuestro parámetro. La siguiente figura intenta sintetizar lo dicho hasta ahora:

8 de 18

Figura 5: Botón de inclusiónde subreporte

Page 9: Sub Reports Tutorial

Obsérvese que en la ventana de definición de parámetro, bajo el título Parameter class type, hay undesplegable. Es posible que éste no contenga el tipo que nos interesa:net.sf.jasperreports.engine.JasperReport. Si es así, no hay problema ya que eldesplegable es editable y lo podremos escribir.

Una vez entrados los datos del parámetro, pulsamos OK y ya lo tendremos definido.

Bien, ya hemos establecido el mecanismo para que nuestro reporte maestro sepa qué tiene que poneren el espacio reservado para el subreporte.

¿Cómo lo lleno?Claro que con saber qué reporte ocupará el espacio reservado para el subreporte no hay bastante.Hemos de establecer los mecanismos para que este subreporte se pueda llenar con los datospertinentes.

Como hemos visto, nuestra fuente de datos es una base de datos. Para acceder a nuestra base dedatos necesitamos una conexión con ella.

Desde nuestro programa Java solemos abrir una conexión con la base de datos que queda plasmadaen un objeto de tipo java.sql.Connection. Esta instancia es la que usamos para llenarnuestro reporte maestro de datos, pasándosela como parámetro al método fillReport() de laclase net.sf.jasperreports.engine.JasperFillManager:

JasperPrint masterPrint = JasperFillManager.fillReport(masterReport, masterParams, con);

Más adelante, comentaremos esta llamada con más detalle. De momento, nos conformamos consaber que nuestro reporte maestro dispone de una conexión a la base de datos que va a usar paraejecutar la consulta SQL que hemos comentado más arriba.

9 de 18

Figura 6: Definición del parámetro SUBREPORT

Page 10: Sub Reports Tutorial

Esta conexión está guardada en un parámetro interno de nuestro reporte maestro que JasperReportsse encarga de crear para nosotros: REPORT_CONNECTION.

Curiosamente, iReport no muestra dicho parámetro en la ventana de definición de parámetros, perohay que tenerlo muy presente. El parámetro existe.

El lector, llegado a este punto, estará preguntándose el porqué de tanto preámbulo. Bien, esimportante entender qué hace un reporte para poder acceder y presentar después los datos. Hasta elmomento, hemos visto que el reporte maestro tiene información suficiente para ejecutar su consultay presentar sus datos, pero nos queda todavía entender cómo se las arreglará para que el subreportehaga lo propio ya que es el reporte maestro quien lanza el llenado del subreporte, al formar ésteparte de él.

Lo primero que hay que indicar es el método utilizado por el subreporte para acceder a los datos.Para ello, hacemos doble clic en el elemento subreporte, que hemos incluido en el reporte maestro,para acceder a sus propiedades y seleccionamos la segunda pestaña (Subreport):

Bajo el título Connection / Datasource expression, vemos una lista desplegable. De ella, podemosseleccionar el método que usará nuestro subreport para obtener los datos. En nuestro caso,seleccionamos el elemento Use connection expression ya que los vamos a obtener de una base dedatos mediante una conexión.

A continuación, escribimos la expresión que nos va a llevar a la conexión deseada. En nuestro caso,el parámetro REPORT_CONNECTION comentado más arriba.

Es decir, nuestro reporte maestro le va a pasar a nuestro subreporte la conexión referenciada en elparámetro REPORT_CONNECTION para que pueda ejecutar su consulta SQL.

10 de 18

Figura 7: Propiedades del subreporte - Subreport

Page 11: Sub Reports Tutorial

Volviendo a la lista desplegable, observamos que nos ofrece dos posibilidades más:

• Don't use connection or datasource• Use datasource expression

La primera, “no uses nada”, es útil si lo que le pasamos es un subreporte que no necesita ni de unafuente de datos ni de una conexión. Por ejemplo, si los datos de los que se nutre le sonproporcionados por parámetros.

La segunda, “Usa una expresión de datasource”, se utilizaría en el caso de que el subreporte sellenara directamente a partir de una fuente de datos que implementase la interficienet.sf.jasperreports.engine.JRDataSource como la clasenet.sf.jasperreports.engine.data.JRTableModelDataSource que se basa enun un modelo de javax.swing.JTable. En este caso, definiríamos un parámetro de tipoJRTableModelDataSource que contuviera la referencia a la fuente de datos deseada.

Acabamos de ver que dependiendo del método que nuestro subreporte use para obtener los datos(base de datos, fuente de datos, nada), será conveniente pasarle una cosa u otra. En nuestro caso,como lo tiene que llenar, le pasamos un JasperReport que deberá obtener sus datos medianteuna conexión a una base de datos y una consulta SQL.

Pues bien, “qué le pasamos” también hay que indicárselo. Para ello, seleccionaremos la tercerapestaña del diálogo de propiedades del subreporte (Subreport (Other)).Allí le diremos que le vamos a proporcionar un objeto del tiponet.sf.jasperreports.engine.JasperReport y que su referencia la puede encontraren el parámetro SUBREPORT.

La siguiente imagen nos lo muestra:

11 de 18

Page 12: Sub Reports Tutorial

¿Con quién me lleno?Bueno, esta es la pregunta existencial que nuestro subreporte se hace. Se tiene que rellenar con losdatos de la misma persona que el reporte maestro.

Recordemos que el reporte maestro tiene un parámetro llamado PERSONA_ID y que, curiosamente,nuestro subreporte tiene otro con el mismo nombre y del mismo tipo. En ambos casos, el valor delparámetro se utiliza para discriminar la persona sobre la que se va a realizar el reporte.

En este caso, al llamarse igual y ser del mismo tipo, el reporte maestro se lo pasará al subreporte demanera que éste sabrá que tiene que obtener los datos de una persona concreta, y para ser másexactos, la misma de la que obtendrá datos el reporte maestro.

Si la cosa no fuera tan sencilla y tuviéramos que pasarle más parámetros o los parámetros delsubreporte, por ejemplo, no tuvieran el mismo nombre que el del reporte maestro o hubiera querealizar algún cálculo previo, etc., etc., los podríamos especificar en la tercera pestaña del diálogo depropiedades del subreporte, en el apartado Subreport Parameters:

12 de 18

Figura 8: Propiedades del subreporte - Subreport (Other)

Page 13: Sub Reports Tutorial

EL PROGRAMAUna vez diseñados el reporte maestro y el subreporte por separado y cumplimentadas lasespecificaciones de localización y rellenado, ¡seguimos sin tener nada! Si intentamos visualizar el reporte maestro desde iReport, veremos sólo el reporte maestro. En elespacio del subreporte, no veremos nada.

La razón es simple, no le hemos pasado al reporte maestro todos los datos necesarios para quepueda mostrarnos el subreporte. Simplemente le hemos indicado dónde los puede encontrar. Laaplicación iReport no sabe crear un objeto JaspeReport y pasárselo en un parámetro al reportemaestro.

Para ver el resultado final de nuestra obra de arte, escribiremos un pequeño programa en Java quenos acabará de llenar los huecos que iReport no puede.

Describiré sólo las partes más relevantes del programa. El fuente del programa está disponible.

Obtención de URL s de los archivos de reportesLo primero que hago es conseguir la ubicación de los archivos previamente compilados de losreportes. Estos archivos se encuentran en el subdirectorio reports de mi proyecto. Es decir,estarán en el subdirectorio reports de mi archivo jar.

Para referirme a ellos, crearé sendas URLs usando el método getResource() de la clase Class.La referencia será, pues, a partir del path interno, del path de la clase. Este es el método habitual decargar recursos y evita aquello tan pesado de “no encuentro el recurso” en cuanto sales del IDE.

SubreportsSample t1 = new SubreportsSample();URL urlMaestro = t1.getClass().getResource

13 de 18

Page 14: Sub Reports Tutorial

("/reports/TUTORIAL_SUBREPORTS_MASTER.jasper");URL urlSubreporte = t1.getClass().getResource("/reports/TUTORIAL_SUBREPORTS_SUBREPORT.jasper");

Creación de los obje tos JasperReportA continuación, voy a crear los objetos JasperReport a partir de los reportes compilados:

JasperReport masterReport = (JasperReport) JRLoader.loadObject(urlMaestro);JasperReport subReport = (JasperReport) JRLoader.loadObject(urlSubreporte);

Parámet rosHemos visto que sólo nuestro reporte maestro necesita parámetros ya que el subreporte, en esteejemplo, los toma del maestro.

Creamos, pues un java.util.Map y lo llenamos con los parámetros:Map masterParams = new HashMap();masterParams.put("SUBREPORT", subReport);masterParams.put("PERSONA_ID", new Integer(3));

Con ellos el reporte maestro sabrá de qué persona tiene que obtener los datos (PERSONA_ID) ydispondrá del subreporte para llenar su hueco (SUBREPORT).

LlenadoPara que podamos ver el resultado, tenemos que llenar con los datos nuestros reportes. Para ello,sólo hay que rellenar el reporte maestro ya que el subreporte se llenará en cascada desde el maestro.

El siguiente código muestra cómo se llena:JasperPrint masterPrint = JasperFillManager.fillReport(masterReport, masterParams, con);

Obsérvese que aquí le pasamos todo lo necesario:

• El reporte maestro: masterReport• Los valores de los parámetros del reporte maestro: masterParams• La conexión a la base de datos: con

El resultado es un objeto JasperPrint, listo para ser visualizado, convertido en HTML, en PDF,etc.

VisualizaciónPor fin, vamos a ver el resultado de nuestros esfuerzos.

Para ello, usaremos el método estático viewReport() de la clase JasperViewer: JasperViewer.viewReport(masterPrint, false);

El segundo parámetro de viewReport ,false, indica que la aplicación no debe cerrarse al cerrarla ventana de visualización. En este caso, lo prefiero así porque quiero cerrar la conexión con labase de datos después de visualizar el reporte.

14 de 18

Page 15: Sub Reports Tutorial

RESUMENIntentaré resumir aquí los principales conceptos y pasos a seguir necesarios para construir unsubreporte.

Conceptos• Un subreporte no es otra cosa que un reporte. Por lo tanto, su diseño no difiere del de otros

reportes.

• Un reporte maestro es un reporte que contiene un elemento más, llamado subreporte. Este elemento reserva espacio para el reporte que actuará como subreporte. Las propiedades del elemento subreporte permiten enlazar el reporte maestro con el subreportede manera que el reporte maestro sepa localizarlo y pueda pasar la información necesaria alreporte que actúa como subreporte para que éste se pueda llenar con los datos pertinentes.

Pasos a seguir1. Diseñar el reporte maestro :

1. Diseñar como un reporte normal

1. Definir uno o más parámetros, si fuera necesario, que nos permitan acotar nuestra consulta(p.e. PERSONA_ID, para identificar a una persona en concreto)5

2. Definir la consulta SQL usando, si fuera necesario, los parámetros del punto anterior. Porejemplo: SELECT P.ID, P.NOMBRE AS NOMBRE, P.APELLIDOS, C.NOMBRE AS CURSO, C.MATRICULA FROM PERSONAS P, CURSOS C, PERSONA_CURSOS PC WHERE P.ID = $P{PERSONA_ID} AND PC.ID_PERSONA = P.ID AND PC.ID_CURSO = C.ID.

2. Incluir un elemento de tipo subreporte en el diseño que reservará espacio para que se muestreel reporte que actuará como subreporte

3. Compilar y visualizar el reporte maestro6 verificando que el resultado sea el esperado, sintener en cuenta el subreporte

2. Diseñar el subreporte :

1. Diseñar como un reporte normal

1. Definir uno o más parámetros, si fuera necesario, que nos permitan acotar nuestra consulta.Si hemos de enlazar el subreporte con el reporte maestro, es conveniente que dichosparámetros compartan el nombre y el tipo con los del reporte maestro (p.e. PERSONA_ID)

2. Definir la consulta SQL usando, si fuera necesario, los parámetros del punto anterior. Porejemplo: SELECT C.NOMBRE AS CURSO, C.MENSUALIDAD, C.MENSUALIDADES

5 Obsérvese que no es posible utilizar en la definición de la consulta parámetros que aún no se han definido. Laaplicación iReport nos daría un error si así lo hiciéramos.

6 En la visualización no aparecerá el subreporte.

15 de 18

Page 16: Sub Reports Tutorial

FROM PERSONAS P, CURSOS C, PERSONA_CURSOS PC WHERE P.ID = $P{PERSONA_ID} AND PC.ID_PERSONA = P.ID AND PC.ID_CURSO = C.ID.

3. Compilar y visualizar el subreporte verificando que el resultado es el esperado, sin tener encuenta el subreporte

2. Enlazar reporte maestro y subreporte :

1. Definición en el reporte maestro del parámetro que contendrá el subreporte:7

1. Definimos un parámetro llamado, por ejemplo, SUBREPORT.

2. Asignamos como tipo de parámetronet.sf.jasperreports.engine.JasperReport.

2. Asignación de este parámetro al elemento subreporte

1. Abrimos el diálogo de propiedades del subreporte haciendo doble clic en el elementosubreporte del reporte maestro

2. Seleccionamos la pestaña Subreport (Other) del diálogo de propiedades

3. En la lista desplegable que lleva por título Image Expression Class, seleccionamos eltipo net.sf.jasperreports.engine.JasperReport

4. En el campo que lleva por título Subreport Expression, especificamos el parámetro quecontendrá nuestro subreport: $P{SUBREPORT}

3. Especificación del método usado por el subreport para obtener los datos:

1. Seleccionamos la pestaña Subreport del diálogo de propiedades del subreport

2. De la lista desplegable Connection / Datasource Expression, seleccionamos el elementoUse connection expression para indicar que los datos se van a obtener mediante unaconexión a una base de datos

3. En el campo de texto que se encuentra debajo de la lista de selección del punto anterior,especificamos el parámetro que va a proporcionar la conexión a la base de datos: $P{REPORT_CONNECTION}

4. Creación del programa :Para poder visualizar los resultados de nuestro trabajo, debemos crear un pequeñoprograma que proporcione al reporte maestro aquellos datos que iReport no puede obtener.Dicho programa tendrá la siguiente estructura:

1. Obtención de las URLs de los archivos que contienen el reporte maestro y el subreporte:URL urlMaestro = t1.getClass().getResource("/reports/TUTORIAL_SUBREPORTS_MASTER.jasper");

URL urlSubreporte = t1.getClass().getResource("/reports/TUTORIAL_SUBREPORTS_SUBREPORT.jasper");

2. Crear los objetos JasperReport, correspondientes al reporte maestro y al subreporte,a partir de las URLs obtenidas en el punto anterior

3. Definir el objeto java.util.Map que contendrá los parámetros correspondientes alreporte maestro

7 El valor de dicho parámetro será asignado desde nuestra aplicación Java, como veremos más adelante.

16 de 18

Page 17: Sub Reports Tutorial

4. Incluir las parejas nombre de parámetro – valor en el Map definido en el punto anterior

5. Llenar el reporte maestro con los valores para obtener un objeto JasperPrint capazde ser visualizado

6. Visualización del reporte maestro (que ahora ya incluye el subreporte) mediante elmétodo estático viewReport() de JasperViewer

¿QUÉ HE USADO?Herramientas de reportesHe usado la versión 0.6.1 de JasperReports (http://jasperreports.sourceforge.net/), si bien, mientrasescribía este tutorial ha aparecido la versión 0.6.2, cuyos cambios no afectan en nada a este tutorial.

He utilizado la última versión de iReport -Designer for JasperReports(http://ireport.sourceforge.net/): la 0.4.0.

Para crear la clase Java de visualización, he utilizado la versión 3.0.1 de Eclipse(http://www.eclipse.org/).

Gestores de bases de datosHe usado la versión 4.1.7-nt de MySQL (http://www.mysql.com) como gestor de bases de datosprincipal. Sobre él he desarrollado la aplicación y he relizado pruebas.

También he usado HSQLDB 1.7.2.8 (http://hsqldb.sourceforge.net/). Sin embargo, no he realizadopruebas contra HSQLDB.

Para la generación del modelo de datos y los DDLs, he usado la versión 1.0.5 del plugin de EclipseClay Database Modeling (http://www.azzurri.jp/en/software/clay/index.jsp). El plugin también se hautilizado para convertir el modelo de datos de MySQL a HSQLDB.

Procesador de textosPara escribir el tutorial y para generar el PDF, he utilizado el extraordinario OpenOfiice 1.1.3(http://www.openoffice.org).

CONTENIDO DEL ARCHIVO ZIPEl archivo SUBREPORTS.ZIP contiene:

• El archivo LEEME.TXT que contiene esta información en formato texto [directorio raíz]

• El tutorial en PDF, SUBREPORTS_TUTORIAL.pdf [directorio raíz]

• Los DDL que permiten crear tablas e insertar datos de ejemplos para MySQL y para HSQLDB[directorio subreports\database]

• Los reportes maestro y subreporte compilados (*.jasper) y sin compilar (*.jrxml) [directoriosubreports\reports]

• La clase de ejemplo, SubreportsSample, en fuente y compilada [directoriosubreports]

17 de 18

Page 18: Sub Reports Tutorial

PARA TERMINARDecir que este tutorial es el resultado de mi primer trabajo con subreportes de JasperReport, por loque seguro que está tapizado de agujeros y errores, que espero que el lector sabrá disculpar y ponerde manifiesto en el apartado de comentarios de javaHispano. Toda crítica será bien recibida ycontribuirá a la generación de una versión más completa de este tutorial.

Espero y deseo que, a pesar de todo, este tutorial cubra una buena parte de las expectativas de losdesarrolladores.

18 de 18