top

Thursday, 10 November 2011

JSF + JPA + JasperReports (iReport) Part 1

Hi in this post we will see the overview of JasperReports and how to integrate into JSF application. JasperReports is the world's most popular open source reporting engine. It is entirely written in Java and it is able to use data coming from any kind of data source and produce pixel-perfect documents that can be viewed, printed or exported in a variety of document formats including HTML, PDF, Excel, OpenOffice and Word.

 In Primeface library also use this JasperReports to generate the PDF, CSV and DOC formats with single line of code. see here. but its not flexible and we cant change template. so here we see the how to use JasperReports for create the template and integrate  JSF 2.0.

We are using iReport tool for crating template.

Download JasperReports and iReport

  • Jasper Reports download from here. This zip contain jasper library and its dependencies and lots sample codes.
  • iReport download  from here
Now create the simple JSF Application to retrieve the data from database using JPA, then create the template using iReport and then integrate into JSF application.

JSF+JPA
  Java Persistence API is standard way to access the all ORM (Object Relational Mapping) tools like Hibernate, EclipseLink, TopLink,.. . These tools are internally use JDBC to access the database.

the Heart of JPA is consist of two parts

  • persistence.xml - Its xml file describe the persistence provider (ORM provider) and connection information like database URL, username and password. or data source.
  • Entity Classes - Its normal POJO class for each table in underlying table. This class is annotated with @Entity and some annotation provided by JPA. Its way to express and map the property in the class into table in the DB. 
These entity class are  manually we can create or using IDE tools like Net beans IDE provide "Entity Classes From Database" option to auto generate the Entity Classes. (See video in below)

Once these entity classes are created then we need to create CRUD methods to wrapping these entities for ease of use. These kind of classes also auto generate from "Session Beans from Entity Classes" option.

 Here we using GlassFish Server 3. Its supports EJB 3.1. 
Now we create the JSF page to display the entity classes in table structure and provide buttons for export into variety of formats.


index.xhtml

        Facelet Title
    
    
        
        
            
             
              
               
               
        
        
            
                
                    User Name
                
                #{user.userId}
            
            
            
                
                    Password
                
                #{user.password}
            
        
    


Jasper Reports
Once sample JSF application is completed then we going to integrate Jasper Reports. 
First, include all necessary lib into our application. We already download the jasper library zip file. Extract this file they have lots of folder. one for dist folder contain main jasperreports-4.1.3.jar file and lib folder contain all necessary dependencies. see the requirements of jasper reports from here.

This is flow diagram of JasperReports. 

Jasper Report Flow

Here we use iReport tool to generate the JRXML template. this file is pure xml file to describe the layout and place-holders. then we need to compile into jasper file. its binary format. this compilation process we can do in 2 ways. 
  1. Using iReport to compile the jrxml file into jasper
  2. Using JasperReport API we can do through programme.
This is the code snippet compile the jrxml file into jasper file
JasperCompileManager.compileReportToFile("report.jrxml", "report.jasper");

or we can use iReport to compile

now compilation is finished. data is also ready. here data is java beans (entity beans) . This entity beans can't use directly. we wrap into one more class JRBeanCollectionDataSource then using JasperFillManager we generate JRPRINT object.

code:
JRBeanCollectionDataSource beanCollectionDataSource=new JRBeanCollectionDataSource(listOfUser);
JasperPrint jasperPrint=JasperFillManager.fillReport("report.jasper", new HashMap(),beanCollectionDataSource);

once JasperPrint is ready then we export using JasperExportManager
JasperExportManager.exportReportToPdfFile(jasperPrint, "report.pdf");

For exporting into docx, xlsx, odt, ods, pptx formats we should use JRDocxExporter, JRXlsxExporter, JROdtExporter, JROdsExporter, JRPptxExporter 
and one more thing we don't want to store the exported format into file system. we need to send these formats to client via stream.
Code:
HttpServletResponse httpServletResponse=(HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
httpServletResponse.addHeader("Content-disposition", "attachment; filename=report.docx");
ServletOutputStream servletOutputStream=httpServletResponse.getOutputStream();
JRDocxExporter docxExporter=new JRDocxExporter();
docxExporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
docxExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, servletOutputStream);
docxExporter.exportReport();
FacesContext.getCurrentInstance().responseComplete();


here we get the OutputStream via FacesContext.



You can download this complete example from GitHub (or) Google Code

DemoBean.xml
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ramki.jsf;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.oasis.JROdtExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporterParameter;
import net.sf.jasperreports.engine.export.ooxml.JRPptxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import org.ramki.entity.User;
import org.ramki.session.UserFacade;

/**
 *
 * @author ramki
 */
@ManagedBean
@SessionScoped
public class DemoBean {
    private List listOfUser;

    @EJB UserFacade userFacade;
    
    public List getListOfUser() {
        listOfUser=userFacade.findAll();
        return listOfUser;
    }

    public void setListOfUser(List listOfUser) {
        this.listOfUser = listOfUser;
    }
    JasperPrint jasperPrint;
    public void init() throws JRException{
        JRBeanCollectionDataSource beanCollectionDataSource=new JRBeanCollectionDataSource(listOfUser);
String  reportPath=  FacesContext.getCurrentInstance().getExternalContext().getRealPath("/reports/report.jasper");        jasperPrint=JasperFillManager.fillReport(reportPath, new HashMap(),beanCollectionDataSource);
    }
    
   public void PDF(ActionEvent actionEvent) throws JRException, IOException{
       init();
       HttpServletResponse httpServletResponse=(HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
      httpServletResponse.addHeader("Content-disposition", "attachment; filename=report.pdf");
       ServletOutputStream servletOutputStream=httpServletResponse.getOutputStream();
       JasperExportManager.exportReportToPdfStream(jasperPrint, servletOutputStream);
       FacesContext.getCurrentInstance().responseComplete();
       
       
   }
    public void DOCX(ActionEvent actionEvent) throws JRException, IOException{
        init();
       HttpServletResponse httpServletResponse=(HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
       httpServletResponse.addHeader("Content-disposition", "attachment; filename=report.docx");
       ServletOutputStream servletOutputStream=httpServletResponse.getOutputStream();
       JRDocxExporter docxExporter=new JRDocxExporter();
       docxExporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
       docxExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, servletOutputStream);
       docxExporter.exportReport();
       FacesContext.getCurrentInstance().responseComplete();
   }
     public void XLSX(ActionEvent actionEvent) throws JRException, IOException{
        init();
       HttpServletResponse httpServletResponse=(HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
      httpServletResponse.addHeader("Content-disposition", "attachment; filename=report.xlsx");
       ServletOutputStream servletOutputStream=httpServletResponse.getOutputStream();
       JRXlsxExporter docxExporter=new JRXlsxExporter();
       docxExporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
       docxExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, servletOutputStream);
       docxExporter.exportReport();
       FacesContext.getCurrentInstance().responseComplete();
   }
      public void ODT(ActionEvent actionEvent) throws JRException, IOException{
       init();
       HttpServletResponse httpServletResponse=(HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
      httpServletResponse.addHeader("Content-disposition", "attachment; filename=report.odt");
       ServletOutputStream servletOutputStream=httpServletResponse.getOutputStream();
       JROdtExporter docxExporter=new JROdtExporter();
       docxExporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
       docxExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, servletOutputStream);
       docxExporter.exportReport();
       FacesContext.getCurrentInstance().responseComplete();
   }
       public void PPT(ActionEvent actionEvent) throws JRException, IOException{
       init();
       HttpServletResponse httpServletResponse=(HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
      httpServletResponse.addHeader("Content-disposition", "attachment; filename=report.pptx");
       ServletOutputStream servletOutputStream=httpServletResponse.getOutputStream();
       JRPptxExporter docxExporter=new JRPptxExporter();
       docxExporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
       docxExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, servletOutputStream);
       docxExporter.exportReport();
       FacesContext.getCurrentInstance().responseComplete();
   }
    
}


Update (02/01/2012): 
mourad mourad mentioned that report’s absolute path is hardcoded like C:\\UsersramkiDesktopreport.jasper". This doesn't work once you deploy your application in another application server.
Yes that's correct. now i fix it.. i used for simplicity purpose.
I try to used getResourceAsStream() method. But it wont work. the reason is our report needs some supporting files like images. If ur report contain no image then u can use getResourceAsStream() method.
So here i want the path of the report jasper file. Then this report engine get the images from that path.

String  reportPath=  FacesContext.getCurrentInstance().getExternalContext().getRealPath("/reports/report.jasper");
jasperPrint=JasperFillManager.fillReport(reportPath, new HashMap(),beanCollectionDataSource); 


Update (22/02/2012): 
            DrAhmedJava commented that i noticed that you have an exception - getOutputStream() has already been called for this response- in your output, and it also happened to me. and i want to share the solution: (Thanks for sharing solution, i updated the code)
                    The idea is that after the pdf() method writes the pdf to http response, the jsf servlet itself tries to reopen the response to write the html rendered from rendering stage of the life cycle, so the solution is to tell the jsf servlet that the response is complete and to skip the rest of life cycle: 
JasperExportManager.exportReportToPdfStream(jasperPrint, servletOutputStream); 
FacesContext.getCurrentInstance().responseComplete(); 


Update : For sub reports and Date Objects check Part 2 of this Series 


Watch the video in HD



Comments are Welcomed
Related Posts Plugin for WordPress, Blogger...