Using Java to create a report with the JasperReport java API

5

In this blog I will describe how to create a Report with JasperReport in Java. For this purpose I have used the Communitie edition of iReport. This edition contains besides JasperReport also iReport. iReport is a report designer for JasperReport. You can download it from http://jasperforge.org/projects/ireport

After installation I started iReport to design a report. I have design a report to create CD booklets. It contains the name of the artist, an album title, an image, the tracklist and the lyrics of these tracks.

JasperReport designs are files stored in XML format. The XML tab of iReport show the content of this file.

 

Now I will come into some more details about the structure of this XML file.
The toplevel tag of this file is ‘JasperReport’. On the next level the detail tags are set:

  • Properties and style like default font, font size, etc.
  • The queryString (important: this is the report entry point)
  • Report background
  • Report title and image
  • Reported fields, positioning, layout, etc.

 

I have created a small program that uses the JasperReport java API to create a CD booklet report and store it as a PDF file on the local file system. The remaining part of this blog explains some code snippets.

To use the JasperReport API for this program the following imports are required:

  • import net.sf.jasperreports.engine.JasperCompileManager;
  • import net.sf.jasperreports.engine.JasperExportManager;
  • import net.sf.jasperreports.engine.JasperFillManager;
  • import net.sf.jasperreports.engine.JasperPrint;
  • import net.sf.jasperreports.engine.JasperReport;
  • import net.sf.jasperreports.engine.design.JasperDesign;
  • import net.sf.jasperreports.engine.xml.JRXmlLoader;
  • import net.sf.jasperreports.engine.JRException;
  • import net.sf.jasperreports.engine.data.JRXmlDataSource;

 

First I created a report request and response type. The request contains the report (template) name, the location of this template, output filename, output location and the xml input datastream (as string). The response also contains the output filename and location. Besides that it contains the output content type and size and finally the report output in base64Binary format.

A Request example:

RunReportRequestType request = new RunReportRequestType();
request.setRapportLocatie("D:\\CDbooklet\\createBooklet\\src\\");
request.setRapportNaam("CDBooklet.jrxml");
request.setOutputLocatie("D:\\CDbooklet\\createBooklet\\src\\");
request.setOutputNaam("CDBooklet.pdf");
request.setXmlData("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<version/>\n" +
"<CDBooklets>\n" +
" <Artist>\n" +
" <ArtistID>1</ArtistID>\n" +
" <ArtistName>Queen</ArtistName>\n" +
" <AlbumID>1</AlbumID>\n" +
" <AlbumTitle> A Night at the Opera</AlbumTitle>\n" +
" <AlbumImage>D:/workspace/queen.jpg</AlbumImage>\n" +
" </Artist>\n" +
" <Track>\n" +
" <TrackID>1</TrackID>\n" +
" <TrackTitle>Bohemian Rhapsody</TrackTitle>\n" +
" <Duration>6.15</Duration>\n" +
" <ArtistID>1</ArtistID>\n" +
" <AlbumID>1</AlbumID>\n" +
" </Track>\n" +
" <Track>\n" +
" <TrackID>2</TrackID>\n" +
" <TrackTitle>Sweet Lady</TrackTitle>\n" +
" <Duration>5.03</Duration>\n" +
" <ArtistID>1</ArtistID>\n" +
" <AlbumID>1</AlbumID>\n" +
" </Track>\n" +
" <Lyric>\n" +
" <TrackID>1</TrackID>\n" +
" <AlbumID>1</AlbumID>\n" +
" <LyricData>\n" +
" Bohemian Rhapsody\n" +
" lyric \n" +
"</LyricData>\n" +
" </Lyric>\n" +
" <Lyric>\n" +
" <TrackID>2</TrackID>\n" +
" <AlbumID>1</AlbumID>\n" +
" <LyricData>\n" +
" Sweet Lady\n" +
" lyric \n" +
"</LyricData>\n" +
" </Lyric>\n" +
"</CDBooklets>\n");

