Sunteți pe pagina 1din 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 tutoriales1 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
concreto que, creo y deseo, sirva de inspiración al lector para usar subreportes.

ESCENARIO
Nuestro escenario va a ser un proceso de matrícula a una serie de cursos. Una persona se matricula a
uno o más cursos y debe saber qué le va a costar en total. La inscripción en un curso supone el pago
de 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 el
precio 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:

Figura 1: Esquema de tablas

El significado de la mayor parte de las columnas de las tablas se puede deducir fácilmente de su
nombre. Quizá la tabla menos clara sea la de Cursos. Comento, pues, las columnas que la forman:
Colu mna Com entario
ID Es la clave primaria. Un entero autoincrementado
NOMBRE Contiene los nombres de los cursos (p.e. Curso 1, Curso 2, etc.)
MATRICULA Contiene los precios de las matrículas de los distintos cursos
MENSUALIDAD Contiene los precios de cada una de las mensualidades a pagar por cada
curso
MENSUALIDADES 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 realidad
estamos 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 los
gastos 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 cursos
matriculados, 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 realmente
queremos obtener en nuestro informe:

2 de 18
Figura 2: Aspecto del informe final

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 SUBREPORTES
Un reporte es un informe resultado del proceso, más o menos complejo, de datos que pueden
proceder de diversas fuentes. Lo más frecuente, en el ámbito informático, es que los datos procedan
de una base de datos.
No hay diferencia entre un reporte y un subreporte. Todo reporte pasa a convertirse en subreporte en
cuanto forma parte de otro reporte.
Este concepto es importante, ya que nos indica que no hay que hacer nada especial para diseñar un
subreporte. 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
que forman parte del maestro, los llamaremos subreportes.

ESTRATEGIA DISEÑO
Como he comentado más arriba, no hay diferencia entre reporte y subreporte ya que ambos son
reportes, 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 maestro
y 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 y
subreporte usando iReport.
La siguiente imagen muestra el resultado de la visualización de nuestro reporte maestro antes de
ligarlo al subreporte:

Figura 3: Vista previa del reporte maestro

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

4 de 18
Figura 4: Vista previa del subreporte

DISEÑO DE REPORTE MAESTRO Y SUBREPORTE


No es mi intención, como ya he comentado, extenderme demasiado en la descripción de los diseños
del reporte y subreporte. El tutorial incluye los fuentes de los reportes y de la clase Java que los
muestra, así que sólo comentaré los puntos más significativos.

Re porte maestro
Consulta
El reporte maestro nos muestra la información existente en nuestra base de datos sobre la matrícula
de 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 un
parámetro: $P{PERSONA_ID}.2
Este parámetro deberá ser pasado por nuestro programa a la instancia de
net.sf.jasperreports.engine.JasperReport para que en el momento de llenado del
reporte, é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.

Campos
Los 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 ser
referenciado en la consulta.

5 de 18
somera de los mismos:
Cam po Descripción
APELLIDOS Los apellidos de la persona
CURSO El nombre del curso
ID El identificador único de la persona
MATRICULA El precio de la matrícula del curso
NOMBRE El nombre de la persona
Tabla 2: Descripción de los campos

Estructura: Bandas
Trabajamos 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 y
NOMBRE, 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 para
cada registro
• La variable MATR_TOTAL, resultado de sumar los valores de la variable MATR_SUBTOT
para cada registro
• El texto estático “MENSUALIDADES”
• El elemento SUBREPORT
• Page Footer
• La fecha y el número de página

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

6 de 18
Sin embargo, nos conviene crearlo desde el punto de vista de la facilidad de presentación. Si no lo
tuviéramos, deberíamos emplear la banda Column Footer para presentar los totales de matrícula y el
subreporte de mensualidades. El resultado sería que dicha banda nos presentaría los resultados al
final 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 banda
Group Footer interesante para nuestro ejemplo porque nos permite ubicar en ella, a nuestra
conveniencia, tanto los totales de matrícula como el subreporte.

Sub reporte
Consulta
El subreporte nos presentará información sobre las mensualidades que una persona en concreto
deberá pagar por cada uno de los cursos matriculados. Para obtener dicha información, usaremos la
siguiente consulta SQL:
SELECT C.NOMBRE AS CURSO, C.MENSUALIDAD, C.MENSUALIDADES
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
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.

Campos
La siguiente tabla describe someramente los campos que se desprenden de la consulta SQL del
subreporte:
Cam po Descrip ción
CURSO Nombre del curso
MENSUALIDAD Importe de cada mensualidad de un curso
MENSUALIDADES Número de mensualidades a abonar
Tabla 3: Campos a partir de la consulta SQL

Estructura: bandas
La estructura de bandas en el subreporte es mucho más sencilla que en el reporte. Sólo usaremos
dos:
• 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ámetro
PERSONA_ID antes de definir la consulta.

