21
May
13

Jasper Report (virtualización y generación de reportes)

Una de las partes a veces menos preciada, dentro de un software son los reportes que de este podemos extraer. Los reportes son documento (que puede ser impreso, digital, audiovisual, etc.) que pretende transmitir información clara y entendible acerca del estado, las características y/o circunstancias de un suceso o asunto.

 

La manera más fácil de observar el estado actual de un negocio a través de su software son las dashboard o los reportes que podemos extraer de ellos. personalmente considero que la mejor suite de reportes que conozco es la Crystal Reports, pero con la que más experiencia tengo (y de la que voy a hablar en está publicación) es Jasper Reports.

 

Jasper es una poderosa herramienta open source totalmente escrita en java y se utiliza para la creación de informes, utiliza diversas clases de data sources, también permite incluir reportes dentro de otros, y exportarlos en los formatos más comunes como son XLS, PDF, RTF, CSV, XML, TXT  y HTML.

 

Existen dos herramienta totalmente visual que nos facilita la creación de nuestros reportes Jaspersoft Studio (basado en eclipse, y cual yo utilizo) y el iReport Designer (basado en netbeans).  No entraremos en como crear reportes y que puedo hacer o no con Jasper, primero pasaremos por hacer un reporte un listado normal y como exportarlo en un formato de los anteriores mencionados; Utilizando el mismo ejemplo departamento-empleado (utilizado ya en más de una ocasión).

 

Desde está dirección podemos descargar Jasper http://sourceforge.net/projects/jasperreports/?source=dlp, jasper utiliza muchas bibliotecas las cuales también debemos incluir en nuestro classpath.

El resto de la configuración es tomada del ejemplo base (MVC en JSP), nos centraremos especialmente en lo que tiene que ver con Jasper y la generación de reportes:

En este ejemplo generaremos un solo reporte reporte_empleados.  este reporte por formato incluye dos subreportes, uno que contiene la cabecera y otro que contiene el pie de página.

reportes

reportes

Nota: Por cada reporte se muestran dos archivos uno es el archivo con el código editable y el otro es el archivo resultande de la compilación.

cabecera

cabecera (header.jrxml)

 

pie de página

pie de página (footer.jrxml)

 

reporte empleados

reporte empleados (reporte_empleados.jrxml)

 

Nota: los iconos  2013-05-21_11h15_34 indican que se está haciendo referencia a un sub-reporte  en este caso cabecera y pie de página respectivamente.

los archivos de reporte de jasper se crean en un formato .jrxml que luego de compilarlo pasa a ser .jasper se puede usar cualquiera de los dos para la generación del reportes, personalmente prefiero los .jasper porque ya están compilados y es un poco más rápido.

También hay que tener en cuenta que como estamos trabajando con Java, a los reportes debemos especificarle que estamos trabajando con ese lenguaje. Y para los reportes cuando los exportamos en HTML a las imágenes (en este caso el logo) le seteamos que sean Lazy.

Lenguaje java

Lenguaje java

Lazy

Lazy

A nivel de GUI  se creo una para generar el reporte de empleados, cuando damos clic en el botón “Generar” de Listado de empleados.

generar reportes

generar reportes

Nota: el único botón que funciona es el de listado de empleados

generar_reporte.jsp

<form action="<%=application.getAttribute("CONTROLLER").toString()%>/Generar/Reporte" method="post" enctype="application/x-www-form-urlencoded">
    <table width="100%" border="0" cellspacing="0" cellpadding="5">
        <tr>
            <td valign="top">
			Listado de empleados
            </td>
            <td>
                <select name="tipo">
                    <option value="pdf">pdf</option>
                    <option value="rtf">rtf</option>
                    <option value="xls">xls</option>
                    <option value="html">html</option>
                    <option value="xml">xml</option>
                    <option value="csv">csv</option>
                    <option value="txt">txt</option>
                </select>
            </td>
            <td>
                <input name="reporte" type="hidden" value="empleados">
                <input type="submit" value="Generar">
            </td>
        </tr>
    </table>
</form>

<form action="<%=application.getAttribute("CONTROLLER").toString()%>/Generar/Reporte" method="post" enctype="application/x-www-form-urlencoded">
    <table width="100%" border="0" cellspacing="0" cellpadding="5">
        <tr>
            <td valign="top">
			Listado de departamentos
            </td>
            <td>
                <select name="tipo">
                    <option value="pdf">pdf</option>
                    <option value="rtf">rtf</option>
                    <option value="xls">xls</option>
                    <option value="html">html</option>
                    <option value="html">xml</option>
                    <option value="html">csv</option>
                    <option value="txt">txt</option>
                </select>
            </td>
            <td>
                <input name="reporte" type="hidden" value="departamentos">
                <input name="reporte" type="button" value="Generar">
            </td>
        </tr>
    </table>
</form>

A nivel de Actions se creo uno para escribir el reporte en la salida del response GenerarReporte; esta clase se encarga de escribir por la salida el reporte.

GenerarReporte.java

package org;

//clases para que sea servlet
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import javax.servlet.ServletException;
import java.util.HashMap;

