Informes dinámicos con DynamicJasper

9
35738

Informes dinámicos con DynamicJasper

0. Índice de contenidos

1. Introducción

DynamicJasper es una buena librería de la que nos podemos servir para hacer nuestra vida un poco más fácil, principalmente cuando estamos trabajando en la generación
de informes con JasperReports.

Es open-source y nos va a permitir crear informes de manera dinámica, definiendo en tiempo de ejecución gran parte de los elementos que pone a nuestra disposición JaperReports para crear informes (Definición de columnas, grupos, variables, tipos de letras, gráficos, subinformes etc …. ) .

Por experiencia, en la mayor parte de los proyectos en los que he tenido que trabajar con JasperReports, siempre he tendido a definir una plantilla para cada uno
de los informes. Principalmete porque el diseño y la información de estos informes siempre era la misma (informes estáticos). Sin embargo, en ocasiones y debido a la complejidad de informe no era suficiente con una simple plantilla y era necesario mostrar un diseño y una información distinta en un único informe lo que hasta ahora,
que no conocía esta librería, me había dado más de un quebradero de cabeza.

Ahora DynamicJasper nos da una solución facil para generar informes dinámicos, integrándose a la perfección con Maven y manteniendo la compatibilidad con los informes de Jasper ya que sólo se trata de una herramienta de ayuda a la creación de informes a nivel de programación.

Antes de continuar os dejo el código fuente con el ejemplo que veremos en el tutorial y la referencia a la página
http://dynamicjasper.com/ a la página oficial de la librería donde podemos encontrar más información.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware : Portátil Mac Book Pro 15″ (2,6 Ghz Intel Core i7, 4 GB DDR3)
  • Sistema Operativo:Mac OS X Snow Leopard 10.6.6
  • Eclipse Galileo
  • Apache Maven 2.2.1
  • JaspertReports 3.5.2
  • DynamicJasper 3.0.13

3. Características

Hay que decir que la mayoría de las características de la librería son proporcianadas por JasperReports pero haciendo uso del API de DynamicJasper obtenedremos buenos resultados con un mínimo esfuerzo. A continuación paso a destacar algunas de las principales características de DynamicJasper:

  • Informes con columnas dinámicas

    Las propiedades de las columnas se pueden definir en tiempo de ejecución lo que nos proporciona el control total sobre el diseño del informe.

  • Creación y repetición de grupos

    Esto es muy interesante ya que nos permite definir grupos en función a unos criterios (como con Jasper) pero además nos permite modificar propiedades
    de cada unos de los grupos tales como el encabezado o pie de página por ejemplo.

  • Informe de diseño automático

    Con sólo definir un conjunto mínimo de opciones DynamicJasper se encarga de generar el informe de manera automática. Esta característica se convertirá en una de las más a útiles a la hora de trabajar con DynamicJasper.

  • Dynamic Crosstab

    Con DynamicJasper el manejo de las populares tablas de referencias cruzadas (crosstabs) se hace de una manera mucho mas sencilla y conveniente.

  • SubInformes dinámicos

    De la misma manera que con los informes con DynamicJasper podemos crear en tiempo de ejecución los subinformes. Esto supone que no tendremos que tener las plantillas que se definen normalmente para los subinformes en Jasper. Además tendremos la capacidad de que el diseño y la información de cada uno de los subinformes que pertenecen al informe principal pueda ser distinta.

  • Estilos

    Cada columna puede tener sus propios estilos para el título y datos de detalle definiendo aspectos tales como color de borde, tamaño de la fuente, tipo y color, color de fondo ect….

  • Cálculo de variables

    Con DynamicJasper es posible crear y modificar variables de informe con el resultado de una operación en un determinado campo (columna) y que podremos utilizar por ejemplo como condiciones a la hora de trabajar con grupos.

  • Uso de plantillas

    Nos va a permitir hacer uso de plantillas jrxml básicas para definir los aspectos comunes y no perecederos en nuestros informes tales como el logotipo de la
    empresa, el fondo corporativo etc …

4. Requerimientos y configuración

Según la documentación oficial para poder trabajar con esta librería es necesario tener una serie de dependencias. A continuación se indican las librerías mínimas para el correcto funcionamiento de DynamicJasper:

