Crysfel’s Blog

Generar reporte de una colección de beans con JasperReport

Monday, January 21, 2008, 01:26:04 pm

Desarrollo, Featured, Java, Tutoriales

El día de hoy quiero continuar con el tutorial de JasperReport, he explicado una introducción a la estructura principal del reporte, el paso de parámetros al reporte y como llenar un reporte desde una base de datos incluyendo el Query dentro del jrxml, en esta ocasión explicaré como llenar un reporte por medio de una colección de objetos VO o DTO, como mejor los conozcas.

Objetivos.

  1. Cómo poner acentos y eñes dentro del reporte jrxml.
  2. Poner una imagen en formato gif.
  3. Generar la fecha actual del sistema y desplegarla en el reporte con un formato legible.
  4. Pasarle la información al reporte por medio de una colección de beans.
  5. Cómo poner títulos a las columnas de la información desplegada.
  6. Realizar un reporte como este.

Una vez definidos los objetivos se puede apreciar el alcance de este tutorial y así decidir si al lector le conviene continuar con la lectura de este tutorial.

Cómo poner acentos y eñes.
Lo primero es definir la cabecera del archivo jrxml, y dentro de este especificarle el encode a utilizar dentro del documento, generalmente el encode por de facto es UTF8, pero este encode no soporta los caracteres extendidos, que es donde se encuentran los acentuados y la eñe, es por eso que si no ponemos el encode correcto, al compilar el reporte obtendremos un error, para evitar esto, es necesario indicar que el encode a utilizar sea ISO-8859-1, el cual contiene los caracteres necesarios para el español.

<?xml version="1.0" encoding="ISO-8859-1"  ?>
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN"
"http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<!--======================================================================================== -->
<!--===================================== Por Crysfel Villa==================================== -->
<!--======================================================================================== -->

Paso de parámetros e información.
Lo siguiente es pasarle algunos parámetros para desplegar el titulo, y el subtitulo, además de declararse las Fields de la información a desplegar en el reporte.

<jasperReport
         name="plantilla"
         pageWidth="595"
         pageHeight="842"
         leftMargin="20"
         rightMargin="20"
         topMargin="20"
         bottomMargin="20">


    <parameter name="P_TITULO" class="java.lang.String"/>
    <parameter name="P_SUBTITULO" class="java.lang.String"/>
    <parameter name="LOGO_URL" class="java.lang.String"/>

   
    <field name="universidad" class="java.lang.String"/>
    <field name="rector" class="java.lang.String"/>
    <field name="direccion" class="java.lang.String"/>
    <field name="alumnos" class="java.lang.Integer"/>
</jasperReport>

A diferencia del tutorial anterior, únicamente se le ha suprimido el Query que consultaba la base de datos, esto es por que ahora la información se le pasará directamente desde Java por medio de una colección de DTOs (Data Transfer Object).

Más adelante explicaré mas a detalle el paso de información, por ahora basta con declarar la información a desplegar en la parte del detail.

Poner una imagen en formato gif.
En esta sección se definirá el background y la cabecera del documento, en el tutorial anterior explique cómo hacerlo, el día de hoy será exactamente igual con la diferencia de que en lugar de pasarle una imagen JPG se le pasará una imagen GIF, además de que las medidas y posiciones son diferentes, todo esto escrito en código es:

<background>
    <band height="67">
        <image>
            <reportElement
                x="430"
                y="0"
                width="100"
                height="67"/>

            <imageExpression class="java.lang.String"><![CDATA[$P{LOGO_URL}]]></imageExpression>
        </image>
    </band>
</background>
<title>
    <band height="90">
        <textField>
            <reportElement
                x="0"
                y="40"
                width="530"
                height="30"/>

            <textElement>
                <font pdfFontName="Helvetica-Bold" size="20" isBold="true"/>
            </textElement>
        <textFieldExpression   class="java.lang.String"><![CDATA[$P{P_TITULO}]]></textFieldExpression>
        </textField>
        <line direction="TopDown">
            <reportElement
                x="0"
                y="69"
                width="530"
                height="0"
                key="line"/>

            <graphicElement stretchType="NoStretch"/>
        </line>
        <textField>
            <reportElement
                x="0"
                y="70"
                width="250"
                height="20"
                key="textField"/>

            <textElement>
                <font pdfFontName="Helvetica-Bold" size="10"/>
            </textElement>
        <textFieldExpression   class="java.lang.String"><![CDATA[$P{P_SUBTITULO}]]></textFieldExpression>
        </textField>
        <textField pattern="EEEEE dd MMMMM yyyy">
            <reportElement
                x="260"
                y="70"
                width="270"
                height="20"
                key="textField"/>

            <textElement textAlignment="Right">
                <font pdfFontName="Helvetica-Bold" size="10"/>
            </textElement>
        <textFieldExpression   class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
        </textField>
    </band>
