Wednesday, December 22, 2010

Spring 3 MVC - Jasper: Using Two Sub-reports with Distinct Data Sources Tutorial

In this tutorial we will integrate Jasper reporting with a simple Spring 3 MVC application. We will create a master report and two sub-reports to display our data. We will provide three distinct data sources for each report. To design the report layout we will use iReport to create the template.

This tutorial is a variation of the Spring 3 MVC - Jasper: Sub-reports Using Two Data Sources Tutorial. It's highly recommended that you read that first. In that tutorial we provided a main report, a single sub-report, and two distinct data sources. This time we have two sub-reports and an additional data source. Everything else is still the same.

What is Jasper Reports?
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.

Source: http://jasperforge.org/projects/jasperreports

What are Sub-reports?
Sub-reports are normal Jasper reports. They're called sub-reports because they are embedded within a report. The structure and data access is essentially the same.

Similar with our previous tutorial. We will setup our Spring 3 MVC application first. If you need a review with Spring MVC, I suggest you read the other tutorials I've posted. Or you can also Google for related tutorials.

Here's our report without the sub-report added:


Here's our report with a single sub-report added:


Here's our final report with two sub-reports added:


Here are the associated JRXML files for each sub-report.

Sub-report 1: tree-template_subreport1.jrxml

Sub-report 2: tree-template_subreport2.jrxml

Let's view the final structure of our project.


We can now start our project.

Our first task is to setup the main controller that will handle the download request.

This controller declares three mappings:
/download - for showing the download page
/download/xls - for retrieving the actual Excel report
/download/pdf - for retrieving the actual PDF report

If you notice in each request handlers, we return an instance of ModelAndView. The view names are declared on a separate XML file under /WEB-INF/jasper-views.xml

jasper-views.xml

We have declared four beans in this XML file. Each bean uses a Spring built-in view for Jasper that corresponds to a specific format. Take note of these special properties for each view:
id
url
reportDateKey
subReportUrls
subReportDataKeys

Also take note of the following sub-report variables:
JasperCustomSubReportLocation1
JasperCustomSubReportLocation2
JasperCustomSubReportDatasource1
JasperCustomSubReportDatasource2

We declared these fours variables in the master JRXML report file named tree-template.jrxml.

First, in the headers:

Second, in the subreport element:

If you want to see the whole JRXML file, you can find it in the downloadable project at the end of this tutorial. If you look carefully at the following line:

We have basically wrapped our sub-report datasource JasperCustomSubReportDatasource with a JRBeanCollectionDataSource. This is important if you want to see your data repeated over multiple rows. Otherwise, all your data will be consumed by the first record. See this post at SpringSource forums for more info.

Let's examine further the contents of the subreport element:

Here we're referencing a single sub-report parameter: PARENT_ID. This parameter is declared inside the sub-report JRXML file itself. We've declared how to populate this parameter. We instructed Jasper "Hey, Jasper this is what you need to do when you encounter this parameter". For example, in the PARENT_ID parameter, we wrote:
[CDATA[$F{id}]]

This means take and assign the value of the Field id.

In this tutorial the PARENT_ID and id point to the same value so that the parent table has a relation with its child table. For example, an address to a person, there must be an identifier that links between the two. Maybe, we can use the person's id. This means the person's id must be present in the Person's table and in the Address table.

Let's return to the master report.

If you examine the header of the master report file, you'll see the following field declarations:

If you look back at the MainController, the master report and the sub-report have their own distinct data sources.

SalesDAO

Our datasources are simple array lists populated with simple POJO instances.

Sales

Remarks

Dealer

Our application is almost finished. We just need to setup some required Spring configuration files.

To enable Spring MVC we need to add it in the web.xml

web.xml

Take note of the URL pattern. When accessing any pages in our MVC application, the host name must be appended with
/krams

In the web.xml we declared a servlet-name spring. By convention, we must declare a spring-servlet.xml as well.

spring-servlet.xml

By convention, we must declare an applicationContext.xml as well.

applicationContext.xml

Our application is now finished. We've managed to setup a simple Spring 3 MVC application with reporting capabilities using Jasper. We've managed to add a master report and sub-report using two distinct data sources. We've also leveraged Spring's MVC programming model via annotation.

