Using The JasperReports Struts2 Plugin, A Main Report, And A Subreport

Introduction

My next step in learning how to use JasperReports, is to integrate JasperReports into a Struts2 web application. There is a Struts2 JasperReports plugin (refer 1) that is part of the Struts2 download. Look for the jar named "struts2-jasperreports-plugin-2.0.11.1.jar" in the struts-2.0.11.1\lib directory.

Using the Struts2 JasperReports plugin it's relatively easy to integrate JasperReports into your web application. There are a couple of changes you'll need to make to the master report if you're using a subreport. The changes you need to make are not well documented as it took me several hours of trouble shooting to figure it out. Luckily, Dave Newton, a Struts2 - JasperReports plugin expert, kindly explained to me what I was doing wrong.

I thought it would be a good idea to write the steps up in my blog to help others who are trying to use the Struts2 JasperReports plugin with a main report and subreport.

Example Application

I'm using the example application from reference 2 (see below). You can view a working example and also download a complete war file with all source code (including the .jrxml files).

In the example application there is a Person class that has three attributes (firstName, lastName, and phones). The phones attribute is an ArrayList of Phone objects. The Phone class has two attributes (phoneNumber and phoneType).

In the previous example (refer. 2), I had a main report and a subreport. The subreport was used to display each Person's phone numbers and phone types. I'll be using those same reports for the web application.

I created a dynamic web application in Eclipse and brought in the Person and Phone classes (in package model). I then put all the Struts2 and JasperReport jar files into my web-inf/lib directory. I then created a simple Struts2 ActionSupport class that has an execute method that just returns success. This class also has a getBeanCollection method that returns an ArrayList of Person objects. This method will be used as the data source to fill the Jasper report with data.

Modify The Main JasperReport .jrxml File

The one important step that took me so much trouble to figure out (and thanks again to Dave Newton) is that you have to modify your main .jrxml file if you're using a subreport that is linked to the main report through a field that is an ArrayList (in this case the phones field of class Person).

First copy the struts2-jasperreports-plugin-2.0.11.1.jar to the lib folder that is under iReports (in my case this is "C:\Program Files\JasperSoft\iReport-3.0.0\lib"). Then start up iReport.

Open the main report, which in the example is contacts.jrxml. Select View - Fields, and then click on the phones field and click on modify.

Under Field Class Type enter: org.apache.struts2.views.jasperreports.ValueStackDataSource. This is a data type defined by the Struts2 JasperReports plugin. This data type will ensure the Collection type (phones) is exposed to the subreport by the Struts2 JasperReport plugin.

Click OK and close the fields window.

Next, right click on the subreport and select properties. Click on the Subreport tab and change this

new JRBeanCollectionDataSource($F{phones})

(which is under Use data source expression) to this

$F{phones}

The Struts2 JasperReport plugin will handle processing the phones ArrayList and make it available to the subreport.

Next click the Subreport (Other) tab and under Subreport Expression enter this:

"jasper/contacts_subreport0.jasper"

(this is the location in your web application class path where the subreport can be located, so in my examples the subreport is under web-inf/classes/jasper). Then your web application will be able to find the subreport.

Close that window. Save the report and Build - Compile. Make sure your Options - Settings - Compiler is set to compile the report into the correct folder in your web application (in my example that is WebContent/Jasper).

Also make sure you've compiled the subreport and copied the subreport .jasper file into the correct folder in your web application (again in my example that is web-inf/classes/jasper).

Struts2 XML

In the struts2.xml I defined a package and action with the following code.



<package name="default" extends="jasperreports-default,struts-default">

<action name="myJasperTest" class="action.JasperAction">

        <result name="success" type="jasper">
<param name="location">/jasper/contacts.jasper</param>
<param name="dataSource">beanCollection</param>
<param name="format">PDF</param>
</result>

<result name="error" type="jasper">/Error.jsp</result>

</action>

</package>

Note the extends attribute value of the package node.

In the action's success result the type is set to jasper and three parameter values are passed. The location parameter specifies where to find the main report (in my example the main report is in /jasper/contacts.jasper from my web application's root directory. The dataSource parameter value is the getBeanCollection method (Struts2 calls the getBeanCollection method if you use the beanCollection value) in the ActionSupport class (found in action.JasperAction). This method returns an ArrayList of Person objects that are used to fill the JasperReport.

Lastly, the format parameter specifies the returned report format (eg PDF). Check out the plugin API (reference 1) for other report format types you can specify.

Summary

Hopefully, you'll be able to follow these guidelines to get your own Struts2 - JasperReports web application up and running. In the references section are links to the Struts2 mailing list and to the JasperReports forum. Searching those two resources may help you answer any questions.

References

  1. Struts2 JasperReports Plug In
  2. Bruce Phillips Blog, Using JasperReports With An ArrayList of Objects Part 2: Using the Report In A Java Application
  3. Working Example, Struts2 JasperReports Plug In, Main Report and Subreport
  4. Struts2 Mailing List
  5. JasperReports User Forum
  6. Download a complete war file of the example

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
To control the name of the result file and to help browsers identify the result return type (eg PDF), you can use the contentDisposition param as follows:

<result name="success" type="jasper">
<param name="location">/jasper/contacts.jasper</param>
<param name="dataSource">beanCollection</param>
<param name="format">PDF</param>
         <param name="contentDisposition">attachment;filename="contacts.pdf"</param>
</result>
# Posted By Bruce | 7/16/08 5:45 PM
how to use the label <param name="reportParameters">parametros</param> to pass parameters in struts2?