</title>

Hasta aquí no hay nada nuevo, excepto que en el campo donde se despliega la fecha, en lugar de sacarla de la base de datos como en el tutorial anterior, ahora se generará directamente en el reporte, esto es muy sencillo de hacer, únicamente hay que crear una instancia de la clase Date dentro de la expresión del campo:

new java.util.Date()

El formato es exactamente igual al tutorial anterior.

Poner títulos a las columnas.
Anteriormente no se le había agregado cabeceras a las columnas de la información, pero si había mencionado en la introducción que esto es posible, a continuación se muestra cómo por medio de la sección <columnHeader> se puede realizar.

<columnHeader>
    <band height="20">
        <staticText>
            <reportElement x="0" y="0" width="200" height="13" key="staticText"/>
            <text><![CDATA[Universidad]]></text>
        </staticText>
        <staticText>
            <reportElement x="205" y="0" width="150" height="13"/>
            <text><![CDATA[Rector]]></text>
        </staticText>
        <staticText>
            <reportElement x="360" y="0" width="150" height="13"/>
            <text><![CDATA[Dirección]]></text>
        </staticText>
        <staticText>
            <reportElement x="490" y="0" width="100" height="13"/>
            <text><![CDATA[Alumnos]]></text>
        </staticText>
    </band>
</columnHeader>

Si te das cuenta, esta sección no tiene nada especial que no se haya cubierto en los tutoriales anteriores, simplemente son textos estáticos distribuidos en forma linear, es aquí donde se ha necesitado poner acentos, los cuales son correctamente soportados gracias a que se ha especificado el encoding correcto al inicio del documento.

Desplegar la información principal.
Esta es la sección principal del reporte, las columnas donde se muestra la información. En el tutorial anterior explicaba que esta sección es iterada sobre el data source provisto, anteriormente la consulta SQL generaba una colección de información regresada por la base de datos, en esta ocasión la colección se le pasará desde Java. Al diseñar el reporte esto no tiene ninguna implicación, simplemente se acomodan los campos en las posiciones deseadas, todo esto exactamente igual al tutorial anterior, pero con diferente información a desplegar.

<detail>
    <band height="15">
        <textField>
            <reportElement x="0" y="0" width="200" height="13"/>
            <textFieldExpression class="java.lang.String">
                <![CDATA[$F{universidad}]]>
            </textFieldExpression>
        </textField>
        <textField>
            <reportElement x="205" y="0" width="150" height="13"/>
            <textFieldExpression class="java.lang.String">
                <![CDATA[$F{rector}]]>
            </textFieldExpression>
        </textField>
        <textField>
            <reportElement x="360" y="0" width="150" height="13"/>
            <textFieldExpression class="java.lang.String">
                <![CDATA[$F{direccion}]]>
            </textFieldExpression>
        </textField>
        <textField>
            <reportElement x="515" y="0" width="20" height="13"/>
            <textFieldExpression class="java.lang.Integer">
                <![CDATA[$F{alumnos}]]>
            </textFieldExpression>
        </textField>
    </band>
</detail>

El reporte completo.
Esto es todo en cuanto al diseño del reporte, todo ha sido semejante por no decir igual al reporte del tutorial anterior, únicamente cambiamos el encoding para que aceptara acentos, se le agregó una nueva sección al reporte para desplegar los titulos de las columnas, la fecha se ha generado directamente en el reporte y se suprimió la consulta SQL a la base de dato, el reporte completo es el siguiente.