To access the download page, enter the following URL:
http://localhost:8080/spring-jasper-two-subreports/krams/main/download

If you want to download the report directly, enter the following URL for XLS format:
http://localhost:8080/spring-jasper-two-subreports/krams/main/download/xls

For PDF format, enter the following URL:
http://localhost:8080/spring-jasper-two-subreports/krams/main/download/pdf

For HTML and CSV, I left this exercise for my readers.

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-jasper-integration-tutorial/

You can download the project as a Maven build. Look for the spring-jasper-two-subreports.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and Jasper, feel free to read my other tutorials in the Tutorials section.

For more info about Sub-reports, check the following:
Spring Framework Reference: Chapter 17.7 JasperReports
JasperForge: Subreports! by Giulio Toffoli
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3 MVC - Jasper: Using Two Sub-reports with Distinct Data Sources Tutorial ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring 3 MVC - Jasper Integration Tutorial Without the View Support

In this tutorial we will integrate Jasper with a simple Spring 3 MVC application. We will provide a custom data source where Jasper will retrieve its data. We will not use any of Spring's View implementations for Jasper. Instead we will manually build the report.

Note: I suggest reading the following updated tutorial instead:
Spring MVC 3.1 and JasperReports: Using iReport and AJAX

For a reference to these View implementations please see the "Spring Framework Reference 16.7.2.2 Configuring the Views". If you want to learn how to integrate Jasper with Spring's View implementations, please read my other tutorial Spring 3 MVC - Jasper Integration Tutorial

What is JasperReports?
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.

Source: http://jasperforge.org/projects/jasperreports

Similar with our previous tutorial. We will setup our Spring 3 MVC application first. If you need a review with Spring MVC, I suggest you read the other tutorials I've posted. Or you can also Google for related tutorials.

Here's a screenshot of the report that we will be generating:


Our first task is to setup the main controller that will handle the download request.

MainController

This controller declares two mappings:
/download - for showing the download page
/download/xls - for retrieving the actual Excel report

Examine the doSalesReportXLS() controller method. It has a reference to a download service named downloadService. This service handles the actual report processing. Later, we'll discuss that in-depth.

The /download mapping will display the downloadpage view which resolves to /WEB-INF/jsp/downloadpage.jsp

downloadpage.jsp

This is a simple JSP. It has an HTML link for downloading the report. Notice the URL points to /krams/main/download/xls. The same mapping we have in the MainController.

Here's a screenshot of this page:

Next, we enable Spring MVC in the web.xml

web.xml

Take note of the URL pattern. When accessing any pages in our MVC application, the host name must be appended with
/krams

In the web.xml we declared a servlet-name spring. By convention, we must declare a spring-servlet.xml as well.

spring-servlet.xml

This XML config declares a view resolver. All references to a JSP name in the controllers will map to a corresponding JSP in the /WEB-INF/jsp location.

By convention, we must declare an applicationContext.xml

applicationContext.xml

This XML config declares three beans to activate the Spring 3 MVC programming model.

Let's return back to Jasper.

If you remember back in the MainController we declared a reference to a DownloadService which is automatically injected by Spring.

The DownloadService is a delegate. All reporting processing is handled by this service.

DownloadService

To generate the report, we call the downloadXLS() method. This generates an Excel report. Let's examine further how the report is generated:

1. Retrieve an instance of our datasource:
SalesDAO datasource = new SalesDAO();
JRDataSource ds = datasource.getDataSource();

The datasource can come from a variety of sources like from an in-memory list, database, and alike. Later, we'll show what's inside this SalesDAO

2. Retrieve an InputStream reference to the actual JRXML file itself:
InputStream reportStream = this.getClass().getResourceAsStream("/tree-template.jrxml");


3. Create a JasperDesign object from the JRXMl file:
JasperDesign jd = JRXmlLoader.load(reportStream);


4. Compile the JasperDesign:
JasperReport jr = JasperCompileManager.compileReport(jd);


5. Create the Jasper print:
JasperPrint jp = JasperFillManager.fillReport(jr, params, ds);

This basically fills the JasperReport with contents from the datasource.

6. Export the report to your desired format. For this tutorial we will export it as an
Excel document.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Exporter exporter = new Exporter();
exporter.export(jp, baos);