public class GenerarReporte extends Action implements Serializable {

    public void run() throws ServletException, IOException {
        try {
            String reporte = request.getParameter("reporte");
            String tipo = request.getParameter("tipo");
            /*la direccion local a la imagen del logo*/
            ReportGenerator.DIRECCION_LOGO=application.getRealPath("/shared/images/ids_report_logo.png");
            /*la direccion local de la carpeta donde se encuentral los reportes*/
            ReportGenerator.DIRECCION_REPORTES=application.getRealPath("/shared/report/")+ File.separator;

            if (tipo.matches("pdf")) {
                response.setContentType("application/pdf");
                ReportGenerator.FORMATO_REPORTE = ReportGenerator.FORMATO_REPORTE_PDF;
            } else if (tipo.matches("rtf")) {
                response.setContentType("application/rtf");
                ReportGenerator.FORMATO_REPORTE = ReportGenerator.FORMATO_REPORTE_RTF;
            } else if (tipo.matches("xls")) {
                response.setContentType("application/vnd.ms-excel");
                ReportGenerator.FORMATO_REPORTE = ReportGenerator.FORMATO_REPORTE_XLS;
            } else if (tipo.matches("html")) {
                response.setContentType("text/html");
                ReportGenerator.FORMATO_REPORTE = ReportGenerator.FORMATO_REPORTE_HTML;
                /*si elreporte es HTML la utilizamos la url para acceder a la imagen*/
                ReportGenerator.DIRECCION_LOGO=request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath()+"/shared/images/ids_report_logo.png";
            } else if (tipo.matches("xml")) {
                response.setContentType("application/xml");
                ReportGenerator.FORMATO_REPORTE = ReportGenerator.FORMATO_REPORTE_XML;
            } else if (tipo.matches("csv")) {
                response.setContentType("text/csv");
                ReportGenerator.FORMATO_REPORTE = ReportGenerator.FORMATO_REPORTE_CSV;
            } else if (tipo.matches("txt")) {
                response.setContentType("text/plain");
                ReportGenerator.FORMATO_REPORTE = ReportGenerator.FORMATO_REPORTE_TXT;
            }
            response.setHeader("Content-disposition", "attachment");
            response.setHeader("filename", reporte + "." + tipo);
            /*mandamos a crear el reporte*/
            byte[] reporteBytes = ReportGenerator.createReport(reporte, new HashMap(), model);
            OutputStream outputStream = response.getOutputStream();
            /*escribimos el reporte*/
            outputStream.write(reporteBytes);
            outputStream.flush();
        } catch (Exception ex) {
            throw new ServletException("error en GenerarReporte ", ex);
        }
    }
}

A nivel de utilidades se utiliza la clase ReportGenerator, ReportGenerator es la clase donde generamos el reporte en un formato especifico. cada formato tiene sus particularidades aunque funcionalmente y para nuestro ejemplo solo necesitamos modificar tres de estos:

exporter = new JRHtmlExporter();
exporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, Boolean.FALSE);

Los reportes en HTML sino se le especifica  el parámetro IS_USING_IMAGES_TO_ALIGN a falso, este utilizará unas imágenes en blanco para darle espaciamiento al reporte añadiendo una lógica que para mi parecer es innecesaria (o lo ha sido hasta el momento).

exporter = new JRTextExporter();
exporter.setParameter(JRTextExporterParameter.PAGE_HEIGHT, new Integer(70).floatValue());
exporter.setParameter(JRTextExporterParameter.PAGE_WIDTH, new Integer(70).floatValue());
exporter.setParameter(JRTextExporterParameter.CHARACTER_WIDTH, new Integer(15).floatValue());
exporter.setParameter(JRTextExporterParameter.CHARACTER_HEIGHT, new Integer(15).floatValue());

Los reportes de tipo texto necesitan un tamaño de página y de carácter estos valores no están por defecto y sino son seteados lanzará una excepción.

exporter = new JRXlsExporter();
exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE);
exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
exporter.setParameter(JRXlsExporterParameter.IS_IGNORE_CELL_BORDER, Boolean.FALSE);

Por estética más que por otra cosa esta es la configuración que utilizo para generar Excel desde Jasper (aunque para los reportes en realidad utilizo JExcel o POI directamente).

package org;

import java.util.Map;
import java.io.File;
import java.io.ByteArrayOutputStream;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.fill.JRFileVirtualizer;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.engine.export.JRXmlExporter;
import net.sf.jasperreports.engine.export.JRTextExporter;
import net.sf.jasperreports.engine.export.JRTextExporterParameter;

public class ReportGenerator {

    public static Integer FORMATO_REPORTE = 1;
    public final static Integer FORMATO_REPORTE_PDF = 1;
    public final static Integer FORMATO_REPORTE_XLS = 2;
    public final static Integer FORMATO_REPORTE_RTF = 3;
    public final static Integer FORMATO_REPORTE_HTML = 4;
    public final static Integer FORMATO_REPORTE_XML = 5;
    public final static Integer FORMATO_REPORTE_CSV = 6;
    public final static Integer FORMATO_REPORTE_TXT = 7;
    public static String DIRECCION_LOGO = null;
    public static String DIRECCION_REPORTES = null;
    private static JRFileVirtualizer reportVirtualizer = null;

    public static byte[] createReport(String nombreReporte, Map parametros, Model model) throws Exception {
        /*la virtualizacion no es obligatoria*/
        if (reportVirtualizer == null) {
            /*y de los tres metodos para virtualizar reportes prefiero la de archivos.
             utilizamos una carpeta en disco para ello*/
            String urlReportes = System.getProperty("user.home") + File.separator + "ids" + File.separator + "temp";
            File carpeta = new File(urlReportes);
            File[] archivos = carpeta.listFiles();
            /*eliminamos el contenido de dicha carpeta*/
            if(archivos!=null){
            	 for (File file : archivos) {
	                try {
	                    file.delete();
	                } catch (Exception e) {
	                    e.printStackTrace();
	                }
	            }
            }

            /*declaramos el virtualizador*/
            reportVirtualizer = new JRFileVirtualizer(10, urlReportes);
        }

        parametros.put(JRParameter.REPORT_VIRTUALIZER, reportVirtualizer);
        parametros.put("direccion_logo", DIRECCION_LOGO);
        parametros.put("titulo", nombreReporte.toUpperCase());
        parametros.put("direccion_reportes", DIRECCION_REPORTES);
        /*cargamos el archivo jasper*/
        JasperReport report = (JasperReport) JRLoader.loadObject(DIRECCION_REPORTES + "reporte_" + nombreReporte + ".jasper");
        /*cargamos la informacion*/
        JasperPrint jasperPrint = JasperFillManager.fillReport(report, parametros, model.getConexion());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        JRExporter exporter = null;
        /*configuramos la impresion del reporte dependiendo del formato*/
        if (FORMATO_REPORTE == FORMATO_REPORTE_PDF) {
            exporter = new JRPdfExporter();
        } else if (FORMATO_REPORTE == FORMATO_REPORTE_RTF) {
            exporter = new JRRtfExporter();
        } else if (FORMATO_REPORTE == FORMATO_REPORTE_HTML) {
            exporter = new JRHtmlExporter();
            exporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, Boolean.FALSE);
        } else if (FORMATO_REPORTE == FORMATO_REPORTE_XML) {
            exporter = new JRXmlExporter();
        } else if (FORMATO_REPORTE == FORMATO_REPORTE_CSV) {
            exporter = new JRCsvExporter();
        } else if (FORMATO_REPORTE == FORMATO_REPORTE_TXT) {
            exporter = new JRTextExporter();
            /*para los reportes en texto debemos expresar el tamaño de la pagina*/
            exporter.setParameter(JRTextExporterParameter.PAGE_HEIGHT, new Integer(70).floatValue());
            exporter.setParameter(JRTextExporterParameter.PAGE_WIDTH, new Integer(70).floatValue());
            exporter.setParameter(JRTextExporterParameter.CHARACTER_WIDTH, new Integer(15).floatValue());
            exporter.setParameter(JRTextExporterParameter.CHARACTER_HEIGHT, new Integer(15).floatValue());
        } else if (FORMATO_REPORTE == FORMATO_REPORTE_XLS) {
            exporter = new JRXlsExporter();
            /*para los reportes en excel para una mejor visualizacion utilizo esta configuracion*/
            exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE);
            exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
            exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
            exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
            exporter.setParameter(JRXlsExporterParameter.IS_IGNORE_CELL_BORDER, Boolean.FALSE);
        }
        /*marcamos PDF como el formato predeterminado*/
        FORMATO_REPORTE = FORMATO_REPORTE_PDF;
        /*exportamos el reporte*/
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
        exporter.exportReport();
        /*obtenemos el byte[] que representa ek archivo*/
        if (baos != null) {
            /*llamamos al garbage collector*/
            System.gc();
            return baos.toByteArray();
        }
        return null;
    }
}

Otro tema que se esta incluyendo en esta clase es la Virtualización de los reportes en Jasper (la virtualización, data sources y el ciclo de vida de un reporte jasper serán tratados a futuro) tiene utilidad en caso de reportes muy grande ya que la información se carga en memoria y puede generar una OutOfMemoryException, la virtualización se utiliza para almacenar la información del reporte de manera temporal en otra disposición (afectando el rendimiento) garantizando que la memoria no se llenará a causa de Jasper y evitando un colapso en el sistema.


0 Responses to “Jasper Report (virtualización y generación de reportes)”



  1. Dejar un comentario

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s


I+Ds

Dudas consultas
Facebook
Twiter
Google +

Escribe tu dirección de correo electrónico para suscribirte a este blog, y recibir notificaciones de nuevas publicaciones por correo.

Únete a otros 348 seguidores

Ingenio DS en Facebook

Redes Sociales y Archivos

Entradas

mayo 2013
L M X J V S D
« Abr   Sep »
 12345
6789101112
13141516171819
20212223242526
2728293031  

IngenioDS en twiter


A %d blogueros les gusta esto: