Crear subinformes

Los subinformes son una de las características interesantes de JasperReports. Esta característica permite incorporar un informe dentro de otro informe, es decir, un informe puede ser un subinforme de otro. Los subinformes nos ayudan a mantener los diseños de informes simples, ya que podemos crear muchos informes simples y encapsularlos en un informe maestro. Los subinformes se compilan y completan como los informes normales. Cualquier plantilla de informe se puede utilizar como subinforme cuando se incorpora a otra plantilla de informe, sin que se modifique nada dentro (de la plantilla de informe).

Los subinformes son como plantillas de informes normales. De hecho , son objetos net.sf.jasperreports.engine.JasperReport , que se obtienen después de compilar un objeto net.sf.jasperreports.engine.design.JasperDesign .

Elemento <subreport>

Se utiliza un elemento <subreport> al introducir subinformes en informes maestros. Aquí está la lista de subelementos en el elemento JRXML <subreport>.

  • <reportElement>

  • <parametersMapExpression>: se utiliza para pasar un mapa que contiene parámetros de informe al subinforme. El mapa generalmente se obtiene a partir de un parámetro en el informe maestro o mediante el parámetro integrado REPORTS_PARAMETERS_MAP para pasar los parámetros del informe principal al subinforme. Esta expresión siempre debe devolver un objeto java.util.Map en el que las claves son los nombres de los parámetros.

  • <subreportParameter>: este elemento se utiliza para pasar parámetros al subinforme. Tiene un nombre de atributo , que es obligatorio.

  • <connectionExpression>: se utiliza para pasar una java.sql.Connection al subinforme. Se utiliza solo cuando la plantilla de subinforme necesita una conexión a la base de datos durante la fase de llenado del informe.

  • <dataSourceExpression>: se utiliza para pasar una fuente de datos al subinforme. Esta fuente de datos generalmente se obtiene de un parámetro en el informe maestro o mediante el parámetro REPORT_DATA_SOURCE incorporado para pasar la fuente de datos del informe principal al subinforme.

  • Los elementos ( connectionExpression y dataSourceExpression ) no pueden estar presentes al mismo tiempo en una declaración de elemento <subreport>. Esto se debe a que no podemos proporcionar una fuente de datos y una conexión al subinforme. Debemos decidirnos por uno de ellos y ceñirnos a él.

  • <returnValue>: se utiliza para asignar el valor de una de las variables del subinforme a una de las variables del informe maestro. Este subelemento tiene los siguientes atributos:

    • subreportVariable : este atributo especifica el nombre de la variable del subinforme cuyo valor se devolverá.

    • toVariable : este atributo especifica el nombre de la variable del informe principal cuyo valor se va a copiar / incrementar con el valor del subinforme.

    • cálculo : este atributo puede tomar valores: nada, recuento, recuento distintivo, suma, promedio, más bajo, más alto, desviación estándar, varianza. El valor predeterminado para el cálculo de atributos es "Nada".

    • incrementerFactoryClass : este atributo especifica la clase de fábrica para crear la instancia de incrementer.

  • <subreportExpression>: indica dónde encontrar la plantilla de informe compilado para el subinforme. Este elemento tiene unclassatributo. El atributo de clase puede tomar cualquiera de estos valores: java.lang.String, java.io.File, java.net.URL, java.io.InputStream, net.sf.jasperreports.engine.JasperReport. El valor predeterminado es java.lang.String .

  • isUsingCache: este es un atributo del elemento <subreport>. Este es un booleano; cuando se establece en verdadero , el motor de informes intentará reconocer los objetos de plantilla de subinforme cargados previamente, utilizando su fuente especificada. Esta funcionalidad de almacenamiento en caché está disponible solo para elementos de subinforme que tienen expresiones que devuelven objetos java.lang.String como fuente de la plantilla de subinforme, que representan nombres de archivo, URL o recursos de ruta de clases.

Ejemplo

Tomemos un ejemplo simple para demostrar la creación de subinformes utilizando JRDataSource. Primero escribamos dos nuevas plantillas de informes, una que sea un subinforme y la otra un informe maestro. El contenido de la plantilla del subinforme (address_report_template.jrxml) es como se indica a continuación. Guárdelo en el directorio C: \ tools \ jasperreports-5.0.1 \ test.