Here we pass an instance of a ByteArrayOutputStream and a JasperPrint object.

7. Set the response header and content type:
String fileName = "SalesReport.xls";
response.setHeader("Content-Disposition", "inline; filename="+ fileName);
response.setContentType("application/vnd.ms-excel");
response.setContentLength(baos.size());

Make sure you set the correct contentType.

8. Write the report to the output stream:
writeReportToResponseStream(response, baos);

Now, let's examine the remaining classes.

The Exporter
This is a custom wrapper to Jasper's JRXlsExporter. The purpose of this class is to encapsulate the exporting of the report to different formats. This isn't mandatory. You can remove the contents of export() and place it along with the DownloadService. Take note we're encapsulating a Jasper feature here, not a DynamicJasper. So if you have specific questions about these, make sure to search the Jasper forums.

The datasource
Here we provide a custom datasource made from in-memory list of Sales items. We use the DAO name here to indicate that the data can come from a DAO or other persistence means.

SalesDAO

Our datasource returns a list of Sales. This is a simple Data Transfer Object for containing our data from the database.

Sales

Our application is now finished. We've managed to setup a simple Spring 3 MVC application with reporting capabilities from Jasper. We've managed to create a report without relying on Spring's View implementations for Jasper. We've also leveraged Spring's MVC programming model via annotation.

To access the download page, enter the following URL:
http://localhost:8080/spring-jasper-nospringviews/krams/main/download

If you want to download the report directly, enter the following URL:
http://localhost:8080/spring-jasper-nospringviews/krams/main/download/xls

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-jasper-integration-tutorial/

You can download the project as a Maven build. Look for the spring-jasper-nospringviews.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and Jasper, feel free to read my other tutorials in the Tutorials section.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3 MVC - Jasper Integration Tutorial Without the View Support ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring 3 MVC - Jasper: Sub-reports Using Two Data Sources Tutorial

In this tutorial we will integrate Jasper reporting with a simple Spring 3 MVC application. We will create a master report and a sub-report to display our data. We will provide two separate data sources for each report. To design the report layout we will use iReport to create the template. If you're not familiar yet with integrating a simple report, I suggest you read my other tutorial: Spring 3 MVC - Jasper Integration Tutorial. It's also a good time to review sub-reports by reading Spring 3 MVC - Jasper: Sub-reports Tutorial. This tutorial is a variation of that last one.

What is Jasper Reports?
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.

Source: http://jasperforge.org/projects/jasperreports

What are Sub-reports?
Sub-reports are normal Jasper reports. They're called sub-reports because they are embedded within a report. The structure and data access is essentially the same.

Similar with our previous tutorial. We will setup our Spring 3 MVC application first. If you need a review with Spring MVC, I suggest you read the other tutorials I've posted. Or you can also Google for related tutorials.

The image below is an actual screenshot of our report without the sub-report:


With sub-report added, here's the new image:

We added two extra fields: buyer and remarks field. These two fields are located in the sub-report. These fields are placed in the Detail section of the report layout. The data will be repeated as many times as the number of rows in your datasource. You can place conditions inside your sub-report to restrict the data that gets repeated.

Using iReport we can generate both report layouts. On the final document, the master and sub-report are merged as if there's only a single document.

Here's the master report:

The highlighted gray rectangle indicates an embedded sub-report. The format is exactly the same as we had in our previous Jasper tutorial. If you need to a refresher, feel free to read that tutorial first.

Here's the sub-report:

Notice we have two Parameters here. Both have the same identifier $P{PARENT_ID}. Actually, the fields are too short to show the whole Parameter names. If we examine the JRXML file, here's what we will see:

The two fields are actually condition statements:
($P{PARENT_ID}).equals($F{id})?$F{buyer}:""
($P{PARENT_ID}).equals($F{id})?$F{remarks}:""

Each condition means if the parameter PARENT_ID is equal to the field id then display the buyer field. If they're not equal, display an empty string. So basically on the sub-report we show an empty string if the id doesn't match.

There's a problem with that. Yes, it's going to print empty strings but these empty strings will still occupy space in the report. The yellow boxes show these empty spaces.