A pesar de ello para el ejemplo que os mostraré a continuación solo ha sido necesario las referencias a JasperReports y DynamicJasper.
Por tanto en cuanto a la configuración se refiere no podía ser más sencillo ya que como he comentado anteriormente DynamicJasper se integra con Apache Maven y sólo tendremos que incluir en nuestro fichero de dependencias (pom.xml) las siguientes líneas:

	
	    ar.com.fdvs
	    DynamicJasper
	    3.0.13
	
	
	
	    jasperreports
	    jasperreports
	    3.5.2
	

5. Un par de ejemplos

ReportBase.java : Esta clase es la que contiene la lógica necesaria para generar el informe propieamente dicho y hace uso de JaperReports y DynamicReports. El resto de clases extiende de ésta e implementan la contrucción del informe a nivel de diseño y obtienen la fuente de datos.

Por el resto creo que no hay mucho que explicar ya que el código es bastante sencillo así que solo echadle un ojo.

public abstract class ReportBase {

	protected static final Log log = LogFactory.getLog(ReportBase.class);
	protected JasperPrint jp;
	protected JasperReport jr;
	protected Map params = new HashMap();
	protected DynamicReport dr;

	
	public abstract DynamicReport buildReport() throws Exception;
	
	public abstract JRDataSource getDataSource();

	public void generateReport() throws Exception {
 			
		dr = buildReport();
  
		/**
		 * Ontenemos la fuente de datos en base a una colleccion de objetos
		 */
  		JRDataSource ds = getDataSource();
  
	  	/**
		 * Creamos el objeto JasperReport que pasamos como parametro a 
		 * DynamicReport,junto con una nueva instancia de ClassicLayoutManager 
		 * y el JRDataSource
		 */
  		jr = DynamicJasperHelper.generateJasperReport(dr, getLayoutManager(), params);
  
	  	/**
	  	 * Creamos el objeto que imprimiremos pasando como parametro
		 * el JasperReport object, y el JRDataSource
		 */
  		log.debug("Filling the report");
  		if (ds != null){
  			jp = JasperFillManager.fillReport(jr, params, ds);
  		}else{
  			jp = JasperFillManager.fillReport(jr, params);
  			log.debug("Filling done!");
  			log.debug("Exporting the report (pdf, xls, etc)");
  		}
  			
  		exportReport();
 
        log.debug("test finished");
		 
	}

	

	protected LayoutManager getLayoutManager() {
		return new ClassicLayoutManager();
	}

	
	
	protected void exportReport() throws Exception {

			final String path=System.getProperty("user.dir")+ "/target/reports/" + this.getClass().getCanonicalName()+ ".pdf";
			
			log.debug("Exporing report to: " + path);
			JRPdfExporter exporter = new JRPdfExporter();
			File outputFile = new File(path);
			File parentFile = outputFile.getParentFile();
			if (parentFile != null)
			  			parentFile.mkdirs();
			
	  		FileOutputStream fos = new FileOutputStream(outputFile);
			  
	  		exporter.setParameter(JRExporterParameter.JASPER_PRINT, jp);
	  		exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, fos);
	  
	  		exporter.exportReport();
	  		log.debug("Report exported: " + path);
			
	}
		 	
	
	protected void exportToJRXML() throws Exception {
		if (this.jr != null){
			DynamicJasperHelper.generateJRXML(this.jr, "UTF-8",System.getProperty("user.dir")+ "/target/reports/" + this.getClass().getCanonicalName() + ".jrxml");
			
		} else {
			DynamicJasperHelper.generateJRXML(this.dr, this.getLayoutManager(), this.params, "UTF-8",System.getProperty("user.dir")+ "/target
			/reports/" + this.getClass().getCanonicalName() + ".jrxml");
		}
	}	
	
	
}

Ejemplo sencillo que muestra la configuración básica de un informe y sus columnas:

public class SimpleReportOne extends ReportBase{

	
	public static void main(String[] args) throws Exception {
  		SimpleReportOne simpleReportOne = new SimpleReportOne();
  		simpleReportOne.generateReport();
  		simpleReportOne.exportToJRXML();
  		JasperViewer.viewReport(simpleReportOne.jp);	//finally display the report report
  		JasperDesignViewer.viewReportDesign(simpleReportOne.jr);
	}