7 de 18
MENSUALIDADES
• La variable SUBTOTAL_MENSUALIDADES, resultado de multiplicar los valores del
campo MENSUALIDAD por los del campo MENSUALIDADES

Inclusión del subr eporte en iR eport


La inclusión de un subreporte en un reporte usando iReport supone lo mismo que incluir un campo
de texto o un texto estático. Simplemente hay que pulsar el botón de Subreport tool de la barra de
herramientas y después arrastrar el ratón en la banda que nos interese hasta conseguir el tamaño
deseado para nuestro subreporte.
La siguiente imagen muestra la parte de la barra de herramientas que incluye el botón de
subreportes:

Figura 5: Botón de inclusión


de subreporte

ENLACE REPORTE MAESTRO – SUBREPORTE


Hemos visto hasta ahora cómo diseñar el reporte maestro y el subreporte y cómo reservar un espacio
para éste en el reporte maestro.
Fijémonos en el detalle. En realidad hemos reservado un espacio en el reporte maestro. Éste no sabe
absolutamente 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 hemos
reservado.
Fijémonos que la manera más cómoda de pasárselo es mediante un parámetro. Nuestro programa
creará una instancia de java.util.Map que contendrá la información necesaria para que el
reporte maestro cargue el subreporte.
Una estrategia sería definir un parámetro de tipo String que nuestro programa rellenará con el
path completo de nuestro reporte. En alguno de los ejemplos que he consultado, han optado por esta
solución. Sin embargo, yo le veo un problema si lo que pretendo es que el subreporte forme parte
del archivo jar que contendrá nuestra aplicación.
Lo que haremos, pues, es definir en el reporte maestro un parámetro, al que llamaremos
SUBREPORT, 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ón
de 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 6: Definición del parámetro SUBREPORT

Obsérvese que en la ventana de definición de parámetro, bajo el título Parameter class type, hay un
desplegable. Es posible que éste no contenga el tipo que nos interesa:
net.sf.jasperreports.engine.JasperReport. Si es así, no hay problema ya que el
desplegable 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 poner
en 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 datos
pertinentes.
Como hemos visto, nuestra fuente de datos es una base de datos. Para acceder a nuestra base de
datos necesitamos una conexión con ella.
Desde nuestro programa Java solemos abrir una conexión con la base de datos que queda plasmada
en un objeto de tipo java.sql.Connection. Esta instancia es la que usamos para llenar
nuestro reporte maestro de datos, pasándosela como parámetro al método fillReport() de la
clase 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 con
saber que nuestro reporte maestro dispone de una conexión a la base de datos que va a usar para
ejecutar la consulta SQL que hemos comentado más arriba.

9 de 18
Esta conexión está guardada en un parámetro interno de nuestro reporte maestro que JasperReports
se encarga de crear para nosotros: REPORT_CONNECTION.
Curiosamente, iReport no muestra dicho parámetro en la ventana de definición de parámetros, pero
hay que tenerlo muy presente. El parámetro existe.
El lector, llegado a este punto, estará preguntándose el porqué de tanto preámbulo. Bien, es
importante entender qué hace un reporte para poder acceder y presentar después los datos. Hasta el
momento, hemos visto que el reporte maestro tiene información suficiente para ejecutar su consulta
y presentar sus datos, pero nos queda todavía entender cómo se las arreglará para que el subreporte
haga lo propio ya que es el reporte maestro quien lanza el llenado del subreporte, al formar éste
parte 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):

Figura 7: Propiedades del subreporte - Subreport

Bajo el título Connection / Datasource expression, vemos una lista desplegable. De ella, podemos
seleccionar 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 de
datos 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 el
parámetro REPORT_CONNECTION para que pueda ejecutar su consulta SQL.

10 de 18
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 una
fuente de datos ni de una conexión. Por ejemplo, si los datos de los que se nutre le son
proporcionados por parámetros.
La segunda, “Usa una expresión de datasource”, se utilizaría en el caso de que el subreporte se
llenara directamente a partir de una fuente de datos que implementase la interficie
net.sf.jasperreports.engine.JRDataSource como la clase
net.sf.jasperreports.engine.data.JRTableModelDataSource que se basa en
un un modelo de javax.swing.JTable. En este caso, definiríamos un parámetro de tipo
JRTableModelDataSource 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 mediante
una 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 tercera
pestaña del diálogo de propiedades del subreporte (Subreport (Other)).
Allí le diremos que le vamos a proporcionar un objeto del tipo
net.sf.jasperreports.engine.JasperReport y que su referencia la puede encontrar
en el parámetro SUBREPORT.
La siguiente imagen nos lo muestra:

11 de 18
Figura 8: Propiedades del subreporte - Subreport (Other)

¿Con quién me lleno?


