JasperReports Tutorial

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0
Info

The support for Struts 2 JasperReports is an optional download. This product is distributed under the LGPL and cannot be bundled with Apache Licensed productsplugin is a bridge from Struts 2 to JasperReports and does not include JasperReports itself, which must be downloaded separately.

JasperReports is one of the leading open-source Java reporting libraries. It compiles .jrxml (XML source) to .jasper (=compiled version) files, which in turn can be transformed to into several output types (including PDF, HTML, CSV, and XLS and HTML).

In the following example, we will use the framework to dynamically create a PDF with a list of persons. Our action will be used to create a List with Person objects, and our JasperReport JasperReports Result will use this list to fill our template, and return the PDF.

I assume you already have a Struts 2 webapp working.

Note

Note: although this is a very simple example, I suggest you read the fine documentation of both Struts 2 and JasperReports.

Info
titleUsed versions

Webwork 2.2 beta 3 (but should apply to previous versions)
JasperReports 1.1.0
JDK 1.4.2

Right, let's begin.

Our Person class

We start by defining a simple Person POJO class: Person.java

Code Block
titlecom.meviproacme.test.Person.java
package com.meviproacme.test;

public class Person {

	    private Long id;

	    private String name;

	    private String lastName;

	    public Person() {
		super();
	    }

	    public Person(String name, String lastName) {
		super();
		        this.name = name;
		        this.lastName = lastName;
	    }

  	  public Person(Long id, String name, String lastName) {
		super();
		        this.id = id;
		        this.name = name;
		        this.lastName = lastName;
	}  	/** 	 *}
@return
Returns the id. 	 */
	public Long getId() {
		return id; 	}  	/** 	 * @param return id;
The id to set. 	}
*/
	
    public void setId(Long id) {
		        this.id = id;
	}  	/** 	 *}
@return
Returns the lastName. 	 */
	public String getLastName() {
		return lastName; 	}  	/** 	 * @param return lastName;
The lastName to set. 	}
*/
	
    public void setLastName(String lastName) {
		        this.lastName = lastName;
	}  	/** 	 *}
@return
Returns the name. 	 */
	public String getName() {
		return name; 	}  	/** 	 * @param return name;
The name to set. 	}
*/
	
    public void setName(String name) {
		        this.name = name;
	}    }

Nothing special. Just your basic properties, constructor, getters and setters.

}

JasperReports libraries

Before we can continue, we need to add the JR libraries to our classpath. You can download the JR project here: http://www.sourceforge.net/projects/jasperreports
Save the jasperreports-X-project.zip to your harddisk, and extract the files.

We need the following files:

  • dist/jasperreports-X.jar
  • lib/commons-*.jar (all the commons - except maybe for commons-logging)
  • lib/itext-X.jar
  • lib/jdt-compiler.jar

Copy these jars over to your S2_WEBAPP/WEB-INF/lib directory, and add them to your classpath.

...

Creating the Action

Code Block
titlecom.meviproacme.test.action.JasperAction
package com.meviproacme.test.action;

import java.util.ArrayList;
import java.util.List;

import net.sf.jasperreports.engine.JasperCompileManager;

import com.meviproacme.test.Person;
import com.opensymphony.xwork.ActionSupport;

public class JasperAction extends ActionSupport {

	//basic    /** List -to ituse will serve as our JasperReports dataSource. later*/
on 	   private ListList<Person> myList;