<?xml version="1.0" encoding="ISO-8859-1"  ?>
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN"
"http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<!--======================================================================================== -->
<!--===================================== Por Crysfel Villa==================================== -->
<!--======================================================================================== -->
<jasperReport
         name="plantilla"
         pageWidth="595"
         pageHeight="842"
         leftMargin="20"
         rightMargin="20"
         topMargin="20"
         bottomMargin="20">


    <parameter name="P_TITULO" class="java.lang.String"/>
    <parameter name="P_SUBTITULO" class="java.lang.String"/>
    <parameter name="LOGO_URL" class="java.lang.String"/>


   
    <field name="universidad" class="java.lang.String"/>
    <field name="rector" class="java.lang.String"/>
    <field name="direccion" class="java.lang.String"/>
    <field name="alumnos" class="java.lang.Integer"/>
   
        <background>
            <band height="67">
                <image>
                    <reportElement
                        x="430"
                        y="0"
                        width="100"
                        height="67"/>

                    <imageExpression class="java.lang.String"><![CDATA[$P{LOGO_URL}]]></imageExpression>
                </image>
            </band>
        </background>
        <title>
            <band height="90">
                <textField>
                    <reportElement
                        x="0"
                        y="40"
                        width="530"
                        height="30"/>

                    <textElement>
                        <font pdfFontName="Helvetica-Bold" size="20" isBold="true"/>
                    </textElement>
                <textFieldExpression   class="java.lang.String"><![CDATA[$P{P_TITULO}]]></textFieldExpression>
                </textField>
                <line direction="TopDown">
                    <reportElement
                        x="0"
                        y="69"
                        width="530"
                        height="0"
                        key="line"/>

                    <graphicElement stretchType="NoStretch"/>
                </line>
                <textField>
                    <reportElement
                        x="0"
                        y="70"
                        width="250"
                        height="20"
                        key="textField"/>

                    <textElement>
                        <font pdfFontName="Helvetica-Bold" size="10"/>
                    </textElement>
                <textFieldExpression   class="java.lang.String"><![CDATA[$P{P_SUBTITULO}]]></textFieldExpression>
                </textField>
                <textField pattern="EEEEE dd MMMMM yyyy">
                    <reportElement
                        x="260"
                        y="70"
                        width="270"
                        height="20"
                        key="textField"/>

                    <textElement textAlignment="Right">
                        <font pdfFontName="Helvetica-Bold" size="10"/>
                    </textElement>
                <textFieldExpression   class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
                </textField>
            </band>
        </title>
        <columnHeader>
            <band height="20">
                <staticText>
                    <reportElement x="0" y="0" width="200" height="13" key="staticText"/>
                    <text><![CDATA[Universidad]]></text>
                </staticText>
                <staticText>
                    <reportElement x="205" y="0" width="150" height="13"/>
                    <text><![CDATA[Rector]]></text>
                </staticText>
                <staticText>
                    <reportElement x="360" y="0" width="150" height="13"/>
                    <text><![CDATA[Dirección]]></text>
                </staticText>
                <staticText>
                    <reportElement x="490" y="0" width="100" height="13"/>
                    <text><![CDATA[Alumnos]]></text>
                </staticText>
            </band>
        </columnHeader>
        <detail>
            <band height="15">
                <textField>
                    <reportElement x="0" y="0" width="200" height="13"/>
                    <textFieldExpression class="java.lang.String">
                        <![CDATA[$F{universidad}]]>
                    </textFieldExpression>
                </textField>
                <textField>
                    <reportElement x="205" y="0" width="150" height="13"/>
                    <textFieldExpression class="java.lang.String">
                        <![CDATA[$F{rector}]]>
                    </textFieldExpression>
                </textField>
                <textField>
                    <reportElement x="360" y="0" width="150" height="13"/>
                    <textFieldExpression class="java.lang.String">
                        <![CDATA[$F{direccion}]]>
                    </textFieldExpression>
                </textField>
                <textField>
                    <reportElement x="515" y="0" width="20" height="13"/>
                    <textFieldExpression class="java.lang.Integer">
                        <![CDATA[$F{alumnos}]]>
                    </textFieldExpression>
                </textField>
            </band>
        </detail>

</jasperReport>

Ahora viene la parte interesante en Java, la cual cambiará muy poco conforme al tutorial anterior.

Generar el reporte con Java.
Para generar el reporte son necesarios cuatro pasos, muy sencillos por cierto. El paso número uno es llenar el data source con la información a enviar, el paso dos compilar el reporte, paso tres llenarlo con la información y parámetros necesarios, paso cuatro exportar el reporte al formato deseado, en este caso pdf.

package pruebas;
/**
 * Generar un reporte con Jasper Report
 * Por Crysfel Villa Roman
 * 21/01/2008
 *
 * */

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

import net.sf.jasperreports.engine.JasperCompileManager;
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;