Bueno, esta es la pregunta existencial que nuestro subreporte se hace. Se tiene que rellenar con los
datos 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 del
pará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 de
manera que éste sabrá que tiene que obtener los datos de una persona concreta, y para ser más
exactos, 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 del
subreporte, por ejemplo, no tuvieran el mismo nombre que el del reporte maestro o hubiera que
realizar algún cálculo previo, etc., etc., los podríamos especificar en la tercera pestaña del diálogo de
propiedades del subreporte, en el apartado Subreport Parameters:

12 de 18
EL PROGRAMA
Una vez diseñados el reporte maestro y el subreporte por separado y cumplimentadas las
especificaciones de localización y rellenado, ¡seguimos sin tener nada!
Si intentamos visualizar el reporte maestro desde iReport, veremos sólo el reporte maestro. En el
espacio del subreporte, no veremos nada.
La razón es simple, no le hemos pasado al reporte maestro todos los datos necesarios para que
pueda mostrarnos el subreporte. Simplemente le hemos indicado dónde los puede encontrar. La
aplicación iReport no sabe crear un objeto JaspeReport y pasárselo en un parámetro al reporte
maestro.
Para ver el resultado final de nuestra obra de arte, escribiremos un pequeño programa en Java que
nos 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 reportes


Lo primero que hago es conseguir la ubicación de los archivos previamente compilados de los
reportes. 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 de
cargar 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
("/reports/TUTORIAL_SUBREPORTS_MASTER.jasper");
URL urlSubreporte = t1.getClass().getResource
("/reports/TUTORIAL_SUBREPORTS_SUBREPORT.jasper");

Cre ación de los obje tos JasperReport


A 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 ros
Hemos visto que sólo nuestro reporte maestro necesita parámetros ya que el subreporte, en este
ejemplo, 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) y
dispondrá del subreporte para llenar su hueco (SUBREPORT).

Ll enado
Para 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.

Vi sualización
Por 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 cerrar
la ventana de visualización. En este caso, lo prefiero así porque quiero cerrar la conexión con la
base de datos después de visualizar el reporte.

14 de 18
RESUMEN
Intentaré resumir aquí los principales conceptos y pasos a seguir necesarios para construir un
subreporte.

Conceptos
• Un subre port e no es otra cosa que un reporte. Por lo tanto, su diseño no difiere del de otros
reportes.
• Un repo rte m aestro 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 subreporte
de manera que el reporte maestro sepa localizarlo y pueda pasar la información necesaria al
reporte que actúa como subreporte para que éste se pueda llenar con los datos pertinentes.

Pasos a seguir
1. 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. Por
ejemplo:
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 muestre
el reporte que actuará como subreporte
3. Compilar y visualizar el reporte maestro6 verificando que el resultado sea el esperado, sin
tener 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 dichos
pará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. Por
ejemplo:
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. La
aplicación iReport nos daría un error si así lo hiciéramos.
6 En la visualización no aparecerá el subreporte.

15 de 18
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 en
cuenta 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ámetro
net.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 elemento
subreporte 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 el
tipo net.sf.jasperreports.engine.JasperReport
4. En el campo que lleva por título Subreport Expression, especificamos el parámetro que
contendrá 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 elemento
Use connection expression para indicar que los datos se van a obtener mediante una
conexió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ño
programa 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 al
reporte maestro

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

16 de 18
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 capaz
de ser visualizado
6. Visualización del reporte maestro (que ahora ya incluye el subreporte) mediante el
método estático viewReport() de JasperViewer

¿QUÉ HE USADO?
Herrami entas de reportes
He usado la versión 0.6.1 de JasperReports (http://jasperreports.sourceforge.net/), si bien, mientras
escribí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/).

Gestor es de bases de datos


He usado la versión 4.1.7-nt de MySQL (http://www.mysql.com) como gestor de bases de datos
principal. 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 realizado
pruebas contra HSQLDB.
Para la generación del modelo de datos y los DDLs, he usado la versión 1.0.5 del plugin de Eclipse
Clay Database Modeling (http://www.azzurri.jp/en/software/clay/index.jsp). El plugin también se ha
utilizado para convertir el modelo de datos de MySQL a HSQLDB.

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

CONTENIDO DEL ARCHIVO ZIP


El 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) [directorio
subreports\reports]
• La clase de ejemplo, SubreportsSample, en fuente y compilada [directorio
subreports]

17 de 18
PARA TERMINAR
Decir que este tutorial es el resultado de mi primer trabajo con subreportes de JasperReport, por lo
que seguro que está tapizado de agujeros y errores, que espero que el lector sabrá disculpar y poner
de manifiesto en el apartado de comentarios de javaHispano. Toda crítica será bien recibida y
contribuirá 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 los
desarrolladores.

18 de 18

S-ar putea să vă placă și