Siempre que usamos Jasperreports para montar informes, pasamos todos los parámetros, incluso las etiquetas, desde el aplicativo Java. Esto ofrece varias ventajas:
- Si por ejemplo cambia el motor de la BBDD de un aplicativo en producción, únicamente ajustamos la configuración de Hibernate sin regenerar los informes.
- Si necesitamos el informe en varios idiomas, controlamos el idioma del usuario desde el aplicativo Java (por ejemplo recogiendo las preferencias del navegador con JSF).
Clase Java para generar el informe
package org.dune.app;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.util.JRLoader;
import org.dune.pojo.Coche;
import org.dune.pojo.Telefono;
public class TestReport {
//Datos cabecera
private static Map<String,Object> datosCabeceraReport;
//Datos detalle
private static List<Coche> datosDetalleReport;
private static List<Telefono> datosDetalleSubReport;
public static void main(String args[]) throws JRException{
//Preparamos los datos de cabecera del report, cuando en
//el report.jrxml añadamos los Parameter "titulo" y "fecha"
//tendremos que asegurarnos que sean de tipo "String"
datosCabeceraReport = new HashMap<String,Object>();
datosCabeceraReport.put("titulo", "Inventario de bienes");
datosCabeceraReport.put("fecha", "15/03/2013");
//Preparamos los datos de detalle del report
datosDetalleReport = new ArrayList<Coche>();
datosDetalleReport.add(new Coche("1234-AAA", "Peugeot 207"));
datosDetalleReport.add(new Coche("5678-AAA", "Peugeot 307"));
datosDetalleReport.add(new Coche("9012-AAA", "Peugeot 407"));
//Preparamos los datos de detalle del subreport
datosDetalleSubReport = new ArrayList<Telefono>();
datosDetalleSubReport.add(new Telefono("111111111", "Nokia 1000"));
datosDetalleSubReport.add(new Telefono("222222222", "Nokia 2000"));
datosDetalleSubReport.add(new Telefono("333333333", "Nokia 3000"));
//Añadimos los datos de detalle del subreport al Map de parametros del
//padre y montandolos sobre un JRBeanCollectionDataSource. Cuando en
//el report.jrxml añadamos el Parameter "datosSubRep" tendremos que
//forzar el tipo a: "net.sf.jasperreports.engine.data.JRBeanCollectionDataSource"
datosCabeceraReport.put("datosSubRep", new JRBeanCollectionDataSource(datosDetalleSubReport));
//Montamos el objeto JRMapCollectionDataSource con los datos de la bandas de detalle del report
final JRBeanCollectionDataSource datosReport = new JRBeanCollectionDataSource(datosDetalleReport);
//Generamos el informe compilado
creaInforme(datosCabeceraReport, datosReport);
}
private static void creaInforme(final Map<String,Object> datosCabeceraReport, final JRBeanCollectionDataSource datosReport) throws JRException{
//Cargamos el informe previamente compilado
final String urlReport = TestReport.class.getResource("/report.jasper").getFile();
final JasperReport informe = (JasperReport) JRLoader.loadObject(urlReport);
//Añadimos los datos
final JasperPrint informePrint = JasperFillManager.fillReport(informe, datosCabeceraReport, datosReport);
//Exportamos a pdf
JasperExportManager.exportReportToPdfFile(informePrint,"./src/main/resources/report.pdf");
}
}
Cuestiones fundamentales
Los detalles fundamentales se han introducido como comentarios en el código de la clase anterior, pero merece la pena repasarlos:
- Los "parámetros estáticos" del report padre, esto es, todos aquellos que no aparecen en la banda de detalle del informe padre, se pasan al JasperFillManager dentro del objeto: final Map<String,Object> datosCabeceraReport.
- Los datos de detalle del subreport (lista de telefonos) se pasan al JasperFillManager como un parámetro de tipo JRBeanCollectionDataSource dentro del objeto: final Map<String,Object> datosCabeceraReport .
- Los datos de detalle del report (lista de coches) padre se pasan al JasperFillManager dentro del objeto: final JRBeanCollectionDataSource datosReport.
- En el report.jrxml hemos definido los parámetros: titulo, fecha y datosSubRep. Los dos primeros, de tipo String, se usarán en la banda título del report padre. El tercer parámetro, de tipo JRBeanCollectionDataSource, se usará en la propiedad "Data Source Expression" del subreport: $P{datosSubRep}.
- En el report.jrxml hemos definido los "Fields": matricula y modelo, que son las columnas del área de detalle y que son los atributos de la clase Coche.java.
- En el subreport.jrxml hemos definido los "Fields": numero y tipo, que son las columnas del área de detalle y que son los atributos de la clase Telefono.java.
La clase Coche.java se usará en la banda de detalle del informe padre.
package org.dune.pojo;
public class Coche {
private String matricula;
private String modelo;
public Coche(final String matricula, final String modelo) {
super();
this.matricula = matricula;
this.modelo = modelo;
}
public String getMatricula() {
return matricula;
}
public void setMatricula(String matricula) {
this.matricula = matricula;
}
public String getModelo() {
return modelo;
}
public void setModelo(String modelo) {
this.modelo = modelo;
}
}
La clase Telefono.java se usará en la banda de detalle del subinforme.
package org.dune.pojo;
public class Telefono {
private String numero;
private String tipo;
public Telefono(final String numero, final String tipo) {
this.numero = numero;
this.tipo = tipo;
}
public String getNumero() {
return numero;
}
public void setNumero(String numero) {
this.numero = numero;
}
public String getTipo() {
return tipo;
}
public void setTipo(String tipo) {
this.tipo = tipo;
}
}
report.jrxml
El aspecto general del informe padre en el diseñador es:
El código xml del informe padre es:
<?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="report1" language="groovy" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
<property name="ireport.zoom" value="1.4641000000000008"/>
<property name="ireport.x" value="0"/>
<property name="ireport.y" value="0"/>
<parameter name="titulo" class="java.lang.String"/>
<parameter name="fecha" class="java.lang.String"/>
<parameter name="datosSubRep" class="net.sf.jasperreports.engine.data.JRBeanCollectionDataSource"/>
<field name="matricula" class="java.lang.String"/>
<field name="modelo" class="java.lang.String"/>
<title>
<band height="51" splitType="Stretch">
<rectangle radius="5">
<reportElement mode="Transparent" x="2" y="4" width="547" height="44"/>
</rectangle>
<textField>
<reportElement x="61" y="26" width="488" height="20"/>
<textElement verticalAlignment="Middle"/>
<textFieldExpression class="java.lang.String"><![CDATA[$P{fecha}]]></textFieldExpression>
</textField>
<staticText>
<reportElement x="6" y="6" width="55" height="20"/>
<textElement verticalAlignment="Middle">
<font isBold="true"/>
</textElement>
<text><![CDATA[TITULO:]]></text>
</staticText>
<staticText>
<reportElement x="6" y="26" width="55" height="20"/>
<textElement verticalAlignment="Middle">
<font isBold="true"/>
</textElement>
<text><![CDATA[FECHA:]]></text>
</staticText>
<textField>
<reportElement x="61" y="6" width="488" height="20"/>
<textElement verticalAlignment="Middle"/>
<textFieldExpression class="java.lang.String"><![CDATA[$P{titulo}]]></textFieldExpression>
</textField>
</band>
</title>
<pageHeader>
<band height="73">
<rectangle radius="5">
<reportElement positionType="Float" mode="Opaque" x="2" y="50" width="547" height="22" backcolor="#C68B8B"/>
</rectangle>
<rectangle radius="5">
<reportElement mode="Opaque" x="2" y="1" width="547" height="22" forecolor="#010101" backcolor="#C68B8B"/>
</rectangle>
<staticText>
<reportElement x="6" y="2" width="100" height="20"/>
<textElement verticalAlignment="Middle">
<font isBold="true"/>
</textElement>
<text><![CDATA[TELEFONOS:]]></text>
</staticText>
<staticText>
<reportElement positionType="Float" x="6" y="51" width="100" height="20"/>
<textElement verticalAlignment="Middle">
<font isBold="true"/>
</textElement>
<text><![CDATA[COCHES:]]></text>
</staticText>
<subreport>
<reportElement x="0" y="24" width="555" height="24"/>
<dataSourceExpression><![CDATA[$P{datosSubRep}]]></dataSourceExpression>
<subreportExpression class="java.lang.String"><![CDATA["/home/eduardo/trabajo/workspaces-helios/wksTestJasper/TestJasper/src/main/resources/subreport.jasper"]]></subreportExpression>
</subreport>
</band>
</pageHeader>
<columnHeader>
<band height="25" splitType="Stretch">
<rectangle radius="5">
<reportElement mode="Transparent" x="2" y="2" width="547" height="22"/>
</rectangle>
<staticText>
<reportElement x="104" y="3" width="445" height="20"/>
<textElement verticalAlignment="Middle">
<font isBold="true"/>
</textElement>
<text><![CDATA[MODELO]]></text>
</staticText>
<staticText>
<reportElement x="6" y="3" width="100" height="20"/>
<textElement verticalAlignment="Middle">
<font isBold="true"/>
</textElement>
<text><![CDATA[MATRICULA]]></text>
</staticText>
</band>
</columnHeader>
<detail>
<band height="27" splitType="Stretch">
<rectangle radius="5">
<reportElement stretchType="RelativeToBandHeight" isPrintRepeatedValues="false" mode="Transparent" x="2" y="2" width="547" height="22" isPrintWhenDetailOverflows="true"/>
</rectangle>
<textField>
<reportElement x="6" y="3" width="100" height="20"/>
<textElement verticalAlignment="Middle"/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{matricula}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="104" y="3" width="445" height="20"/>
<textElement verticalAlignment="Middle"/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{modelo}]]></textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
subreport.jrxml
El aspecto general del subinforme en el diseñador es:
El código xml del subinforme padre es:
<?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="subreport" language="groovy" pageWidth="555" pageHeight="100" columnWidth="555" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="0">
<property name="ireport.zoom" value="1.464100000000001"/>
<property name="ireport.x" value="0"/>
<property name="ireport.y" value="0"/>
<field name="numero" class="java.lang.String"/>
<field name="tipo" class="java.lang.String"/>
<columnHeader>
<band height="25" splitType="Stretch">
<rectangle radius="5">
<reportElement mode="Transparent" x="2" y="2" width="547" height="22"/>
</rectangle>
<staticText>
<reportElement x="6" y="3" width="100" height="20"/>
<textElement verticalAlignment="Middle">
<font isBold="true"/>
</textElement>
<text><![CDATA[NUMERO]]></text>
</staticText>
<staticText>
<reportElement x="106" y="3" width="441" height="20"/>
<textElement verticalAlignment="Middle">
<font isBold="true"/>
</textElement>
<text><![CDATA[TIPO]]></text>
</staticText>
</band>
</columnHeader>
<detail>
<band height="25" splitType="Stretch">
<rectangle radius="5">
<reportElement stretchType="RelativeToTallestObject" isPrintRepeatedValues="false" mode="Transparent" x="2" y="1" width="547" height="22" isPrintWhenDetailOverflows="true"/>
</rectangle>
<textField>
<reportElement x="106" y="2" width="441" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{tipo}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="6" y="2" width="100" height="20"/>
<textElement/>
<textFieldExpression class="java.lang.String"><![CDATA[$F{numero}]]></textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
Aspecto del informe generado
Dependencias
Las dependencias Maven del proyecto son:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dune</groupId>
<artifactId>TestJasper</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>4.0.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7.5</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
</project>