public class JasperReport4{
  public static void main(String[] args){
    String reportName = "plantilla";
    JRBeanCollectionDataSource dataSource;
    JasperReport jasperReport;
    JasperPrint jasperPrint;
    Map pars = new HashMap();
    pars.put("LOGO_URL", "logo.gif");
    pars.put("P_TITULO", "Reporte de universidades inscritas");
    pars.put("P_SUBTITULO", "Región Nor-Este");
    try{
        //1-Llenar el datasource con la informacion de la base de datos o de donde este, en este caso "hardcode"
        Collection lista = populateData();
        dataSource = new JRBeanCollectionDataSource(lista);
       
        //2-Compilamos el archivo XML y lo cargamos en memoria
        jasperReport = JasperCompileManager.compileReport(
                reportName+".jrxml");

        //3-Llenamos el reporte con la información de la coleccion y parámetros necesarios para la consulta
        jasperPrint = JasperFillManager.fillReport(
            jasperReport, pars, dataSource);

        //4-Exportamos el reporte a pdf y lo guardamos en disco
        JasperExportManager.exportReportToPdfFile(
            jasperPrint, reportName+".pdf");

       
        System.out.println("Done!");
    }catch (Exception e){
      System.out.println(e);
      e.printStackTrace();
    }
  }
  private static Collection populateData(){
      Collection list = new ArrayList();
      list.add(new Universidad("Universidad de Montemorelos","Dr. Oscar Castillo","Montemorelos NL.",new Integer(4800)));
      list.add(new Universidad("Tecnológico de Monterrey","Dr. Jair Acosta","Monterrey NL.",new Integer(10956)));
      list.add(new Universidad("Universidad Regiomontana","Dr. Meliza Orduñez","Monterrey NL.",new Integer(5200)));
      list.add(new Universidad("Universidad Autónoma de México","Dr. Carlos Medina","Mexico DF.",new Integer(15700)));
      list.add(new Universidad("Instituto Politécnico Nacional","Dr. Manuel Obrador","México DF.",new Integer(16380)));
      list.add(new Universidad("Universidad del Valle de México","Dr. Héctor Solano","México DF.",new Integer(6280)));
      return list;
  }
}

Lo mas importante a resaltar aquí es la clase net.sf.jasperreports.engine.data.JRBeanCollectionDataSource la cual es la encargada de entregar la información al reporte. Esta clase se instancia con una colección de Objetos DTO. En este caso el objeto es Universidad, que contiene las mismas propiedades que el reporte desplegará con sus respectivos getters y setters.

Para ejemplo se ha hardcodeado la información en el método populateData, en la vida real esto no se hace, este método debiera ser implementado de acuerdo a las necesidades del desarrollador, ya sea consultando una base de datos, un webservice, un archivo de texto, etc.

A continuación el bean necesario para llenar el reporte.

package pruebas;

public class Universidad {
    private String universidad;
    private String rector;
    private String direccion;
    private Integer alumnos;
   
    //Obligatorio tener un constructor sin parametros.
    public Universidad(){
       
    }
    //Constructor util para setear las propiedades inicialmente.
    public Universidad(String universidad,String rector,String direccion,Integer alumnos){
        this.universidad = universidad;
        this.rector = rector;
        this.direccion = direccion;
        this.alumnos = alumnos;
    }

    public Integer getAlumnos() {
        return alumnos;
    }

    public void setAlumnos(Integer alumnos) {
        this.alumnos = alumnos;
    }

    public String getDireccion() {
        return direccion;
    }

    public void setDireccion(String direccion) {
        this.direccion = direccion;
    }

    public String getRector() {
        return rector;
    }

    public void setRector(String rector) {
        this.rector = rector;
    }

    public String getUniversidad() {
        return universidad;
    }

    public void setUniversidad(String universidad) {
        this.universidad = universidad;
    }
   
}

Lo más importante aquí es que las propiedades deben corresponder a los campos declarados en el reporte, de esta manera el motor de JasperReports puede relacionarlas y desplegar la información.

El código es muy claro y sencillo, si se siguen los cuatro pasos no se tendrá problema para generar el reporte, al igual que en los tutoriales anteriores voy a poner el proyecto para eclipse, con el ejemplo, para ser descargado.

Po último quiero dar una disculpa por referirme tanto al tutorial anterior, pero tanto este como el tutorial anterior son muy semejantes. ;-)

Saludos.

Imprimir Comentarios (14) Leer mas

14 Respuestas para este tema

Lucy

Wednesday, February 6, 2008, 3:28 pm

Muchisimas gracias me quebre la cabeza tratando de hacer un reporte asi (es la primera vez q hago un reporte) y esta es la unica pagina que me ayudo de verdad, muy bueno tu tutorial. Felicitaciones.

AJENJO

Wednesday, March 12, 2008, 6:33 am

La verdad es de lo mejorcito que hay por ahí.

Lo que sí quería preguntarte es si existe alguna posibilidad de que un determinado texto (que ocupa bastante) pueda ajustarse al campo de texto en donde se encuentra y no me lo corte cuando ya llega al tope del textField donde está definido.

Y si existe alguna posibilidad (aunque creo que no, ya que he visto que el atributo height tiene que existir siempre) de que la línea donde aparezca el texto varíe de altura dependiendo del contenido, en este caso del tamaño de la cadena a mostrar.

Gracias y enhorabuena.