	public DynamicReport buildReport() throws Exception {

		FastReportBuilder drb = new FastReportBuilder();
		
  		drb.addColumn("Name", "name", String.class.getName(),30)
			.addColumn("Address", "address", String.class.getName(),30)
  			.addColumn("Zip Code", "zipcode", Integer.class.getName(),10)
  			.addColumn("Country", "country", String.class.getName(),50)
  			.setTitle("Primer informe con Dynamic Jasper")
  			.setSubtitle("Ha sido generado " + new Date())
  			.setPrintBackgroundOnOddRows(true)			
  			.setUseFullPageWidth(true);
		  
  		return drb.build();

	}

	public JRDataSource getDataSource() {
		Collection dataOneReport = getDataOneReportMock();
		dataOneReport = SortUtils.sortCollection(dataOneReport,dr.getColumns());

		//Create a JRDataSource, the Collection used
		JRDataSource ds = new JRBeanCollectionDataSource(dataOneReport);		
		return ds;

	}

	private Collection getDataOneReportMock() {
		
		SimpleReportOneBean elementToInclude;
		Collection dataResult=new ArrayList();
		
		for (int i = 0; i < 10; i++) {
			elementToInclude=new SimpleReportOneBean();
			elementToInclude.setName("name "+ i);
			elementToInclude.setAddress("address "+i);
			elementToInclude.setZipcode(i);
			elementToInclude.setCountry("country" + i);
			dataResult.add(elementToInclude);
		}
		
		
		return dataResult;
	}

}

Como vemos la aplicación se encarga de generar un informe en función del diseño
inicial que definimos en el la implementación del método buildReport().
En dicho método definimos cada una de las columnas indicando como parámetros:

  • literal que se visualizará en la cabecera
  • nombre de la propiedad del objeto que representan cada una de las lineas del informe
  • tipo de objeto de la propiedad
  • ancho de cada una de las columnas

Además estamos indicando un título, que se pinten las filas con colores de manera
alternativa y que se ocupe todo el ancho posible de la página.
Para poder ver el resultado pulsamos sobre las clase y ejecutar como --> Java Application .
A continuación se mostrará el informe en una ventana como esta:

En el siguiente ejemplo vamos a ver cómo generar un informe en base a una plantilla predefinida y creada desde iReports. Esta plantilla sólo tiene campo para la imagen y otro para el título aunque podríamos definir todos los elementos comunes e inalterables del informe:

	public class SimpleReportTemplate extends ReportBase {

	public static void main(String[] args) throws Exception {
		SimpleReportTemplate reportTemplate=new SimpleReportTemplate();
		reportTemplate.generateReport();
		reportTemplate.exportToJRXML();
  		JasperViewer.viewReport(reportTemplate.jp);	//finally display the report report
  		JasperDesignViewer.viewReportDesign(reportTemplate.jr);

	}

	@Override
	public DynamicReport buildReport() throws Exception {
		// Definimos las columnas del informe
		final String[] columns = {"name","address","zipcode","country"};
		// Definimos el titulo y el logo como parametros del informe
		params =populateParametersMap("Informe en base a una plantilla");
		// Construimos el informe dinámico en funcionde las columnas y la lista de objetos que se pintara
		final DynamicReport dynamicReport = new ReflectiveReportBuilder(getDataOneReportMock(), columns).
		setTemplateFile(System.getProperty("user.dir")+ "/src/main/resources/dynamicJasperReportTemplate.jrxml").build();
		
		// Definimos un estilo para el detalle de las properties
		Style styleColumns = new Style(); 
		styleColumns.setHorizontalAlign(HorizontalAlign.CENTER);
		styleColumns.setTextColor(Color.BLUE);
		styleColumns.setBorder(Border.PEN_1_POINT);
		
		// Definimos algunas propiedades para las distintas columnas del informe
		for (int i = 0; i < columns.length; i++) {
			String name = columns[i];
			final PropertyColumn propertyColumn = (PropertyColumn)dynamicReport.getColumns().get(i);
			propertyColumn.setTitle(name);
			propertyColumn.setBlankWhenNull(true);
			propertyColumn.setWidth(25);
			propertyColumn.setStyle(styleColumns);
		}
		
		
		return dynamicReport;
	}

	
	private Map populateParametersMap(String title) {
		
		final Map parameters = new HashMap();
		final String pathLogo=System.getProperty("user.dir")+ "/src/main/resources/autentialogo.png";
		
			parameters.put("REPORT_LOGO", new File(pathLogo).getPath());
			parameters.put("REPORT_TITLE", title);
		return parameters;
	}

	
}

Como podemos observar la única diferencia con el ejemplo anterior es la implementación del builReport(), donde definimos un diseño distinto en algunos detalles como por ejemplo:

  • Línea 19 : Construimos el informe en base a las columnas que sólo están definidas y la fuente de datos. Lo importante aquí es el setTemplateFile donde indicamos la plantilla básica que hemos diseñado en anterioridad.
  • Línea 23-26: Se define un estilo que se aplicará al detalle de cada una de las columnas. (Alineación, color del texto y border de cada campo).
  • Línea 29-36: Es donde se definen unas propiedades mínimas para cada propiedad incluyendo los estilos.

Si ejecutamos el programa veremos el siguiente informe:

6. Conclusiones

Con este simple ejemplo hemos podido comprobar lo sencillo y rápido que puede resultar generar un informe con DynamicJasper. Y lo mejor de todo es que esto es sólo un adelanto ya que la librería nos ofrece un gran número de posiblidades que intentaré ir desgranando en próximos tutoriales.

Como ya he comentado en alguna ocasión, desde Autentia os animamos a que probéis todas aquellas herramientas que puedan hacer vuestra vida como desarrolladores un poco más facil. Intentad no caer en la tentación de programar todo ya que en muchísimas ocasiones hay muy buenas librerías que hacen justo lo que necesitamos y además con una buena calidad como DynamicJasper.

Espero que os sirva de utilidad.

Un Saludo,

Sau´l García Díaz

9 COMENTARIOS

  1. Este tutorial también lo veo interesante, pues los informes a día de hoy es algo solicitado en muchos clientes. Todo lo que permita dinamizar esta parte es un buen avance,

    Gracias,
    Jaime.

  2. Muy buen tutorial, en este momento momento me estan saliendo errores cuando uso las clases de dynamicJasper y es que no encuentra la clase, como por ejemplo este error

    java.lang.ClassNotFoundException: ar.com.fdvs.dj.core.layout.LayoutManager

    me pasa con cualquier clase que este adentro de dynamic jasper y eclipse no me informa de ningun error.

  3. PD: me da este error

    Exception in thread \\\»main\\\» java.lang.NoSuchMethodError: ar/com/fdvs/dj/domain/DynamicJasperDesign.setPrintOrder(B)V
    at ar.com.fdvs.dj.core.DJJRDesignHelper.getNewDesign(DJJRDesignHelper.java:69)
    at ar.com.fdvs.dj.core.DynamicJasperHelper.generateJasperDesign(DynamicJasperHelper.java:207)
    at ar.com.fdvs.dj.core.DynamicJasperHelper.generateJasperReport(DynamicJasperHelper.java:535)
    at ar.com.fdvs.dj.core.DynamicJasperHelper.generateJasperReport(DynamicJasperHelper.java:518)
    at src.ReportBase.generateReport(ReportBase.java:50)
    at src.dynamicReport.main(dynamicReport.java:19)

    en muchos sitios dicen que es por la versión de jaspery la de Dynamic, que no son compatibles, en otras no se que del pom.xml…
    Estas son mis versiones:
    Jasper 4.5
    DynamicJasper 3.2.2

    Ayuda por favor.

    Un saludo

  4. Ya lo solucioné. El problema era que tenía la versión 4.5.1 de Jasper, cuando DynamicReport 3.2.2 es solo compatible con la 3.7.1

    Saludos

  5. Hola, me gustaría saber si se puede añadir texto en el detalle, como si fuera texto normal.

    Y si es posible usar viñetas como las de Office word, los puntitos «·».

    Gracias

    Sigo diciendo que es muy útil este tutorial.

  6. Saludos, muy buena explicacion, pero en mi caso estoy haciendo el reporte de un tableview de javafx en donde el ususario puede escoger las columnas que desee mostrar, todos los ejemplos que he visto ya vienen predefinisdas las colummnas en base una entidad o algo asi, alquien me puede dar alguna idea de como puedo hacer mi reporte, saludos

  7. Necesito llenar una tabla donde sus columnas difieren de tamaño y ubicacion segun la pagina. es decir yo tengo el valor para la columna, si es muy largo tengo q cortarlo y seguir en la hoja 2, pero la ubicacion de la columna es distinta a la hoja por lo q no puedo usar «stretch with overflow». Sabes como podria solucionarlo? Muchas gracias.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad