jueves, 2 de abril de 2009

Creación de Reportes con JasperRepots y iReports - Parte 4: Reportes en Aplicaciones Web

Esta es la cuarta entrega de esta serie de tutoriales sobre JasperReports. En la primer parte, vimos cómo generar reportes haciendo uso de una conexión a base de datos como nuestro DataSource. Después, en la segunda parte, aprendimos a hacer esto mismo pero con un DataSource propio, lo que nos evita en tener las consultas SQL directamente en nuestro reporte y tener que pasarle posteriormente un objeto de tipo “java.sql.Connection”. Finalmente, en la tercer parte, vimos cómo hacer uso de parametros y variables para hacer nuestros reportes más dinámicos.

Ahora, en esta cuarta parte, veremos cómo hacer que un usuario pueda descargar o ver en su navegador estos reportes haciendo uso de Servlets y JSPs respectivamente.

Para este tutorial usaremos el reporte que creamos en el tutorial anterior. Así que si no lo tienen pueden ver cómo crearlo en la segunda parte del tutorial de JasperReports.

Usaremos solo el archivo "reporte2.jasper" y el código que ya habíamos creado lo pasaremos a un Servlet un poco más adelante.

Para comenzar con este tutorial lo primero que debemos hacer es abrir nuestro IDE de trabajo. Los que han seguido este blog saben que el IDE que más me gusta para trabajar con Java es el NetBeans. Así que será el que usaremos en este tutorial (y para todos los demás ^_^).

Al final del tutorial de instalación de plugins en NetBeans vimos cómo configurar Tomcat para usarlo como contenedor de Servlets y JSPs; y servidor web. Usaremos el Tomcat para este proyecto, así que si no lo tienen instalado o configurado sigan los pasos indicados en este tutorial.

Ahora creamos un nuevo proyecto web yendo al menú “File -> New Project”. En la ventana que se abre seleccionamos la categoría "Java Web" y seleccionamos "Web Application".



Hacemos clic en el botón "Next". En el siguiente paso le damos un nombre (que en mi caso será "ReporteWeb") y una ubicación al proyecto. Hacemos clic en el botón "Next". Para terminar seleccionamos el servidor que vamos a usar. En este caso, y como dije antes, usaremos el Tomcat 6, por lo que lo seleccionamos y hacemos clic en el botón "Finish". Con esto debe aparecer nuestro proyecto en la ventana "Projects", y un archivo llamado "index.jsp" en la ventana del editor.



Ahora agregamos la biblioteca de “JasperReports” que creamos en el primer tutorial de la serie, como lo hemos venido haciendo ("Add Library" en el nodo "Library" del panel "Projects").

Además también debemos copiar el archivo "reporte2.jasper" al directorio "web/WEB-INF" debajo de la raíz del proyecto. Esto es muuuuy importante porque este archivo debe poder ser encontrado por los componentes web (Servlets) de nuestra aplicación, y lo mejor es colocarlos en esta ubicación para poder obtener la ruta absoluta de dónde está, usando los métodos que nos proporcionan los Servlets. Lo colocamos dentro de “WEB-INF” para que nuestro servidor no lo envíe al usuario como lo hace, por ejemplo, con las páginas web o con las imágenes.

En el tutorial anterior usamos una clase "Participante", y eran los valores de los atributos de las instancias de esta clase los que se mostraban en el reporte. Como estamos usando la misma plantilla de reporte (“reporte2.jasper”), también usaremos la misma clase para almacenar los datos que se mostrarán. Por lo que creamos una nueva clase "Participante" (colocándola en el paquete "pruebas.reportes.jasperreports.web") y copiamos el código que ya teníamos al nuevo archivo. Para que no se regresen al tutorial anterior a ver el código, lo dejo aquí:


public class Participante
{ 
    private int id; 
    private String nombre; 
    private String username; 
    private String password; 
    private String comentarios; 
    private int puntos;  

    public Participante() 
    { 
    }  

    public Participante(int id, String nombre, String username, String password, String comentarios) 
    { 
        this.id = id; 
        this.nombre = nombre; 
        this.username = username; 
        this.password = password; 
        this.comentarios = comentarios; 
    }  

    public String getComentarios() 
    { 
        return comentarios; 
    }  

    public void setComentarios(String comentarios) 
    { 
        this.comentarios = comentarios; 
    }  

    public int getId() 
    { 
        return id; 
    }  
    
    public void setId(int id) 
    { 
        this.id = id; 
    }  

    public String getNombre() 
    { 
        return nombre; 
    }  

    public void setNombre(String nombre) 
    { 
        this.nombre = nombre; 
    }  

    public String getPassword() 
    { 
        return password; 
    }  

    public void setPassword(String password) 
    { 
        this.password = password; 
    }  

    public String getUsername() 
    { 
        return username; 
    }  

    public void setUsername(String username) 
    { 
        this.username = username; 
    }  

    public int getPuntos() 
    { 
        return puntos; 
    }  

    public void setPuntos(int puntos) 
    { 
        this.puntos = puntos; 
    } 
} 


Ahora crearemos un nuevo Servlets, que será el componente desde el que generaremos el reporte. Para eso hacemos clic derecho sobre el nodo "Source Package" del panel "Projects" y en el menú contextual que se abre seleccionamos "New -> Other...". En la ventana que se abre seleccionamos la categoría “web” y como tipo de archivo “Servlet”:



Escribimos "ServletReporte" como nombre del Servlet y lo colocamos en el paquete "pruebas.reportes.jasperreports.web":



Hacemos clic en el botón "Finish" y tendremos nuestro nuevo Servlet en la ventana del editor. Este Servlet contendrá tres métodos generados desde las plantilla de Servlets:

  • doGet (para atender la peticiones HTTP GET)
  • doPost (para atender las peticiones HTTP POST)
  • processRequest que es llamado por los dos métodos anteriores

La funcionalidad para generar el reporte la colocaremos en este último método, así que lo primero que haremos es borrar el código que ya contiene, dejándolo vacio, principalmente porque el método utiliza un “java.io.PrintWriter”, que es un objeto para generar respuestas en texto, y nosotros usaremos un “javax.servlet.ServletOutputStream”, que es un objeto para generar respuestas binarias, que en este caso será el reporte:


public class ServletReporte extends HttpServlet 
{   
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    {

    } 

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    {
        processRequest(request, response);
    } 

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    {
        processRequest(request, response);
    }

    @Override
    public String getServletInfo() 
    {
        return "Short description";
    }
}


Como el reporte que regresaremos estará en formato PDF, y este es un formato binario, (todo lo que no pueda abrirse con un bloc de notas, o cualquier editor de texto plano, y entenderse directamente es un archivo binario) la única forma que existe para regresarlo de forma correcta al cliente es haciendo uso de un Stream, en este caso de un “ServletOutputStream”. Es también por esta razón que debemos hacer uso de un Servlet y no de una JSP, ya que la llamada al método que regresa el “ServletOutputStream” solo es permitida dentro de un Servlet.

Lo primero que haremos dentro de nuestro Servlet es indicar el tipo de contenido que regresaremos (que por default es "text/html"). Como se trata de un archivo PDF el tipo de retorno es "application/pdf". Indicamos esto con el método "setContentType" del objeto "HttpServletResponse" que recibimos como segundo argumento, de la siguiente forma:


response.setContentType("application/pdf");


Este método se encarga de establecer las cabeceras adecuadas en la respuesta regresada al cliente para que este sepa cómo tratar los datos que está recibiendo. En este caso esperamos que abra el reporte con su aplicación habitual para leer archivos PDF (Acrobat Reader o algún otro). Es importante establecer este valor antes de obtener el “ServletOutputStream”, de lo contrario podríamos obtener algún error inesperado al enviar la respuesta.

Ahora que el Servlet ya conoce el tipo de respuesta que regresará podemos proceder a obtener el “ServletOutputStream” correspondiente para enviar la respuesta al cliente:


ServletOutputStream out = response.getOutputStream();


Ahora generamos el reporte como lo hemos estado haciendo hasta ahora, haciendo unos pequeños cambios: como ahora el archivo de la plantilla del reporte no se encuentra en la raíz del proyecto, sino dentro del directorio web, debemos indicar la ruta completa en la que se encuentra este archivo. Por lo que es necesario cambiar la línea


JasperReport reporte = (JasperReport) JRLoader.loadObject("reporte2.jasper");


Por:


JasperReport reporte = (JasperReport) JRLoader.loadObject(getServletContext().getRealPath("WEB-INF/reporte2.jasper"));        


Además, como ahora el reporte no será generado en un archivo, sino que será enviado directamente al cliente, debemos cambiar la línea:


exporter.setParameter(JRExporterParameter.OUTPUT_FILE, new java.io.File("reporte2PDF_2.pdf")); 


Por:


exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);


En realidad la línea anterior es la que hace el truco. El flujo del reporte es dirigido al flujo que es regresado al cliente, logrando así que este vea el reporte directamente en su navegador.

El resto del código de “processRequest” es igual al que ya hemos visto en los tutoriales anteriores, y queda de la siguiente forma:


protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
   response.setContentType("application/pdf");

   ServletOutputStream out = response.getOutputStream();

   List listaPariticipantes = new ArrayList();

   for (int i = 1; i <= 10; i++)
   {
      Participante p = new Participante(i, "Particpante " + i, "Usuario " + i, "Pass " + i, "Comentarios para " + i);
      p.setPuntos(i);
      listaPariticipantes.add(p);
   }

   try
   {
      JasperReport reporte = (JasperReport) JRLoader.loadObject(getServletContext().getRealPath("WEB-INF/reporte2.jasper"));

      Map parametros = new HashMap();
      parametros.put("autor", "Juan");
      parametros.put("titulo", "Reporte");

      JasperPrint jasperPrint = JasperFillManager.fillReport(reporte, parametros, new JRBeanCollectionDataSource(listaPariticipantes));

      JRExporter exporter = new JRPdfExporter();
      exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
      exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
      exporter.exportReport();
   }
   catch (Exception e)
   {
      e.printStackTrace();
   }
}


Si ahora ejecutamos el proyecto (den algún tiempo para que el Tomcat se levante, hasta que vean el mensaje "INFO: Server startup in ***** ms" en el panel del salida) e ingresamos a la siguiente dirección:


http://localhost:8080/ReporteWeb/ServletReporte


Veremos que el reporte generado se muestra directamente en la pantalla del navegador:



Aunque esto es muy útil tal y como esta, algunas veces es mejor que el usuario decida si quiere guardar este reporte en su máquina o abrirlo con alguna otra aplicación en vez de usar directamente el navegador. Para poder lograr esto es necesario agregar una cabera llamada "Content-Disposition" a la respuesta. Esta cabecera tiene como valor "attachment; filename=" y el nombre que queremos darle a nuestro reporte. Para establecer esta cabecera usamos el método "setHeader" del objeto "HttpServletResponse", de la siguiente forma:


response.setHeader("Content-Disposition","attachment; filename=\"reporte.pdf\";");


Ahora compilamos y ejecutamos nuevamente nuestra aplicación y veremos que en esta ocasión se nos pregunta qué acción queremos realizar: abrir el reporte con alguna aplicación que seleccionemos, o guardarlo en nuestra máquina (tal vez será necesario que detengan y vuelvan a reiniciar su servidor para que tome los cambios):



Para evitar que nuestro navegador guarde el archivo en cache podemos establecer, como se indica en esta página del sitio jGuru, las siguientes cabeceras:


response.setHeader("Cache-Control","no-cache"); 
response.setHeader("Pragma","no-cache");  
response.setDateHeader ("Expires", 0);


Aunque el darle al usuario la oportunidad de abrir o guardar el archivo es también bastante útil, algunas veces nos gustaría poder mostrar este archivo como parte de la información de nuestra página JSP embebiéndolo en la misma. Hacer esto es bastante sencillo, como se menciona en este artículo de flash colony. Solo hay que agregar la etiqueta <object>, con algunos atributos de configuración, en nuestra página JSP.

Si agregamos la siguiente etiqueta en nuestro archivo "index.jsp":


<object type="application/pdf" data="http://localhost:8080/ReporteWeb/ServletReporte" width="500" height="650"></object>


e ingresamos a la dirección:


http://localhost:8080/ReporteWeb/


Obtendremos el siguiente resultado:



Lo cual también puede sernos de mucha utilidad ^-^.

El código del método “processRequest” queda finalmente de la siguiente forma:


protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
    response.setHeader("Content-Disposition", "attachment; filename=\"reporte.pdf\";");
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("Pragma", "no-cache");
    response.setDateHeader("Expires", 0);

    response.setContentType("application/pdf");
        
    ServletOutputStream out = response.getOutputStream();

    List listaPariticipantes = new ArrayList();

    for (int i = 1; i <= 10; i++)
    {
        Participante p = new Participante(i, "Particpante " + i, "Usuario " + i, "Pass " + i, "Comentarios para " + i);
        p.setPuntos(i);
        listaPariticipantes.add(p);
    }

    try
    {
        JasperReport reporte = (JasperReport) JRLoader.loadObject(getServletContext().getRealPath("WEB-INF/reporte2.jasper"));

        Map parametros = new HashMap();
        parametros.put("autor", "Juan");
        parametros.put("titulo", "Reporte");

        JasperPrint jasperPrint = JasperFillManager.fillReport(reporte, parametros, new JRBeanCollectionDataSource(listaPariticipantes));

        JRExporter exporter = new JRPdfExporter();
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
        exporter.exportReport();
    }
    catch (Exception e)
        {
        e.printStackTrace();
    }
}


Y el código del archivo “index.jsp” queda así:


<%@page contentType="text/html" pageEncoding="UTF-8">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>    
    <body>   
        <h1>Este es el archivo</h1>

        <object type="application/pdf" data="http://localhost:8080/ReporteWeb/ServletReporte" width="500" height="650"></object>

    </body>
<html>


Bien, este es el final de este cuarto tutorial sobre el uso de JasperReports. Espero que les sea de utilidad. No olviden dejar sus dudas, comentarios y sugerencias.


Saludos.

Descarga los archivos de este tutorial desde aquí:

Entradas Relacionadas:

46 comentarios:

  1. hola he probrado, pero no me muestra nada mi servlet, q puede estar mal

    ResponderEliminar
  2. Hola. Eso me ocurrió en una ocasión al estar creando el tutorial y resulta que, aunque no me habia dado cuenta, se estaba lanzando una excepción de que el archivo .jasper especificado no se encontraba, ya que habia escrito mal el nombre. ¿Has revisado la salida de la consola para ver si no te ocurre algo parecido?.

    Saludos.

    ResponderEliminar
  3. Hola, el tutorial es muy bueno, pero no se si me podrías ayudar con el siguiente error:

    INFO: Marcando el servlet ServletReporte como no disponible
    27-abr-2009 9:26:34 org.apache.catalina.core.ApplicationContext log
    GRAVE: Error loading WebappClassLoader
    delegate: false
    repositories:
    /WEB-INF/classes/
    ----------> Parent Classloader:
    org.apache.catalina.loader.StandardClassLoader@1c282a1
    pruebas.jasperreports.web.ServletReporte
    java.lang.ClassNotFoundException: pruebas.jasperreports.web.ServletReporte
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1386)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1232)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1068)
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:791)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:127)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:875)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
    at java.lang.Thread.run(Unknown Source)
    27-abr-2009 9:26:34 org.apache.catalina.core.StandardWrapperValve invoke
    GRAVE: Excepción de reserva de espacio para servlet ServletReporte
    java.lang.ClassNotFoundException: pruebas.jasperreports.web.ServletReporte
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1386)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1232)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1068)
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:791)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:127)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:875)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
    at java.lang.Thread.run(Unknown Source)

    ResponderEliminar
  4. Hola programador Java:

    Oye no se que pasa le pongo al servlet:

    response.setHeader("Content-Disposition","inline; filename=reporte.pdf");
    response.setContentType("application/pdf");

    y no me general la ventanita para que el usuario decida si quiere abrir el archivo pdf o guardarlo, me abre directamnte el reporte en el explorador que puede ser???

    ResponderEliminar
  5. Hola;

    Puede ser por dos razones, la primera es que estas poniendo

    "Content-Disposition","inline; filename=reporte.pdf"

    cambialo por

    "Content-Disposition","attachment; filename=reporte.pdf";"

    (cambia el inline por attachment)

    La otra razón puede ser que tu navegador guardó en caché la página que se obtiene de la dirección de donde obtienes el reporte. Prueba borrando el caché de tu navegador. Para eso son estas líneas:

    response.setHeader("Cache-Control","no-cache");
    response.setHeader("Pragma","no-cache");
    response.setDateHeader ("Expires", 0);

    para que no tengas que borrarlo manualmente cada vez y te asegures de que siempre consulta el sitio en vez de su caché (aunque si ya lo ha guardado deberás borrarlo manualmente).

    Prueba con las dos soluciones y avisame que pasa, sino buscamos qué otra cosa puede estar ocurriendo.

    Saludos.

    ResponderEliminar
  6. este es mi codigo:

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws IOException,ServletException
    {
    response.setHeader("Content-Disposition","attachment; filename=\"reporte.pdf\"");
    response.setContentType("application/pdf");

    Connection conexion = new Conexion().getConexion();
    ServletContext application = this.getServletContext();
    ServletOutputStream outputStream = response.getOutputStream();


    short claveDelegacion = ((Usuario)request.getSession().getAttribute("usuarioActual")).getCveDel();
    String periodo = (String)request.getSession().getAttribute("periodo");

    Map parametros = new HashMap();

    parametros.put("imagen",application.getRealPath("reporte//LogoPA2.gif"));
    parametros.put("periodo",periodo);

    File archivoReporte = new File(application.getRealPath("reporte//ReporteBienesCatalogados.jasper"));;

    if(request.getParameter("operacion").equals("reportebc")) {


    try {

    parametros.put("claveRequisicion",Integer.toString(new GestionBienesCatalogados().getClaveRequisicion(claveDelegacion,periodo)));
    parametros.put("delegacion",new ValidarUsuario().getDelegacion(claveDelegacion));
    }
    catch(SQLException e) {

    e.printStackTrace();
    }
    }
    System.out.println("se manda a llamr el servlet reporte");

    try {

    JasperReport reporte = (JasperReport)JRLoader.loadObject(archivoReporte.getPath());
    JasperPrint print = JasperFillManager.fillReport(reporte,parametros,conexion);

    JRExporter exporter = new JRPdfExporter();
    exporter.setParameter(JRExporterParameter.JASPER_PRINT,print);
    exporter.setParameter(JRExporterParameter.OUTPUT_STREAM,outputStream);
    exporter.exportReport();
    }
    catch(Exception e) {

    e.printStackTrace();
    }

    outputStream.flush();
    outputStream.close();
    }

    ResponderEliminar
  7. Prueba poner la línea

    response.setContentType

    antes de

    response.setHeader

    (qué sea la primer línea de tu método). Si no mal recuerdo las cabeceras se resetean cuando cambias el contentType

    ResponderEliminar
  8. Hola tengo un problema, quiero mostrar mi reporte en una aplicacion web conectandome a una base de datos, pero por alguna razon la pagina me carga sin el Pdf alguien mi podria ayudar. Este es mi codigo. Gracias

    public class NewServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException, JRException
    {
    response.setContentType("application/pdf");

    ServletOutputStream out = response.getOutputStream();

    try{

    Class.forName("org.postgresql.Driver");

    Connection conexion = DriverManager.getConnection("jdbc:postgresql://localhost:5432/PruebaReportes", "postgres", "postgres");

    JasperReport reporte2 = (JasperReport)
    JRLoader.loadObject(getServletContext().getRealPath("CertificadoPrueba2.jasper"));

    JasperPrint jasperPrint = JasperFillManager.fillReport(reporte2, null, conexion);
    JRExporter exporter = new JRPdfExporter();
    exporter.setParameter(JRExporterParameter.JASPER_PRINT,jasperPrint);
    exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
    exporter.exportReport();

    response.setHeader("Cache-Control","no-cache");
    response.setHeader("Pragma","no-cache");
    response.setDateHeader ("Expires", 0);

    }

    catch( Exception e ){

    }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    try {
    processRequest(request, response);
    } catch (JRException ex) {
    Logger.getLogger(NewServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    try {
    processRequest(request, response);
    } catch (JRException ex) {
    Logger.getLogger(NewServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
    }

    @Override
    public String getServletInfo() {
    return "Short description";
    }

    }

    ResponderEliminar
  9. Hola Lisbeth;

    En general veo bien tu código con excepción de las líneas

    response.setHeader("Cache-Control","no-cache");
    response.setHeader("Pragma","no-cache");
    response.setDateHeader ("Expires", 0);


    Las cuales me parecen deben de ir antes de que hagas

    ServletOutputStream out = response.getOutputStream();

    También podrías ver si estas obteniendo alguna excepción en la consola y ponerla?

    Saludos

    ResponderEliminar
  10. Hola,

    Necesito restringir que el usuario solo pueda imprimir una sola copia del reporte, ¿Como puedo hacer esto?

    saludos.

    ResponderEliminar
  11. Todo perfecto, solo añadir una cosa, por si a alguien más le pasa.

    Si incluimos imágenes y le ponemos una ruta relativa hay que añadir esta ruta como parámetro al principio de la clase Java de la siguiente manera, mi ruta donde tengo las imágenes es /web/Jasper/



    String reportsDirPath = getServletContext().getRealPath("/Jasper/");
    File reportsDir = new File(reportsDirPath);
    if (!reportsDir.exists()) {
    throw new FileNotFoundException(String.valueOf(reportsDir));
    }

    parametros.put(JRParameter.REPORT_FILE_RESOLVER, new SimpleFileResolver(reportsDir));


    Con esto ya le indicamos a JasperReports donde se encuentran nuestros ficheros, yo tuve problemas ya que por defecto creo que los busca en el classpath, y en principio no me interesa incluir las imágenes en el mismo.

    Saludos y el tutorial es buenísimo, muchas gracias.

    ResponderEliminar
  12. Hola.. muy buen tutorial. quisiera saber como visualizar directamente el reporte en formato pdf, y no con el visor de jasperviewer.

    ResponderEliminar
  13. @Hector

    Hola jqui, esto también aplica para subretportes?

    Gracias!!!

    ResponderEliminar
  14. @lalucas_183

    Hola lalucas,

    Para esto debes ir a menú superior "Preview" y seleccionas "PDF preview".

    Y para especificar los programas que abriran los reportes según el formato vas a el menu "Herramientas" -> "Opciones" y en la pestania "Viewers" cargas los ejecutables de los programas para visualizar los reportes como excel, Foxit reader, acrobat reader, etc...

    ResponderEliminar
  15. Excelente material el que has creado, felicitaciones, es una gran base de conocimiento! muchas gracias.

    ResponderEliminar
  16. Felicitaciones por estos tutoriales tan bien estructurados.

    Gracias por compartirnos tus conocimientos.

    ResponderEliminar
  17. Hola Alex... necesito generar un reporte en una aplicacion web con struts y mostrarlo en en el navegador... sujerencias o ejemplos?? es un poco urgente.. Gracias de antemano

    ResponderEliminar
  18. @Marlon Rjs
    Hola Marlon;

    Struts 2 tie un plugin para trabajar direct con jasperreports, solo debes indicarle donde está tu archivo .jasper. Con Struts 1 el procedimiento es exactamente igual que el mostrado aqui, obtienes el response, el ServletOutputStream y envias por ahi el reporte generado.

    Saludos

    ResponderEliminar
  19. Hola Alex, tengo que hacer esto pero usando portlets de liferay, sabes como podría ser tengo que crear un servlet o puedo hacerlo en el action? =(
    Gracias

    ResponderEliminar
  20. por que se sale una excepcion en la el siguiente codigo:
    JasperReport reporte = (JasperReport) JRLoader.loadObject(getServletContext().getRealPath("WEB-INF/reporte2.jasper"));

    ResponderEliminar
  21. Por que me sale esta excepcion por favor ayuda:

    INFO: Use of the properties initialization parameter 'properties' has been deprecated by 'org.apache.velocity.properties'
    17-ene-2012 8:48:57 org.apache.catalina.core.StandardWrapperValve invoke
    GRAVE: Servlet.service() para servlet AdmAlmacen.Reporte lanzó excepción
    java.lang.ClassNotFoundException: net.sf.jasperreports.engine.JasperCompileManager
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1358)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1204)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)
    at AdmAlmacen.Reporte.Reporte_1(Reporte.java:50)
    at AdmAlmacen.Reporte.handleRequest(Reporte.java:61)
    at org.apache.velocity.servlet.VelocityServlet.doRequest(VelocityServlet.java:358)
    at org.apache.velocity.servlet.VelocityServlet.doGet(VelocityServlet.java:317)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Unknown Source)

    ResponderEliminar
  22. Muy buen tutorial, muchas gracias, me ha servido de mucho, lo pude adaptar perfectamente a mis consultas SQL y mi aplicacion Web con salidas a Pdf y Excel.... Saludos!!

    ResponderEliminar
    Respuestas
    1. Hola no se si me puedas ayudar ya que logro que el informe me salga en formato pdf, mas no en excel (aun intentando lo que se encuentra en internet), cualquier colaboracion te agradezco

      Eliminar
  23. Que buen material!... Muchas gracias por estos artículos!

    Necesito que me ayuden con algo, el reporte PDF no se genera dando este error por consola:

    java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
    at net.sf.jasperreports.engine.fill.JRIntegerSumIncrementer.increment(JRIntegerIncrementerFactory.java:299)
    at net.sf.jasperreports.engine.fill.JRAbstractExtendedIncrementer.increment(JRAbstractExtendedIncrementer.java:42)
    at net.sf.jasperreports.engine.fill.JRCalculator.estimateVariables(JRCalculator.java:182)
    at net.sf.jasperreports.engine.fill.JRFillDataset.next(JRFillDataset.java:889)
    at net.sf.jasperreports.engine.fill.JRFillDataset.next(JRFillDataset.java:864)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.next(JRBaseFiller.java:1435)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:126)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:836)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:765)
    at net.sf.jasperreports.engine.fill.JRFiller.fillReport(JRFiller.java:84)
    at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:624)
    at pruebas.reportes.jasperreports.web.ServletReporte.processRequest(ServletReporte.java:73)
    at pruebas.reportes.jasperreports.web.ServletReporte.doGet(ServletReporte.java:99)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

    ------------------------------------
    La línea 73 es:
    JasperPrint jasperPrint = JasperFillManager.fillReport(reporte, null, new JRBeanCollectionDataSource(listaParticipantes));

    Muchas gracias!

    ResponderEliminar
  24. Que gran tutorial, he seguido todas las indicaciones y me funciona todo correctamente. Muchísimas gracias por el post!!!!

    ResponderEliminar
  25. cómo puedo acceder al servlet desde una ruta relativa? ya que al llamarlo desde data="http://localhost:8080/ReporteWeb/ServletReporte", si la aplicación la monto en un servidor en red no me muestra el pdf final

    ResponderEliminar
    Respuestas
    1. Hola Sara;

      Cuando tu servidor está en red, que es lo normal una vez que lo pones en producción, en vez de usar "localhost", debes usar la IP del servidor, por ejemplo:

      data="http://192.168.0.10:8080/ReporteWeb/ServletReporte

      Usando, claro está, la IP de tu servidor.

      Saludos

      Eliminar
    2. Yo tuve un tema así, y en vez de marearte con direcciones puedes capturar la el pathcontext, el portlet es como un servlet más así que esto debería servir.
      http://www.exampledepot.com/egs/javax.servlet/GetReqUrl.html

      Eliminar
  26. Hola saludos, he seguido tus tutoriales y me han parecido excelentes, muchas gracias!!

    ResponderEliminar
  27. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  28. Estoy trabajando una aplicación web con tres capas, estoy colocando el servlet en la capa web pero al ejecutar lanza una exception de tipo:
    java.lang.NoClassDefFoundError: Could not initialize class net.sf.jasperreports.engine.util.JRLoader

    y se relaciona con la siguiente linea

    JasperReport reporte = (JasperReport)JRLoader.loadObject(getServletContext().getRealPath("WEB INF/ConsolidadosClientePedidos.jasper"));

    Sospecho que es un problema de ruta ya que la aplicacion se tiene que desplegar apartir de la capa web y el servlet solo es posible acceder a traves de la ruta del enterprise application

    Si alguien tiene el truco para acomodar el path del servlet le agradeceria

    ResponderEliminar
  29. Tengo una consulta, pero primero dejame felicitarte por tus excelentes tutoriales.

    Esty trabajando en un proyecto web con las tecnologias de JSF, PRIMEFACES E HIBERNATE...y queria saber si esta forma de generar reportes se puede adaptar a mi aplicacion o es necesario algunos cambios o que consejo me dan ??, ya que con primefaces las etiquetas cambian pero igual pudes hacer un action , algo asi: habria problemas al llamar a la clase creada por ti??


    Muchas gracias de antemano.

    ResponderEliminar
  30. Saludos cordiales :
    esta muy bueno el tutorial.
    Pero tengo una consulta, lo que pasa estoy haciendo un módulo y
    uno de los requerimiento es que reporte solo se pueda visualizar(.pdf) mas no pueda guardar ni imprimir (deshabilitar las opciones de guardar e imprimir).
    Agradezco su pronta respuesta.

    ResponderEliminar
  31. Los libros electrónicos según se usen, son una gran fuente de ingresos o una forma muy buena de obtener suscriptores a mi negocio en internet, les dejo la página www.EscritoresDeArticulos.com donde hacen estos libros y así nos ahorrarnos este gran trabajo. Espero sirva mi aporte.

    ResponderEliminar
  32. Hola, saludos los tutoriales estan muy buenos ..
    Master of master ...!!!
    muchas gracias me sirvió de maravilla ....

    ResponderEliminar
  33. Como podria hacer para mostrarlo en otra pestaña??

    ResponderEliminar
  34. Que tal Alex, excelente tu aporte!, era justamente lo que estaba buscando hace varios días.
    Se te agradece!

    ResponderEliminar
  35. Hola es muy bien el tutorial, pero tengo un problema , cuando corro mi servlet me manda este error

    java.lang.NoClassDefFoundError: Could not initialize class net.sf.jasperreports.engine.util.JRStyledTextParser
    at net.sf.jasperreports.engine.fill.JRBaseFiller.(JRBaseFiller.java:121)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.(JRVerticalFiller.java:88)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.(JRVerticalFiller.java:103)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.(JRVerticalFiller.java:61)
    at net.sf.jasperreports.engine.fill.JRFiller.createFiller(JRFiller.java:179)
    at net.sf.jasperreports.engine.fill.JRFiller.fill(JRFiller.java:108)........................................

    -----------------------------------------------------------------------------------------------------------------------------------------------------------
    Mi servlet es el siguiente:

    public class Reporte_equip_actv_area extends HttpServlet {
    private StoreService store;

    public Reporte_equip_actv_area(){
    super();
    store= new StoreServiceImpl();
    }

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    //response.setContentType("text/html;charset=UTF-8");
    /* Para la geeracion del pdf */
    BienesDataSourse bds= new BienesDataSourse();

    response.setHeader("Content-Disposition", "attachment; filename=\"reporte.pdf\";");
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("Pragma", "no-cache");
    response.setDateHeader("Expires", 0);
    response.setContentType("application/pdf");
    ServletOutputStream out = response.getOutputStream();

    List listBienes = new ArrayList();

    /* Fin de estas cabecereas */

    String id_aux="";
    id_aux=request.getParameter("id_area");

    Integer id=0;
    try{
    if(id_aux != null || ! id_aux.equals("0")){
    id=Integer.parseInt(id_aux);
    }else{
    id=0;
    }
    }catch(NullPointerException e){

    }
    System.out.println("id de reporte= "+id);

    /* Para la generacion delo del PDF*/
    listBienes=store.ConsultarEquipo_activ_area(id);
    for(int i=0; i<listBienes.size(); i++){
    bds.addBienes(listBienes.get(i));
    }

    try
    {
    JasperReport reporte = (JasperReport) JRLoader.loadObject(getServletContext().getRealPath("Reportes//Rep_Equip_actv_area.jasper"));

    /*Map parametros = new HashMap();
    parametros.put("autor", "Juan");
    parametros.put("titulo", "Reporte");*/

    JasperPrint jasperPrint = JasperFillManager.fillReport(reporte, null, bds);

    JRExporter exporter = new JRPdfExporter();
    exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
    exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
    exporter.exportReport();
    }
    catch (Exception e)
    {
    e.printStackTrace();
    }
    /* fin de la generación delo del PDF */
    }


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    processRequest(request, response);
    }

    }


    Alquien podria ayudarme :'(


    ResponderEliminar
  36. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  37. Genial tuve un poco de problemas al inplementarlo en eclipse, pero, muy bien muchas gracias por el aporte! :)
    un saludo.

    ResponderEliminar
  38. alguien sabe porqué me sale esta excepción al ejecutar el proyecto?

    java.lang.ClassCastException: org.apache.catalina.connector.CoyoteOutputStream cannot be cast to java.io.File
    at net.sf.jasperreports.engine.export.JRPdfExporter.exportReport(JRPdfExporter.java:403)
    at pruebas.reportes.jasperreports.web.ServletReporte.processRequest(ServletReporte.java:76)
    at pruebas.reportes.jasperreports.web.ServletReporte.doGet(ServletReporte.java:94)

    ResponderEliminar
  39. Hola, estoy haciendo reportes con esta herramienta pero en el output del servidor Apache Tomcat de mi IDE (NetBeans) me sale este error:
    SEVERE [http-nio-8084-exec-5] org.apache.catalina.core.StandardWrapperValve.invoke El Servlet.service() para el servlet [jsp] en el contexto con ruta [/Inventarios_Web] lanzó la excepción [java.lang.IllegalStateException: getOutputStream() ya ha sido llamado para esta respuesta] con causa raíz
    java.lang.IllegalStateException: getOutputStream() ya ha sido llamado para esta respuesta
    at org.apache.catalina.connector.Response.getWriter(Response.java:535)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212)
    at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:103)
    at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:115)
    at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:108)
    at org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:181)
    at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:120)
    at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:75)
    at org.apache.jsp.generarReporte_jsp._jspService(generarReporte_jsp.java:130)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:403)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:347)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

    Si me pudieras dar una razón de este error te lo agradecería. Gracias.

    ResponderEliminar
  40. hola primero que nada felicitarte por tu tutorial, lo seguí haciendo con netbeans y en mi maquina corre perfectamente, pero al subirlo a tomcat en mi servidor, no marca ningun error pero no sube, sabras porque sera?? gracias por tu atención

    ResponderEliminar
  41. Tengo una aplicación web, cuando deseo imprimir un comprobante desde un explorador no se realiza, pero cuando hago desde mi IDE eclipse si imprime. Tendrán alguna solución o a que se debe.

    Gracias de antemano.

    ResponderEliminar