PLEASEEEEEEE could give me an example?
# Posted By oscar | 7/17/08 7:31 AM
Oscar - Unfortunately I've not used the "reportParameters" in the Struts2 JasperReports plugin. I recommend you post your question on the Struts2 mailing list (see references).
# Posted By Bruce | 7/19/08 6:53 AM
Hi,Bruce Phillips
How are you! I don't download your war file(struts2-jasperreport),please email to me. My Email is [email protected] you very mach!
# Posted By kevin | 9/8/08 12:19 AM
Kevin - The .war file example is too large to email as an attachment. You can download it from the references.
# Posted By Bruce | 9/8/08 5:07 AM
Hi,
First, I would like to thank you for the example on jasper reports in struts2. It is very helpful for understanding the JasperReports Struts2 Plugin.
I also need to implement some charts in my application. It would be great if you can provide an example on how to create charts at runtime in an struts2 application.
Thanks.
# Posted By Manish | 10/12/08 11:22 PM
Hi,
I'm trying to use jasper report + subreport, buy my subreport is in the title band, i pass a java.util.List like a parameter, y named it in jasperreport like you suggest, bu I got the followin error;
java.lang.NoClassDefFoundError: Could not initialize class org.apache.struts2.views.jasperreports.ValueStackDataSource
and I have no idea than waths be wrong.
I using ireport 3.0.0 and jasperreport struts plugin 2.1.2
# Posted By ccl | 10/20/08 12:29 PM
Hi Bill, great note... i have a cuestion in ur example use a BeanCollection for the DataSource, i do the dummy for undersatnd the way it works, and it works.jejej. Well i have a cuestion? have some example for use a Spring Loaded Hibernate Connection, or who cant i use my AppCntx whit a Hibernate Connection on my Struts2 config Xml and.. how i send a map of parameter to mi report to use that parameter in my report.

that's all jeje just a little cuestion xD.. i hope u can help me and Thanx
# Posted By Apolo Rodriguez | 11/27/08 12:27 PM
Hi, Bill: Thank you very much for your paper. I don't know how you make the .jrxml and .jasper files in your sample. I download the .war file and see them already there. Did you make them in iReport? Will please explain it a little more. I read your other paper and wonder if I need to make them in a jave file outside the struts2 first and then use that one in strust2? Thnaks, Qing
# Posted By Qing | 12/7/08 7:54 PM
To pass parameters to the jasper report from the Action class, use :
<param name="reportParameters">${reportParams}</param> for the
jasper result configuration in struts.xml.
reportParams is a regular HashMap in the Action with a getter and setter
( used as reportParams.put("user", getUser()); )
In the .jrxml file , declare a Map parameter called reportParams and use
($P{reportParams}).get("user") to get its value.
# Posted By Sonia Sawlani | 12/8/08 3:15 PM
Qing:

See: http://tinyurl.com/682dpc for an introduction to using iReport to create the .jrxml and .jasper files.
# Posted By Bruce | 12/9/08 11:45 AM
Hi, ( sorry, i am not speak english lenguage )
I have a problem and i can not resolve
I using ireport 3.0.0 and jasperreport struts plugin 2.1.2
I'm trying to use jasper report + subreport

When i use "new JRBeanCollectionDataSource($F{myList})" for the data source of subreport the error is :

java.lang.NoClassDefFoundError: Could not initialize class org.apache.struts2.views.jasperreports.ValueStackDataSource
and I have no idea than waths be wrong.

I need help
Thanks
# Posted By Joaquín Balaguer | 12/22/08 3:39 AM
Hi, Bruce:

Thanks for your help. I got the report as in your paper part1. But when I try it in struts2 (your paper part2), I got the error:
net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression :      Source text : $F{phones} 
.....
Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to org.apache.struts2.views.jasperreports.ValueStackDataSource 
.....
I don't know what's wrong when I follow your instruction for the web application. I made a new DataSource by using action.JasperAction as Factory class. Then use this Datasource to make .jrxml file with subreport through iReport. Then made all the changes for main .jrxml as you mentioned.
Any further help from you shall be highly appreciated.

Qing
# Posted By Qing | 12/29/08 1:50 AM
Hi, Bruce:
I had your struts2 example code working. Two problems bothered me for a while:
1. I shouldn't run the struts2 version .jasper in iReport.
2. There is a conflict in jar files which prevent me to start Tomcat (Error filterstart). When deletting xercesImpl.jar, everything is fine. I don't know what will happen without xercesImpl.jar in my project.
Thank you very much for your great examples.
Qing
# Posted By Qing | 1/1/09 11:43 AM
Hi, Bruce:
I have a parent report which is consists of three or may be until seven subreport. And I use JRBeanCollectionDataSource to fullfill every subreport where between one and another subreport used different java bean (ie: Person, BankAccount, Department, etc) and also different parameter (I used HashMap as parameter which is have several object's key) .

So, I use this method to fill the subreport :

private void fillSubReport(Collection<PayslipDescription> items,
         HashMap parameter, String subReportName) {
      try {
//subReportName = Payment4_subreport4_subreport2.jasper
         File reportFile = ResourcesHelper.getResourceAsFile(subReportName);
         JasperPrint jasperPrint = JasperFillManager.fillReport(reportFile
               .getAbsolutePath(), parameter,
               new JRBeanCollectionDataSource(items));
      } catch (IOException e) {
         e.printStackTrace();
      } catch (JRException e) {
         e.printStackTrace();
      }
   }

But, i'am not sure it can running well, because if several user request or access this report on the same time from different machine with the different parameter, sometimes the report will give the same responds or the same data. How come? with the different parameter it should give different report too.
Do you have any opinion?

Thnx & Regards,
vajar
# Posted By vajar | 1/7/09 8:20 PM
Hi,
Thanks for this forum and sample that were being presented. This help me a lot and save my day.

Thanks,
winmac
# Posted By winmac | 1/20/09 9:26 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.002. Contact Blog Owner