AJENJO

Wednesday, March 12, 2008, 7:54 am

Ok. Solucionado.

Se hace con el atributo isStretchWithOverflow=”true”. Mi problema ahora es que si el texto está en el último registro de la página y es demasiado largo corta el texto y lo que falta lo pone en la siguiente página. Puedo controlar esto, o sea, que no me corte el texto del último registro de la página?

Gracias

MIRIAM

Monday, May 12, 2008, 5:42 am

Hola Crysfel!
Muchas gracias por este ejemplo, llevaba un tiempo buscando como hacerlo y al fin lo he conseguido.
Pero ahora el problema es que dentro de este informe maestro tengo subinformes y no consigo lograr que obtenga los datos del datasource que le he pasado.Simplemente lo muestra todo en blanco. :-(
¿Tienes idea de hacerlo?

Gracias por todo!

MANUEL

Monday, May 12, 2008, 9:40 am

excelente trabajo,
me ayudo muchisimo, este caso por lo que veo es una lista para la “banda detalle”

es posiblemandar 2 listas diferentes (Universidad, Facultades), e iterar ambas en la “banda detalle”

gracias de antemano

Crysfel

Monday, May 12, 2008, 11:19 am

@MIRIAM
Hola, mira la verdad no he tenido la necesidad de pasarle una colección de beans a subreportes, lo que me ha funcionado siempre es meterle el SQL a cada subreporte en especifico y solo pasarle los parámetros necesarios a cada subreporte.

@MANUEL
La solución a lo que preguntas es hacer subreportes, esto es hacer reportes individuales y luego juntarlos todos en pequeñas secciones dentro de un reporte principal o maestro, de esta manera puedes tener diferente información en el “mismo reporte”.

MIRIAM

Tuesday, May 13, 2008, 1:53 am

Si con la SQL va genial, pero en mi caso cuando llamo al informe ya tengo el objeto, entonces hacer una consulta a la bbdd es una perdida de tiempo y recursos, sobretodo cuando la clase contiene muchos campos.
Al final ayer conseguí pasarle los datos al subinforme, pero de momento estoy probandolo.

Gracias y Un saludo!

Paco

Tuesday, June 24, 2008, 4:52 am

Bueno mákina la verdad es que sabia muy poco de jasper y gracias a tu ayuda en media hora he montado un reporte de una colección, muchisimas gracias, hace falta más gente como tu.

Solo una cosa cambia el ‘vasta’
que tienes en el texto, que baja mucho la calidad del artículo.

un saludo.

Crysfel

Wednesday, June 25, 2008, 5:20 pm

@Paco
Gracias por el feedback, me alegra que te sirvió este tutorial. :D

antonio

Saturday, June 28, 2008, 5:37 am

Oye, muchas gracias por este tutorial, llevaba horas tratando de hacer un data source desde el ireports y nada, y pues con tus ejemplos y consejos pude avanzar demasiado, solo te tengo una pregunta y es saber si al mismo reporte, puedo agregarle otro bean, por ejemplo paises, con diferentes campos, y q si este reporte se llenaria de la misma forma como cuando uno maneja sql, q puede tener varias tablas, gracias de nuevo desde Colombia crisfel

Casto

Monday, June 30, 2008, 2:42 pm

Muchas gracias por tu aporte, me a servido de mucho. Adicional a lo que muestras aca me gustaria saber como recorrer una coleccion dentro de un javabeans. Ejemplo: teniendo la universidad un List de aulas con nombre y profesor. como hago para recorrer esto en el reporte. He intentado d todo y nada. No se como decirle que rrecorra el objeto y q saque sus valores. El convierte la lista dentro del bean a cadena. No se si es tan flexible como lo q se hace JSF. Por favor hazme saber. Gracias.

edo

Wednesday, July 2, 2008, 4:27 pm

erda mijo ke barbaro.
MIs felicitaciones crys.

Hossain

Thursday, July 3, 2008, 5:42 am

Hola Crysfel, te queria hacer una pregunta a ver si me puedes ayudar.

Necesito generar un reporte e incluirle una imagen en la cabecera, pero esta imagen dependerá del valor que tengamos en una tabla en Base de Datos.

Por ejemplo, si en base de datos tenemos ESP, pondremos la bandera de españa, si tenemos ING pondremos la bandera Inglesa y asi sucesivamente.

Un saludo.

Crysfel

Thursday, July 3, 2008, 9:55 am

@Hossain
Esas comparaciones las puedes hacer con java, antes de generar el reporte le asignas el al parámetro de la URL de la imagen, el path a donde esta la imagen adecuada.

saludos. :d

Deja una respuesta