To fix this behavior, we add the following element just right after the band element:
This means "Show me this section if the PARENT_ID matches the field id" This means we can re-write our field expression from:
($P{PARENT_ID}).equals($F{id})?$F{buyer}:""
($P{PARENT_ID}).equals($F{id})?$F{remarks}:""
to this
$F{buyer}
$F{remarks}
Here's our updated sub-report JRXML file:
For the purpose of this tutorial I will keep the old way:
($P{PARENT_ID}).equals($F{id})?$F{buyer}:""
($P{PARENT_ID}).equals($F{id})?$F{remarks}:""

Let's keep in mind that such expression exists. Eventually we might find some use for such expressions.

Let's view the final structure of our project.

Besides the Spring XML files, these are all the files we need for this project.

We can now begin our project.

Our first task is to setup the main controller that will handle the download request.

This controller declares three mappings:
/download - for showing the download page
/download/xls - for retrieving the actual Excel report
/download/pdf - for retrieving the actual PDF report

If you notice in each request handlers, we return an instance of ModelAndView. The view names are declared on a separate XML file under /WEB-INF/jasper-views.xml
jasper-views.xml

We have declared four beans in this XML file. Each bean uses a Spring built-in view for Jasper that corresponds to a specific format. Take note of these special properties for each view:
id
url
reportDateKey
subReportUrls
subReportDataKeys

Also take note of the following sub-report variables:
JasperCustomSubReportLocation
JasperCustomSubReportDatasource

We declared these two variables in the master JRXML report file named tree-template.jrxml.

First, in the headers:

Second, in the subreport element:

If you want to see the whole JRXML file, you can find it in the downloadable project at the end of this tutorial. If you look carefully at the following line:

We have basically wrapped our sub-report datasource JasperCustomSubReportDatasource with a JRBeanCollectionDataSource. This is important if you want to see your data repeated over multiple rows. Otherwise, all your data will be consumed by the first record. See this post at SpringSource forums for more info.

Let's examine further the contents of the subreport element:

Here we're referencing a single sub-report parameter: PARENT_ID. This parameter is declared inside the sub-report JRXML file itself. We've declared how to populate this parameter. We instructed Jasper "Hey, Jasper this is what you need to do when you encounter this parameter". For example, in the PARENT_ID parameter, we wrote:
[CDATA[$F{id}]]

This means take and assign the value of the Field id.

In this tutorial the PARENT_ID and id point to the same value so that the parent table has a relation with its child table. For example, an address to a person, there must be an identifier that links between the two. Maybe, we can use the person's id. This means the person's id must be present in the Person's table and in the Address table.

Let's return to the master report.

If you examine the header of the master report file, you'll see the following field declarations:

If you look back at the MainController, the master report and the sub-report have their own distinct data sources.

SalesDAO

Our datasources are simple array lists populated with simple POJO instances.

Sales

Remarks


Our application is almost finished. We just need to setup some required Spring configuration files.

To enable Spring MVC we need to add it in the web.xml

web.xml

Take note of the URL pattern. When accessing any pages in our MVC application, the host name must be appended with
/krams

In the web.xml we declared a servlet-name spring. By convention, we must declare a spring-servlet.xml as well.

spring-servlet.xml

By convention, we must declare an applicationContext.xml as well.

applicationContext.xml

Our application is now finished. We've managed to setup a simple Spring 3 MVC application with reporting capabilities using Jasper. We've managed to add a master report and sub-report using two distinct data sources. We've also leveraged Spring's MVC programming model via annotation.

To access the download page, enter the following URL:
http://localhost:8080/spring-jasper-subreport-dual/krams/main/download

If you want to download the report directly, enter the following URL for XLS format:
http://localhost:8080/spring-jasper-subreport-dual/krams/main/download/xls

For PDF format, enter the following URL:
http://localhost:8080/spring-jasper-subreport-dual/krams/main/download/pdf

For HTML and CSV, I left this exercise for my readers.

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-jasper-integration-tutorial/

You can download the project as a Maven build. Look for the spring-jasper-subreport-dual.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and Jasper, feel free to read my other tutorials in the Tutorials section.

For more info about Sub-reports, check the following:
Spring Framework Reference: Chapter 17.7 JasperReports
JasperForge: Subreports! by Giulio Toffoli
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3 MVC - Jasper: Sub-reports Using Two Data Sources Tutorial ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share