Trabajamos no solo para producir, sino para dar valor al tiempo.
Eugène Delacroix

iReport sobre Struts – Paso 3 : Generar el informe desde Java

Ahora tenemos la plantilla (.jrxml) y la plantilla compilada (.jasper). La plantilla la podemos compilar también en tiempo de ejecución pero no es lo habitual.

Para entender mejor cómo funciona Jasper Reports puedes consultar la siguiente imagen (sacada de aquí):

 

Nosotros utilizaremos JasperRunManager.runReportToPdf para generar el informe en PDF desde el jasper que hemos generado. Colocamos el informe .jasper en nuestro directorio (yo lo he creado en un paquete llamado "informes"). Creamos una clase que nos genere el pdf es.lycka.holamundoStruts138Jasper.utilidades.GenerarPDF :

package es.lycka.holamundoStruts138Jasper.utilidades;

import java.util.HashMap;

import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.util.JRLoader;
import es.lycka.holamundoStruts138Jasper.model.Informe;

public class GenerarPDF {

    public byte[] generarInforme (Informe informe) {
        byte[] pdf = null;
        String rutaInforme = "/es/lycka/holamundoStruts138Jasper/informes/informe.jasper";
        HashMap<String, Informe> parametros = new HashMap<String, Informe> ();
        parametros.put("informe", informe);

        try {
            JasperReport masterReport = (JasperReport) JRLoader.loadObject(getClass().getResource(rutaInforme));
            pdf = JasperRunManager.runReportToPdf(masterReport, parametros, new JREmptyDataSource());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return pdf;
    }
}

Ahora modificamos el InformeBO para invocar este método :

    public byte[] generarInforme (Informe informe) throws Exception {
        return (new GenerarPDF ()).generarInforme(informe);
    }

Ahora tenermos que hacer que nuestro action nos devuelva el pdf en la response. Para ello hacemos que el método execute nos devuelva null, y ahora implementamos el método que dejamos vacío, mostrarFichero

    private void mostrarPDF (byte[] informePDF, HttpServletResponse response) throws IOException {
        //Incializamos el array
        ByteArrayOutputStream bos    = new ByteArrayOutputStream();
        ServletOutputStream out        = response.getOutputStream();

        bos.write(informePDF);

        response.setContentType("application/pdf");
        //para que el pdf se pueda ver en microsoft explorer
        response.setHeader("Cache-Control", "cache");
        //para que aparezca el diálogo abrir/guardar
        response.setHeader("Content-Disposition", "attachment; filename=informe.pdf");
        response.setHeader("Pragma", "cache");
       
        response.setContentLength(bos.size());
        out.write(bos.toByteArray());
        out.flush();
        bos.close();
        out.close();
        response.flushBuffer();           
    }

Vale, haz la prueba y ya está. He subido el war de este proyecto a hordit, ahí puedes ver la estructura de los ficheros y las fuentes.

Joer ha costado ! Muchas gracias al Espín y a Chema que se curraron todo esto.

También te puede interesar:

  • [Java] – Redigir la salida desde Java Antes del maravailloso invento del Log4J, teníamos los problemas de almacenar las trazas generadas desde un programa Java. Para ello podíamos utilizar al Sistema Operativo...
  • [Struts] – no Cache Si queremos que ninguna página de nuestra aplicación basada en Struts almacene los datos introducidos por el usuario en ellas (lo que se entiende por...
  • Nueva sintaxis bucle for desde Java 5 En la versión 5 de Java se ha incluido una nueva sintaxis para el bucle for con la intención de hacer más legible el código....
  • Implementación con Struts : Cambio de Contraseña Planteamiento Necesitamos implementar en una aplicación web basada en Struts un cambio de contraseña de los usuarios de la aplicación. El usuario al olvidar su...
  • [Struts] – ActionDispatcher Struts permite manejar eventos HTML, mediante la clase ActionDispatcher, LookupDispachAciton y MappingDispatchAction que encontramos en el paquete org.apache.struts.actions. En la clase Action declaramos un ActionDipatcher...

23 Comentarios hasta el momento »

  1. Pepo dijo

    9 de February del 2009 a las 8:16 am

    gracias a ti Rey!!! Como te va todo?

  2. Martín dijo

    9 de February del 2009 a las 1:55 pm

    Yo digo NO a empezar el lunes con struts y digo SÍ a irnos a comer. ^^

  3. Chema dijo

    9 de February del 2009 a las 4:10 pm

    ¿que tal el jamón pájaro? Yo se de uno que dijo que iba a hacer una paella en su casa. ¿que tal todo?

  4. yoyoooyoy dijo

    9 de February del 2009 a las 8:04 pm

    Puf, ha sido duro saltarme el post demagogo este domingo y empezar el lunes con jasper, pero tenía que quitármelo de encia ya ! Mañana será más suave, una cancioncita.

    El jamón os está esperando, junto con esa paella prometida para este sábado. Ahora lanzaré la correspondiente convocatoria vía mail (menos a Martín por supuesto, a ese le damos una dirección falsa).

    De momento todo va bien, alterno mi casa con plaza castilla para currar, cuando llegue la hora de emigrar para alcobendas ya veremos a ver q pasa con el coche. Pero ya os contaré el viernes en el yonkis o el sábado en mi casita.

    Y vosotros ? Ya veo que la Toñi ni me da las gracias por el regalito; Ana ha pasado del post que le dediqué del toad; me imagino al enjuto sentado en mi silla como si estuviera en la tierra prometida; al de fuénla repartiendo ostias con ondas expansivas, al martín comiendo, espin pensando en la siguiente birra, al chema volviendo de la siesta con ese vaso de agua recién fregada, ya veo q edgar sigue en su línea de superproducciones, la pobrecita isaura aguantando las tranchadas, diego visto y no visto, los del cau cagándose en …, los formeros con las vistas… qué paisaje ! Ya me contaréis !

    PD, pepo, Rey, tu comentario ha quedado de un gay tono rosa pálido chillón de la muerte :P

  5. Pepo dijo

    10 de February del 2009 a las 8:20 am

    Pero es un comentario de camaradería, chupitos de tequila y sensibilidad femenina, que falta hace.

    un abrazo

  6. Pitu dijo

    21 de April del 2009 a las 6:48 pm

    Hola a todos, gracias por el artículo, pero veo que es bastante viejo. No sé si alguien podrá contestarme…

    No consigo avanzar del paso 2. Añado el directorio donde estan las clases al classpath, pero al buscarla en PARAMETERS no me sale…

    POr otro lado, el enlace donde pone para descargar las fuentes del tutorial, no me funciona.

    Muchas gracias!!

  7. Pitu dijo

    21 de April del 2009 a las 6:53 pm

    Veo que no he dado mucha información xD En el classpath sólo me deja añadir JARs o CARPETAS. Com no sé si se han de poner las fuentes o las compiladas, he probado con las dos, pero nada de nada…

    Una vez añadido el classpath, en teoria cuando voy a Parameters, en “Parameter Class Type” debería salirme todas las clases existentes en el directorio que he puesto en el classpath, no? y despues en la expresion invocar al método getXXX(), no?

    Muchas gracias!

  8. yoyoooyoy dijo

    23 de April del 2009 a las 8:02 am

    Hola Pitu, he estado enfermo ayer, pero esta tarde le echo un ojo a tu duda y a las demás dudas.

    Lo malo de iReport es la escasa documentación que hay por ahí.

  9. Pitu dijo

    23 de April del 2009 a las 11:25 am

    Hola yoyoooyoy, muchas gracias! lo he planteado de otra manera que me sirve. Aunque no queda muy bonito, ataco a la bbdd desde el propio report… de momento me sirve. El problema es que estoy en struts y quiero que cuando pulsen un botón, me genere el PDF y me salga directamente para descargarlo desde el action en el java. He estado mirando muchas cosas y hasta ahora he conseguido que me lo genere fisicamente en una carpeta, pero no que me salga el descargar o me lo abra directamente.

    Usando este código me genera bien el PDF:
    –>
    try{
    //1. Se compila el reporte
    JasperCompileManager.compileReportToFile(“C:/report.jrxml”);

    //2. Se llena el reporte con la informacion necesaria
    Map pars = new HashMap();
    pars.put(“empresa”, “prueba”);

    JasperPrint jasperPrint = JasperFillManager.fillReport( “C:/report.jasper”, pars, new JREmptyDataSource());

    //3. Se exporta a PDF
    JasperExportManager.exportReportToPdfFile(jasperPr int, “C:/plantilla.pdf”);

    System.out.println(“Done!”);
    }
    catch (JRException e)
    {
    e.printStackTrace();
    }

    try{
    //1. Se compila el reporte
    JasperReport jasperReport = (JasperReport)JRLoader.loadObject (getClass().getResource(“/xxx/yyyreport.jasper”));

    //2. Se llena el reporte con la informacion necesaria
    Map pars = new HashMap();
    pars.put(“empresa”, “prueba”);

    byte[] fichero = JasperRunManager.runReportToPdf (jasperReport, pars, new JREmptyDataSource());
    response.setContentType(“application/pdf”);
    response.setContentLength (fichero.length);
    ServletOutputStream ouputStream = response.getOutputStream();
    ouputStream.write(fichero, 0, fichero.length);
    ouputStream.flush();
    ouputStream.close();

    System.out.println(“Done!”);
    }
    catch (JRException e)
    {
    e.printStackTrace();
    }

    javax.servlet.ServletException: cannot assign instance of
    net.sf.jasperreports.engine.base.JRBaseStaticText to field net.sf.jasperreports.engine.base.JRBaseLineBox.box Container of type net.sf.jasperreports.engine.JRBoxContainer in instance of net.sf.jasperreports.engine.base.JRBaseLineBox
    <–

    Seguiré mirandomelo, muchas gracias!

  10. Pitu dijo

    23 de April del 2009 a las 11:28 am

    Buah, me ha posteado mal lo que he puesto. Lo repito,disculpar.

    Hola yoyoooyoy, muchas gracias! lo he planteado de otra manera que me sirve. Aunque no queda muy bonito, ataco a la bbdd desde el propio report… de momento me sirve. El problema es que estoy en struts y quiero que cuando pulsen un botón, me genere el PDF y me salga directamente para descargarlo desde el action en el java. He estado mirando muchas cosas y hasta ahora he conseguido que me lo genere fisicamente en una carpeta, pero no que me salga el descargar o me lo abra directamente.

    Usando este código me genera bien el PDF:
    try{
    //1. Se compila el reporte
    JasperCompileManager.compileReportToFile(”C:/report.jrxml”);

    //2. Se llena el reporte con la informacion necesaria
    Map pars = new HashMap();
    pars.put(”empresa”, “prueba”);

    JasperPrint jasperPrint = JasperFillManager.fillReport( “C:/report.jasper”, pars, new JREmptyDataSource());

    //3. Se exporta a PDF
    JasperExportManager.exportReportToPdfFile(jasperPr int, “C:/plantilla.pdf”);

    System.out.println(”Done!”);
    }
    catch (JRException e)
    {
    e.printStackTrace();
    }

    Pero claro, esto no es lo que necesito. Quiero que cuando se pulse un botón desde la web, me salga el PDF para descargar. Y, la ruta al PDF depende del hosting (no C:/). Ahora lo hago así:

    try{
    //1. Se compila el reporte
    JasperReport jasperReport = (JasperReport)JRLoader.loadObject (getClass().getResource(”/xxx/yyyreport.jasper”));

    //2. Se llena el reporte con la informacion necesaria
    Map pars = new HashMap();
    pars.put(”empresa”, “prueba”);

    byte[] fichero = JasperRunManager.runReportToPdf (jasperReport, pars, new JREmptyDataSource());
    response.setContentType(”application/pdf”);
    response.setContentLength (fichero.length);
    ServletOutputStream ouputStream = response.getOutputStream();
    ouputStream.write(fichero, 0, fichero.length);
    ouputStream.flush();
    ouputStream.close();

    System.out.println(”Done!”);
    }
    catch (JRException e)
    {
    e.printStackTrace();
    }

    Pero, este último código me genera este error:

    javax.servlet.ServletException: cannot assign instance of
    net.sf.jasperreports.engine.base.JRBaseStaticText to field net.sf.jasperreports.engine.base.JRBaseLineBox.box Container of type net.sf.jasperreports.engine.JRBoxContainer in instance of net.sf.jasperreports.engine.base.JRBaseLineBox

    Seguiré mirandomelo, muchas gracias!

  11. Pitu dijo

    23 de April del 2009 a las 5:47 pm

    Hola yoyoooyoy, he avanzo bastante, ahora ya me genera el PDF y me lo abre y todo!! El problema es que tengo que ponerle la ruta estática… xq esto es lo que me provoca el error comentado:
    JasperReport subReport = subReport = (JasperReport) JRLoader.loadObject(getClass().getResource(
    “/com/informe/subreport.jasper”));

    y, para mañana, me sirve con estáticas ya que tengo que presentar una demo en mi máquina, pero para más adelante cuando tenga que instalarlo en su servidor no me servirá. Pero bueno, tiempo al tiempo. Ahora lo que me preocupa es mañana y con lo que tengo me sirve.

    Pongo el código de lo que tengo actualmente por si a alguien le sirve:
    try {
    //1. Se compila el reporte
    String urlMaestro = “C:/report.jrxml”;
    String urlSubreporte = “C:/subreport.jrxml”;
    JasperCompileManager.compileReportToFile(urlMaestro);
    JasperCompileManager.compileReportToFile(urlSubreporte);

    JasperReport jasperReport = null;
    try {
    jasperReport = (JasperReport)JRLoader.loadObject (“C:/report.jasper”);
    } catch (JRException e) {
    System.out.println(“*****>> Error cargando el reporte maestro: ” + e.getMessage());
    }

    //2. Se llena el reporte con la informacion necesaria
    HttpSession session = request.getSession();
    Map pars = new HashMap();
    pars.put(“id”, (Integer)session.getAttribute(“id”));

    byte[] fichero = JasperRunManager.runReportToPdf (jasperReport, pars, con);
    response.setContentType(“application/pdf”);
    response.setContentLength (fichero.length);
    ServletOutputStream ouputStream = response.getOutputStream();
    ouputStream.write(fichero, 0, fichero.length);
    ouputStream.flush();
    ouputStream.close();
    }
    catch (JRException e)
    {
    e.printStackTrace();
    }

    Lo que no me sirve es el PDF que genera. Pero es tema del iReport. En el PDF hay una parte que sólo debe salir una vez y me sale en todas las páginas. Es decir, tengo una parte con unos cálculos generales que sólo deberían salir una única vez, luego otra (subreport) que me devuelve muchos resultados y es lo que me provoca el salto de página. Pero lo que digo, me replica la parte de cálculos en todas las páginas y no quiero eso…

    Ahora provaré hacer la parte de los cálculos con un subreporte a ver si así sólo me lo muestra una vez. Si se te ocurre algo o sabes como hacer esto avisame xfa. Iré mirando este post constantemente.

    Muchas gracias por todo!

  12. Pitu dijo

    23 de April del 2009 a las 6:14 pm

    jaja, veo que este post es mío!!! jaja, pues ya he conseguido que no me replique los cálculos en todas las páginas!! Era tan fácil como meterlo en otro subreporte y, este nuevo subreporte, junto con el otro, ponerlos en el detail del ireport. Ahora ya sólo me pone los cálculos en una sóla página!! come onnnnnnnnn!!

    Merci!

  13. yoyoooyoy dijo

    24 de April del 2009 a las 9:19 am

    Me alegra haber sido de ayuda XD XD XD Dale caña!

  14. Edward dijo

    25 de June del 2009 a las 4:41 am

    hola q tal, no he podido ver el war, para tomarlo como ejmplo, gracias

  15. defe dijo

    5 de July del 2009 a las 3:37 am

    Hola a todos!!!

    Tengo un problema para levantar el reporte en una aplicacion web
    El codigo es el siguiente
    Connection conexion;
    Class.forName(“com.mysql.jdbc.Driver”).newInstance();
    conexion = DriverManager.getConnection(“jdbc:mysql://localhost/carnes?createDatabaseIfNotExist=true&amp;useUnicode=true&amp;characterEncoding=utf-8″,”root”,”adminadmin”);

    File reportFile = new File(application.getRealPath(“clientes.jasper”));

    Map parameters = new HashMap();

    1. byte[] bytes = JasperRunManager.runReportToPdf(reportFile.getPath(), parameters,conexion);

    response.setContentType(“application/pdf”);
    response.setContentLength(bytes.length);
    ServletOutputStream ouputStream = response.getOutputStream();
    ouputStream.write(bytes, 0, bytes.length);

    ouputStream.flush();
    ouputStream.close();

    en la linea que tiene un “1″ me tira NullPointerException…ahora bien cuando le saco el “conexion” y le pongo “new JREmptyDataSource()” no me tira ningùn error pero el reporte me lo pinta en blanco…..

    alguna idea……

    saludos la entrada esta muy buena

  16. yoyoooyoy dijo

    7 de July del 2009 a las 7:22 am

    Hola Federico,

    tú mismo me estás diciendo cuál es el error : el objeto conexion que le pasas es un null (verifícalo si quieres depurando el programa) porque no encuentra la bbdd cuando inicializa la conexión :) ( conexion = DriverManager.getConnection(”jdbc:mysql://localhost/carnes?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf-8″,”root”,”adminadmin”); )

    Saludos

  17. Fernando dijo

    11 de August del 2009 a las 8:58 pm

    Saludos, Necesito ayuda, cuando llamo el procedimiento, efectivamente me sale para descargarlo, pero cuando lo abro, me dice: “El archivo miArchivo.pdf esta dañado, esto sucede cuando se cargan mal via email por ejemplo”

    cuando veo el Log de lo que paso me sale el siguiente error:

    “java.net.ProtocolException: Didn’t meet stated Content-Length, wrote: ’0′ bytes instead of stated: ’2070′ bytes”

    El Error completo es:

    ” <Servlet execution in servlet context “weblogic.servlet.internal.WebAppServletContext@16df6f5 – appName: ‘PruebaReporte’, name: ‘PruebaReporte-Project1-context-root’, context-path: ‘/PruebaReporte-Project1-context-root’, spec-version: ’2.5′” failed, java.net.ProtocolException: Didn’t meet stated Content-Length, wrote: ’0′ bytes instead of stated: ’2070′ bytes..
    java.net.ProtocolException: Didn’t meet stated Content-Length, wrote: ’0′ bytes instead of stated: ’2070′ bytes.
    at weblogic.servlet.internal.ServletOutputStreamImpl.ensureContentLength(ServletOutputStreamImpl.java:414)
    at weblogic.servlet.internal.ServletResponseImpl.ensureContentLength(ServletResponseImpl.java:1416)
    at weblogic.servlet.internal.ServletResponseImpl.send(ServletResponseImpl.java:1459)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1415)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    Truncated. see log file for complete stacktrace

    De verdad que he probado con muchos codigos, pero no logro hacer que funcione bien x__x

  18. juan carlos dijo

    20 de January del 2010 a las 10:21 am

    Hola amigos, ¿qué tal?

    antes de nada advertiros que soy nuevo en esto de jasperreports + iReport. Utilizo las versiones jasperreports 3.7 y iRepor 3.7 en un proyecto desarrollado en eclipse. Ocurre que en este proyecto tenía instalada previamente la librería jasperreports 2.0 y cuando genero el pdf me salta la excepción del tipo:

    “cannot assign instance of net.sf.jasperreports.engine.base.JRBaseTextField to field net.sf.jasperreports.engine.base.JRBaseLineBox”

    Creo que estoy modificando mal el path: elimino jarperreports2_0.jar y añado jarperreports3_7.jar en las librerias referenciadas del proyecto, compilo y ejecuto pero me salta el error indicado arriba. ¿Donde puedo mirar las versiones que se están utilizando realmente? ¿Cómo modifico el path en caso de que estas versiones no coincidan?

    Muchas gracias de antemano.
    Un saludo!

  19. Cecilia dijo

    21 de January del 2010 a las 3:06 pm

    Tengo el mismo problema que Juan Carlos, un proyecto desarrollado con Eclipse, y ayer empecé a usar el iReport 3.7.0, anteriormente usaba el iReport 2.0.1. Cambié las librerías jasperreports y sigue saliendo el mensaje

    cannot assign instance of net.sf.jasperreports.engine.base.JRBaseTextField to field net.sf.jasperreports.engine.base.JRBaseLineBox.boxContainer of type net.sf.jasperreports.engine.JRBoxContainer in instance of net.sf.jasperreports.engine.base.JRBaseLineBox

    ¿Cuál puede ser el problema?
    Gracias. Saludos.

  20. Cecilia dijo

    22 de January del 2010 a las 3:19 pm

    Al fin conseguí hacerlo andar, el la carpeta lib del proyecto eliminé la librería jasperreports anterior y dejé sólo la nueva, y en la carpeta lib del common hice lo mismo. Pero en el classpath del proyecto referencié sólo la carpeta lib del proyecto, espero se entienda, por lo menos solucionó el problema.

  21. Jorge dijo

    8 de March del 2010 a las 1:23 am

    Hola que tal.

    Tengo un reporte con la siguiente estructura para presentar los resultados.

    Reporte – Subreporte
    ——————————–
    – Elemento 1.1
    Elemento 1 – Elemento 1.2
    – Elemento 1.3
    ——————————–
    – Elemento 2.1
    Elemento 2 – Elemento 2.2

    ——————————–

    Pero tengo problemas con la alineación pues el subreporte en algunas ocaciones tiene menor altura que el elemento del reporte principal, he intentado utilizar el stretch type pero aún sin solución.

    Alguien tiene alguna idea de como hacer para que el subreporte siempre tenga la misma altura que el elemento del reporte??

    Gracias.

  22. Edwar dijo

    24 de December del 2011 a las 4:38 am

    holas amigos tengo un grave problema nu me genera el reporte struts con ireport en netbeans … no solo eso sino q al ejecutar el programa no se carga por completo la pagina del index.jsp

    salen errores como

    Grave: Servlet.service() for servlet [jsp] in context with path [/proyecto] threw exception [java.lang.NullPointerException: Module 'null' not found.] with root cause
    java.lang.NullPointerException: Module ‘null’ not found.

    Grave: Unable to initialize Struts ActionServlet due to an unexpected exception or error thrown, so marking the servlet as unavailable. Most likely, this is due to an incorrect or missing library dependency.
    java.lang.NoSuchMethodError: org.apache.commons.digester.Digester.parse(Ljava/net/URL;)Ljava/lang/Object;

  23. yoyoooyoy dijo

    25 de December del 2011 a las 7:26 pm

    Buenas Edwar,

    parece que tienes un problema de configuración de Struts, revisa el fichero de configuración de Struts.

    Suerte

Comentarios RSS · TrackBack URI

Dejanos tu Comentario

Nombre: (Requerido)

E-Mail: (Requerido)

Sitio WEB:

Comentario:

Comenta