	/* 	 * (non-Javadoc) 	 *
	 * @see com.opensymphony.xwork.ActionSupport#execute()
	 */
	public String execute() throws Exception {

		        // createCreate some imaginary persons
		.
        Person p1 = new Person(new Long(1), "Patrick", "Lightbuddie");
		        Person p2 = new Person(new Long(2), "Jason", "Carrora");
		        Person p3 = new Person(new Long(3), "Alexandru", "Papesco");
		        Person p4 = new Person(new Long(4), "Jay", "Boss");

		/* 		 * store everything in a list -// normally,Store thispeople shouldin beour comingdataSource fromlist a(normally 		they *would databasecome butfrom fora thedatabase).
sake of simplicity, I left that out 		 */
		myList = new ArrayListArrayList<Person>();
		        myList.add(p1);
		        myList.add(p2);
		        myList.add(p3);
		        myList.add(p4);

		/* 		 * Here we compile our xml jasper// templateNormally towe would provide a jasperpre-compiled file.jrxml 		file
* Note: this isn't exactly considered 'good practice'.
		 * You should either use precompiled jasper files (.jasper) or provide some kind of check
		 * to make sure you're not compiling the file on every request.
		 * If you don't have to compile the report, you just setup your data source (eg. a List)
		 */
		try {
			JasperCompileManager.compileReportToFile(
					 // or check to make sure we don't compile on every request.
        try {
            JasperCompileManager.compileReportToFile(
                    "S2_WEBAPP/jasper/our_jasper_template.jrxml",
					                    "S2_WEBAPP/jasper/our_compiled_template.jasper");
		        } catch (Exception e) {
			            e.printStackTrace();
			            return ERROR;
		        }
		//if
all goes well ..
		     return SUCCESS;
	}  	/** 	 *}
@return
Returns the myList. 	 */
	public ListList<Person> getMyList() {
		        return myList;
	}    }

...

}

Our JasperAction creates a list of several People. The JasperCompileManager will then compile compiles the jrxml template to a .jasper file.

...

Our Jasper template

JR uses a special XML page configuration to define templates which will be are compiled to .jasper files. These templates will be used to design define the resulting report. It's pretty straightforward.
This is a handwritten version - for more complex versions I seriously suggest taking a look a the various GUI designers.

Code Block
xml
titleour_jasper_template.jrxml
<?xml version="1.0"?>
    <!DOCTYPE jasperReport   PUBLIC "-//JasperReports//DTD Report Design//EN"   "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
    <jasperReport name="jasper_test">
      <!-- ourOur fields -->from the Person class. -->
  <field name="name" class="java.lang.String"/>
      <field name="lastName" class="java.lang.String"/>
      <title>
        <band height="50">
          <staticText>
            <reportElement x="0" y="0" width="180" height="15"/>
            <textElement/>
            <text>
              <<text><![CDATA[WebworkStruts 2 JasperReports Sample]]>
            <></text>
          </staticText>
        </band>
      </title>
      <pageHeader>
        <band></band><band/>
      </pageHeader>
      <columnHeader>
        <band height="20">
          <staticText>
            <reportElement x="180" y="0" width="180" height="20"/>
            <textElement>
              <font isUnderline="true"/>
            </textElement>
            <text>
              <<text><![CDATA[NAME]]>
            <></text>
          </staticText>
          <staticText>
            <reportElement x="360" y="0" width="180" height="20"/>
            <textElement>
              <font isUnderline="true"/>
            </textElement>
            <text>
              <<text><![CDATA[LASTNAME]]>
            <></text>
          </staticText>
        </band>
      </columnHeader>
      <detail>
        <band height="20">
          <textField>
            <reportElement x="180" y="0" width="180" height="15"/>
            <textElement/>
            <textFieldExpression>
              <<textFieldExpression><![CDATA[$F{name}]]>
            <></textFieldExpression>
          </textField>
          <textField>
            <reportElement x="360" y="0" width="180" height="15"/>
            <textElement/>
            <textFieldExpression>
              <<textFieldExpression><![CDATA[$F{lastName}]]>
            <></textFieldExpression>
          </textField>
        </band>
      </detail>
      <columnFooter>
        <band></band><band/>
      </columnFooter>
      <pageFooter>
        <band height="15">
          <staticText>
            <reportElement x="0" y="0" width="40" height="15"/>
            <textElement/>
            <text>
              <<text><![CDATA[Page:]]>
            <></text>
          </staticText>
          <textField>
            <reportElement x="40" y="0" width="100" height="15"/>
            <textElement/>
            <textFieldExpression class="java.lang.Integer">
              <><![CDATA[$V{PAGE_NUMBER}]]>
            <></textFieldExpression>
          </textField>
        </band>
      </pageFooter>
      <summary>
        <band></band><band/>
      </summary>
    </jasperReport>

Save this file in S2_WEBAPP/jasper/ as 'our_jasper_template.jrxml'.

Most important: we declared the fields name and lastName (not surprisingly, two properties from our Person. class). This means we will now be able to use these fields in our Jasper template.

...

Code Block
$F{name}

expression. This means JR JasperReports will ask Struts how to retrieve the name field value . Struts will happily look up this value in the stack (find the person, and invoke the getName() getter), and return it. Similar for the

Code Block

$F{lastName}

The rest is mostly from a Person object; the lastName field is handled the same way.

The rest is markup to define the layout.

Tip

Use a logger (commons-logging, log4j, ...) to watch org.apache.struts2.views.jasperreports in debug mode, if you have any troubles.

...

Registering the Action

Alright, time to add the action to our xwork.xml file:Using the JasperReports plugin requires adding the JasperReports result type as well as normal action configuration.

Code Block
titlexworkstruts.xml
<package name="default" namespace="/" extends="jasperreports-default">
    <action name="myJasperTest" class="com.meviproacme.test.action.JasperAction">
	        <result name="success" type="jasper">
		            <param name="location">/jasper/our_compiled_template.jasper</param>
		            <param name="dataSource">myList</param>
		            <param name="format">PDF</param>
	        </result>
    </action>

Let's explore this a bit further. I assume you are familiar with the xwork notation & schema, if not, check the documentation.

Code Block

<action name="myJasperTest    ...
</package>

To use the JasperReports result type we must either (a) extend the jasperreports-default package that defines it or (b) manually define the JasperReport jasper result type ourselves.

In the above example we extend the jasperreports-default package; we can define the jasper result type manually by defining it the same way the JasperReport plugin does:

Code Block
titleManually defining the "jasper" result type
langxml

<result-types>
    <result-type name="jasper" class="comorg.meviproapache.teststruts2.actionviews.JasperActionjasperreports.JasperReportsResult"/>
</result-types>

We simply register configure our JasperAction with the name 'myJasperTest' - this means that we can execute this Action by sending a request to myJasperTest.action in our browser.

Code Block
<result<action name="successmyJasperTest" typeclass="jaspercom.acme.test.action.JasperAction">

When our JasperAction executes correctly, we will use the Result type registered with the name 'jasper'. This is already done when you include the webwork-default (

Code Block

<include file="webwork-default.xml"/>

). This result type will be configured by our params, which we'll specify below:

Code Block

<param name="location">/jasper/our_compiled_template.jasper</param>

This As discussed above the "jasper" result type is available from either extending the "jasperreports-default" package or by defining the result type manually.

Code Block

<result name="success" type="jasper">

The "location" parameter defines the location of our the compiled jasper file, which will be filled by Struts 2 with our dataSource:

Code Block
<param name="dataSourcelocation">myList</>/jasper/our_compiled_template.jasper</param>

The name of the dataSource - this is the name of the getter you want to call (this will result in a getMyList() call to your JasperAction). It will be used to fill the template with data"dataSource" parameter defines the action property containing the collection of objects to use in our report. In this case it's the myList property which we manually filled with some Person objects.

Code Block
<param name="formatdataSource">PDF<>myList</param>

This The "format" parameter specifies the output format to which the jasper file will be transformedof the report. Possible values are: include PDF, CSV, XLS and HTML.

Code Block

<param name="format">PDF</param>

Conclusion

You should now be able to execute http://localhost:8080/YOUR_WEBAPP/myJasperTest.action - and you should see a nice list of names.
Struts provides probably the most elegant way to deal with JasperReport files; specify the location of the .jasper file, specify what dataSource you want to use, and there you go.

...