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.
Something has changed in your code plugin because is imposible to read it, Could you resolve it? thanks,
I fixed the code blocks for you, hopes it helped.
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.
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.
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!!!