<?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 = "address_report_template" pageWidth = "175" pageHeight = "842" 
   columnWidth = "175" leftMargin = "0" rightMargin = "0" 
   topMargin = "0" bottomMargin = "0">

   <field name = "city" class = "java.lang.String"/>
   <field name = "street" class = "java.lang.String"/>
   
   <background>
      <band splitType = "Stretch"/>
   </background>
   
   <title>
      <band height = "20" splitType = "Stretch">
         
         <staticText>
            <reportElement x = "0" y = "0" width = "100" height = "20"/>
            
            <textElement>
               <font size = "14" isBold = "true"/>
            </textElement>
				
            <text><![CDATA[Addresses]]></text>
         </staticText>
      
      </band>
   </title>
   
   <pageHeader>
      <band height = "12" splitType = "Stretch"/>
   </pageHeader>
   
   <columnHeader>
      <band height = "12" splitType = "Stretch"/>
   </columnHeader>
   
   <detail>
      <band height = "27" splitType = "Stretch">
         
         <textField>
            <reportElement x = "0" y = "0" width = "120" height = "20"/>
            
            <textElement>
               <font size = "12" isBold = "true"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{city}+" Address:"]]>
            </textFieldExpression>
         </textField>
         
         <textField isStretchWithOverflow = "true">
            <reportElement x = "120" y = "0" width = "435" height = "20"/>
            
            <textElement>
               <font size = "12"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{street}]]>
            </textFieldExpression>
         </textField>
      
      </band>
   </detail>
   
   <columnFooter>
      <band height = "8" splitType = "Stretch"/>
   </columnFooter>
  
   <pageFooter>
      <band height = "11" splitType = "Stretch"/>
   </pageFooter>
   
   <summary>
      <band height = "9" splitType = "Stretch"/>
   </summary>

</jasperReport>

Como usamos una fuente de datos, necesitamos escribir un archivo POJO correspondiente SubReportBean.java Como se muestra abajo. Guárdelo en el directorio C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint -

package com.tutorialspoint;

public class SubReportBean {
   private String city;
   private String street;

   public String getCity() {
      return city;
   }

   public void setCity(String city) {
      this.city = city;
   }

   public String getStreet() {
      return street;
   }

   public void setStreet(String street) {
      this.street = street;
   }
}

Aquí, hemos declarado dos campos 'ciudad' y 'calle' y se definen los métodos getter y setter respectivos.

Ahora, actualice nuestro DataBeanarchivo. Agregaremos un nuevo campo subReportBeanList , que es un java.util.List. Este campo contendrá la lista de objetos SubReportBean. El contenido del archivo DataBean es el siguiente. Guárdelo en el directorio C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint.

package com.tutorialspoint;

import java.util.List;

public class DataBean {
   private String name;
   private String country;
   private List<SubReportBean> subReportBeanList;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public String getCountry() {
      return country;
   }

   public void setCountry(String country) {
      this.country = country;
   }

   public List<SubReportBean> getSubReportBeanList() {
      return subReportBeanList;
   }

   public void setSubReportBeanList(List<SubReportBean> subReportBeanList) {
      this.subReportBeanList = subReportBeanList;
   }
}

Actualicemos ahora el archivo C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \DataBeanList.java. El contenido de este archivo es como:

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DataBeanList {
   public ArrayList<DataBean> getDataBeanList() {

      // Create sub report data
      SubReportBean subBean1 = new SubReportBean();
      subBean1.setCity("Mumbai");
      subBean1.setStreet("M.G.Road");
      SubReportBean subBean2 = new SubReportBean();
      subBean2.setCity("New York");
      subBean2.setStreet("Park Street");
      SubReportBean subBean3 = new SubReportBean();
      subBean3.setCity("San Fransisco");
      subBean3.setStreet("King Street");

      ArrayList<DataBean> dataBeanList = new ArrayList<DataBean>();

      // Create master report data
      dataBeanList.add(produce("Manisha", "India",
         Arrays.asList(subBean1)));
      dataBeanList.add(produce("Dennis Ritchie", "USA",
         Arrays.asList(subBean2)));
      dataBeanList.add(produce("V.Anand", "India",
         Arrays.asList(subBean1)));
      dataBeanList.add(produce("Shrinath", "California",
         Arrays.asList(subBean3)));

      return dataBeanList;
   }

   /*
    * This method returns a DataBean object,
    * with name, country and sub report
    * bean data set in it.
    */
   private DataBean produce(String name, String country,
      List<SubReportBean> subBean) {
      DataBean dataBean = new DataBean();

      dataBean.setName(name);
      dataBean.setCountry(country);
      dataBean.setSubReportBeanList(subBean);

      return dataBean;
   }
}

En el método produce () en el archivo anterior, estamos configurando la lista de SubReportBean.

Ahora, escriba una nueva plantilla de informe maestro (jasper_report_template.jrxml). Guarde este archivo en el directorioC:\tools\jasperreports-5.0.1\test. El contenido de este archivo es el siguiente:

<?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 = "jasper_report_template" language = "groovy" pageWidth = "595"
   pageHeight = "842" columnWidth ="555" leftMargin = "20" rightMargin = "20"
   topMargin = "20" bottomMargin = "20">

   <parameter name = "SUBREPORT_DIR" class = "java.lang.String" isForPrompting = "false">
      <defaultValueExpression>
         <![CDATA["C:\\tools\\jasperreports-5.0.1\\test\\"]]>
      </defaultValueExpression>
   </parameter>
   
   <field name = "country" class = "java.lang.String"/>
   <field name = "name" class = "java.lang.String"/>
   <field name = "subReportBeanList" class = "java.util.List"/>
   
   <background>
      <band splitType = "Stretch"/>
   </background>
   
   <title>
      <band height = "35" splitType = "Stretch">
         
         <staticText>
            <reportElement x = "0" y = "0" width = "204" height = "34"/>
            
            <textElement>
               <font size = "26" isBold = "true"/>
            </textElement>
				
            <text><![CDATA[Contact Report]]></text>
         </staticText>
      
      </band>
   </title>
   
   <pageHeader>
      <band height = "17" splitType = "Stretch"/>
   </pageHeader>
   
   <columnHeader>
      <band height = "21" splitType = "Stretch"/>
   </columnHeader>
   
   <detail>
      <band height = "112" splitType = "Stretch">
            
         <staticText>
            <reportElement x = "0" y = "0" width = "100" height = "20"/>
            
            <textElement>
               <font size = "12" isBold = "true"/>
            </textElement>
				
            <text><![CDATA[Name:]]></text>
         </staticText>
         
         <staticText>
            <reportElement x = "0" y = "20" width = "100" height = "20"/>
            
            <textElement>
               <font size = "12" isBold = "true"/>
            </textElement>
				
            <text><![CDATA[Country:]]></text>
         </staticText>
         
         <textField>
            <reportElement x = "104" y = "0" width = "277" height = "20"/>
            
            <textElement>
               <font size = "12"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{name}]]>
            </textFieldExpression>
         </textField>
         
         <textField>
            <reportElement x = "104" y = "20" width = "277" height = "20"/>
            
            <textElement>
               <font size = "12"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{country}]]>
            </textFieldExpression>
         </textField>
         
         <subreport>
            <reportElement positionType = "Float" x = "335" y = "25" width = "175"
               height = "20" isRemoveLineWhenBlank = "true" backcolor = "#99ccff"/>

            <dataSourceExpression>
               new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource
                  ($F{subReportBeanList})
            </dataSourceExpression>
            
            <subreportExpression class = "java.lang.String">
               <![CDATA[$P{SUBREPORT_DIR} + "address_report_template.jasper"]]>
            </subreportExpression>
         </subreport>
         
         <line>
            <reportElement x = "0" y = "50" width = "550" height = "1"/>
         </line>
      
      </band>
   </detail>
   
   <columnFooter>
      <band height = "19" splitType = "Stretch"/>
   </columnFooter>
   
   <pageFooter>
      <band height = "18" splitType = "Stretch"/>
   </pageFooter>
   
   <summary>
      <band height = "14" splitType = "Stretch"/>
   </summary>

</jasperReport>

En la plantilla anterior, hemos definido un nuevo parámetro "SUBREPORT_DIR", que define la ruta del subinforme. Hemos definido un campo subReportBeanList de tipo java.util.List, que corresponde a la propiedad en el archivo DataBean. El elemento <subreport> tiene un subelemento <dataSourceExpression>. Hemos puesto la lista subReportBeanList en una instancia de JRBeanCollectionDataSource. En el subelemento <subreportExpression />, le hemos dado el nombre del subinforme (AddressReport.jasper).

Ahora, escribamos una nueva clase. CreateReportpara compilar y ejecutar nuestra plantilla de informe. El contenido del archivoC:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\CreateReport.java son los que se indican a continuación:

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

public class CreateReport {