This request is used as the input for the runReport method that does the actual processing. This method contains the following parts:

Create a response object

RunReportResponseType response = new RunReportResponseType();
Read the report design
File file = new File(request.getRapportLocatie() + request.getRapportName());
FileInputStream template = null;
try {
template = new FileInputStream(file);
} catch(FileNotFoundException e) {
System.out.println("File " + file.getAbsolutePath() + " could not be found on filesystem");
} catch(IOException ioe) {
System.out.println("Exception while reading the file" + ioe);
}

Load the report design

JasperDesign design = null;
try {
design = JRXmlLoader.load(template);
} catch (JRException e) {
e.printStackTrace();
}

Compile the design (it is also possible to load the compiled reports directly, but for learning purposes I have chosen to load the template and compile it from here).

JasperReport report = null;

try {
report = JasperCompileManager.compileReport(design);

} catch (JRException e) {
e.printStackTrace();

}

Parse the request XML input stream and convert it into a Document. The JRXmlDataSource method requires two parameters. The first one it the input stream document. The second is the earlier mentioned report entry point. For this report is gets the value ‘/CDBooklets’. For a single level report this is straightforward. In a multi level report (master report with one or more subreports) it becomes a bid more complicated. This because each (sub)reports has it’s own entry point. You have to take care of this in your code. But for now it’s easy:

Document xmlDoc = null;
JRXmlDataSource ds = null;
try {
  xmlDoc = convertStringToDocument(xmlPayload);
  ds = new JRXmlDataSource(xmlDoc,report.getQuery().getText());
} catch (JRException e) {
  e.printStackTrace();
}

Fill the report and create the PDF file.

JasperPrint print = null;
byte[] pdf = null;
try {
  print = JasperFillManager.fillReport(report, null, ds);
  pdf = JasperExportManager.exportReportToPdf(print);
} catch (JRException e) {
  e.printStackTrace();
}

Fill the response object

response.setContentSize(String.valueOf(pdf.length));
response.setContentType("application/pdf");
response.setOutputNaam(request.getOutputNaam());
response.setOutputLocatie(request.getOutputLocatie());
response.setReport(pdf);

Or write the pdf output stream to the filesystem.

OutputStream output = null;
try {
  output = new FileOutputStream(new File(request.getOutputLocatie() + request.getOutputNaam()));
} catch (FileNotFoundException e) {
  e.printStackTrace();
}
try {
  JasperExportManager.exportReportToPdfStream(print, output);
} catch (JRException e) {
  e.printStackTrace();
}

And the final result



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

This brings me to the end of this post.
You can download the source code by clicking on the following link createBooklet

In a next post I wil describe how to use this functionality (as a web-service) from Oracle BPEL.


Share.

About Author

As a SOA and BPM professional, Marcel is an experienced consultant in the field of process design and process modeling. Within this field system integration and IT-transcending business processes have Marcel's special interest.

5 Comments

  1. Nice post.
    Keeping the compiled reports on a database table sounds like a good idea.
    Just to add, the compiled jasper files can also be kept on the file system (somewhere separate from the application i.e. outside the .ear). The application just needs to know the filesystem location at runtime.

  2. Marcel van de Glind on

    Hi Renan,Recently in a customer project we choose to store the reports in a database table.We changed the java coding a litle bit to retrieve to reports during runtime from the database. For this project it works very good. decoupling is the key.

  3. Hi Marcel!
    Great tutorial, it helped me alot!!!

    I got my tutorial working and my doubt is about “Deploy”…

    I mean, I already have a ant task to compile reports into .jasper file and I want to know what is best practice talking about report deploy. For example, If I have to change my report I don’t want to deploy the whole application again, I want to change only the .jasper file and put it in server.

    How you do in your organization??? Do you keep it inside .ear or something like??? What is the best practice around that?

    Thanks in advance!!!

Leave a Reply