   public static void main(String[] args) {
      String masterReportFileName = "C://tools/jasperreports-5.0.1/test"
         + "/jasper_report_template.jrxml";
      String subReportFileName = "C://tools/jasperreports-5.0.1/test"
         + "/AddressReport.jrxml";
      String destFileName = "C://tools/jasperreports-5.0.1/test"
         + "/jasper_report_template.JRprint";
			
      DataBeanList DataBeanList = new DataBeanList();
      ArrayList<DataBean> dataList = DataBeanList.getDataBeanList();
      JRBeanCollectionDataSource beanColDataSource = new 
         JRBeanCollectionDataSource(dataList);

      try {
         /* Compile the master and sub report */
         JasperReport jasperMasterReport = JasperCompileManager
            .compileReport(masterReportFileName);
         JasperReport jasperSubReport = JasperCompileManager
            .compileReport(subReportFileName);

         Map<String, Object> parameters = new HashMap<String, Object>();
         parameters.put("subreportParameter", jasperSubReport);
         JasperFillManager.fillReportToFile(jasperMasterReport, 
            destFileName, parameters, beanColDataSource);

      } catch (JRException e) {

         e.printStackTrace();
      }
      System.out.println("Done filling!!! ...");
   }
}

Aquí, vemos que estamos compilando las plantillas de informe maestro y secundario y pasando el archivo de informe maestro (.jasper) para el llenado del informe.

La generación del informe

Ahora, todos nuestros archivos están listos, compilémoslos y ejecutémoslos usando nuestro proceso de compilación ANT regular. El contenido del archivo build.xml (guardado en el directorio C: \ tools \ jasperreports-5.0.1 \ test) es como se indica a continuación.

El archivo de importación, baseBuild.xml, se obtiene del capítulo Configuración del entorno y debe colocarse en el mismo directorio que build.xml.

<?xml version = "1.0" encoding = "UTF-8"?>
<project name = "JasperReportTest" default = "viewFillReport" basedir = ".">
   <import file = "baseBuild.xml" />
   
   <target name = "viewFillReport" depends = "compile,compilereportdesing,run"
      description = "Launches the report viewer to preview the 
      report stored in the .JRprint file.">
      
      <java classname = "net.sf.jasperreports.view.JasperViewer" fork = "true">
         <arg value = "-F${file.name}.JRprint" />
         <classpath refid = "classpath" />
      </java>
   </target>
   
   <target name = "compilereportdesing" description = "Compiles the JXML file and
      produces the .jasper file.">
      
      <taskdef name = "jrc" classname = "net.sf.jasperreports.ant.JRAntCompileTask">
         <classpath refid = "classpath" />
      </taskdef>
      
      <jrc destdir = ".">
         <src>
            <fileset dir = ".">
               <include name = "*.jrxml" />
            </fileset>
         </src>
         <classpath refid = "classpath" />
      </jrc>
		
   </target>

</project>

A continuación, abramos la ventana de la línea de comandos y vayamos al directorio donde se coloca build.xml. Finalmente, ejecute el comandoant -Dmain-class=com.tutorialspoint.CreateReport (viewFullReport es el destino predeterminado) de la siguiente manera:

Buildfile: C:\tools\jasperreports-5.0.1\test\build.xml

clean-sample:
   [delete] Deleting directory C:\tools\jasperreports-5.0.1\test\classes

compile:
   [mkdir] Created dir: C:\tools\jasperreports-5.0.1\test\classes
   [javac] C:\tools\jasperreports-5.0.1\test\baseBuild.xml:28: 
      warning: 'includeantruntime' was not set, defaulting to
   [javac] Compiling 7 source files to C:\tools\jasperreports-5.0.1\test\classes

compilereportdesing:
   [jrc] Compiling 1 report design files.
   [jrc] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.engine.xml.JRXmlDigesterFactory).
   [jrc] log4j:WARN Please initialize the log4j system properly.
   [jrc] log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig 
      for more info.
   [jrc] File : C:\tools\jasperreports-5.0.1\test\
      jasper_report_template.jrxml ... OK.

run:
   [echo] Runnin class : com.tutorialspoint.CreateReport
   [java] Compiling Report Design ...
   [java] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.engine.xml.JRXmlDigesterFactory).
   [java] log4j:WARN Please initialize the log4j system properly.
   [java] Done filling!!! ...

viewFillReport:
   [java] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.extensions.ExtensionsEnvironment).
   [java] log4j:WARN Please initialize the log4j system properly.

BUILD SUCCESSFUL
Total time: 72 minutes 13 seconds

Como resultado de la compilación anterior, se abre una ventana de JasperViewer como se muestra en la pantalla que se muestra a continuación:

Aquí, podemos ver que se muestran los atributos Nombre, País y Dirección.