Designing reports using JasperReports 3.5
From ThemesWiki
| Official Page |
| Project Documentation |
| Download |
|
All reports we have created so far contain simple layouts. In this tutorial, we will cover how to create elaborate layouts, including, among other JasperReports features, adding background images or text to a report, logically grouping report data, conditionally printing report data, and creating subreports.
|
Most of the techniques described in this tutorial are encapsulated in the JRXML template. For this reason, we will not be showing Java code for most examples as it would illustrate nothing we haven't seen before. The code to generate all the reports in this tutorial can be downloaded as part of this tutorial's code, available at [http://www.packtpub.com/files/code/8082_Code.zip http://www.packtpub.com/files/code/8082_Code.zip]. |
[edit] Controlling report-wide layout properties
The <jasperReport> root element of the JRXML template contains a number of attributes that allow us to control report layout. The following table summarizes these attributes:
| Attribute | Description | Valid values | Default values |
|---|---|---|---|
pageWidth
| Determines the width of the page in pixels. | Any non-negative integer. | 595
|
pageHeight
| Determines the height of the page in pixels. | Any non-negative integer. | 842
|
leftMargin
| Determines the left margin of the page in pixels. | Any non-negative integer. | 20
|
rightMargin
| Determines the right margin of the page in pixels. | Any non-negative integer. | 20
|
topMargin
| Determines the top margin of the page in pixels. | Any non-negative integer. | 30
|
bottomMargin
| Determines the bottom margin of the page in pixels. | Any non-negative integer. | 30
|
orientation
| Determines the orientation of the page. | Portrait, Landscape
| Portrait
|
whenNoDataType
| Determines how to create reports with no data in its datasource. | NoPages, BlankPage, AllSectionsNoDetail
| NoPages
|
isTitleNewPage
| Determines if the title section of the report will be printed on a separate page. | true, false
| false
|
isSummaryNewPage
| Determines if the summary section of the report will be printed on a separate page. | true, false
| false
|
Most of the attributes in the table are self-explanatory, and their use should be intuitive. However, the whenNoDataType attribute deserves more explanation.
When there is no data in the report's datasource, by default JasperReports will not generate a report. This happens because the default value of whenNoDataType is BlankPage. Setting whenNoDataType to BlankPage will result in a single blank page report. If we would like a report displaying all sections except the detail section, we can accomplish this by setting whenNoDataType to AllSectionsNoDetail.
[edit] Setting text properties
JasperReports provides several ways to control text properties in the report. We can control the font, whether the text is bold, italic, underlined, its background and foreground colors, and so on.
[edit] Styles
One way JasperReports allows us to control text properties is by using the <style> element. This element allows us to control the foreground and background colors, the style of font (bold, italic, or normal), the font size, a border for the font, and many other attributes. Styles can extend other styles and add to or override properties of the parent style.
The following JRXML template illustrates the use of styles:
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport name="ReportStylesDemo" xmlns=http://jasperreports.sourceforge.net/ jasperreports xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=http://jasperreports .sourceforge.net/jasperreports http:// jasperreports.sourceforge.net/xsd/ jasperreport.xsd"> <style name="parentStyle" isDefault="true" fontName="Times isBold="true" fontSize="13" pdfFontName="Helvetica-Bold"/> <style name="childStyle" fontSize="9"/> <detail> <band height="60"> <staticText> <reportElement x="0" y="0" width="555" height="35" /> <text> <![CDATA[This text uses the default report style, in this report it is called "parentStyle".]]> </text> </staticText> <staticText> <reportElement x="0" y="35" width="555" height="25" style="childStyle"/> <text> <![CDATA[This text uses the style called "childStyle", this style inherits all the properties of it's parents, and overrides only the size.]]> </text> </staticText> </band> </detail> </jasperReport>
There are a few things to note about this example. First, notice the isDefault="true" attribute of the parent style. It makes all the report elements use this style by default without having to explicitly declare it. Because the first <staticText> element does not indicate what style to use, it will use the style named parentStyle by default. The style report used by the elements is defined by the style attribute of the <reportElement> style, as can be seen in the second <staticText> element in this template.
After compiling, filling, and exporting this JRXML template, we should have a report like the following:
The <style> element contains numerous attributes. The complete list of attributes can be found at [http://jasperforge.org/uploads/publish/jasperreportswebsite/JR%20Website/jasperreports_quickref.html#style http://jasperforge.org/uploads/publish/jasperreportswebsite/JR%20Website/jasperreports_quickref.html#style]. Some of the most commonly used style attributes are outlined in the following table:
| Attribute | Description | Valid values |
|---|---|---|
forecolor
| Indicates the text color.
Either a hexadecimal RGB value preceded by the | black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange, pink, red, yellow, white
|
backcolor
| Indicates the text background color. | Refer to the valid values of forecolor above.
|
hAlign
| Indicates the horizontal alignment of the element. | Center, Justified, Left, Right
|
vAlign
| Indicates the vertical alignment of the element. | Bottom, Middle, Top
|
fontName
| Indicates what font to use for the element. | A string indicating the font to be used. |
fontSize
| Indicates the size of the font. | An integer indicating the text size to be used. |
isBold
| Indicates whether the font is bold. | true, false
|
IsItalic
| Indicates whether the font is italic. | true, false
|
IsUnderline
| Indicates whether the font is underlined. | true, false
|
isStrikeThrough
| Indicates whether the font is strikethrough. | true, false
|
lineSpacing
| Determines the spacing between lines of text. A value of 1_1_2 indicates a line and a half of space between lines of text.
| 1_1_2, Double, Single
|
markup
| Allows the element to be styled using HTML snippets, RTF snippets or the JasperReports specific "styled" markup. | none, html, rtf, styled
|
All the attributes that are not specific to textual information (forecolor, backcolor, hAlign, and so on) can be used for any kind of element, not just textual elements. The markup attribute is used to allow segments of the text to be styled using HTML markup, RTF snippets, or using the JasperReports specific <style> XML element. This is covered in detail later in this tutorial.
Reusing styles through style templates
Although adding styles directly to a report template is fairly straightforward, it does have one disadvantage: if we need to add the same style to several reports, then we need to add the style individually to each report. Furthermore, if we need to change a style, then we need to go and modify the style definition in each report template.
To avoid the situation described in the previous paragraph, JasperReports allows us to define styles in a style template. When using a style template, styles can be defined separately from the report template and reused across several reports. Additionally, if we need to modify a style, all we need to do is modify the template, as opposed to having to update each report template individually.
The following JRXML template takes advantage of a style template that defines the text styles used in the report:
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport name="ReportStylesDemo" xmlns=http://jasperreports.sourceforge.net /jasperreports xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=http://jasperreports .sourceforge.net/jasperreports http:// jasperreports.sourceforge.net/xsd /jasperreport.xsd"> <template> http://localhost:8080/jaspertutorialch6/reports/styles.jrtx </template> <detail> <band height="60"> <staticText> <reportElement x="0" y="0" width="555" height="35" /> <text> <![CDATA[This text uses the default report style, in this report it is called "parentStyle".]]> </text> </staticText> <staticText> <reportElement x="0" y="35" width="555" height="25" style="childStyle"/> <text> <![CDATA[This text uses the style called "childStyle", this style inherits all the properties of its parents, and overrides only the size.]]> </text> </staticText> </band> </detail> </jasperReport>
This JRXML template is a slightly modified version of the report template we saw in the previous report. The only difference is that, instead of defining styles in the JRXML template, they are defined in an external report style template. As we can see, we can import an external template by using the <template> tag. The body of this tag must be the URL or the full/relative path to the report template.
Notice how the URL for the style template is absolute, it includes the protocol, host, port, and path. This allows us to "publish" our template in a web server or servlet container and easily reuse it in the future.
The actual style template is shown below:
<?xml version="1.0"?> <!DOCTYPE jasperTemplate PUBLIC "-//JasperReports//DTD Template//EN" "http://jasperreports.sourceforge.net/dtds/jaspertemplate.dtd"> <jasperTemplate> <style name="parentStyle" isDefault="true" fontName="Times" isBold="true" fontSize="13" pdfFontName="Helvetica-Bold"/> <style name="childStyle" style="parentStyle" fontSize="9"/> </jasperTemplate>
Notice how a style template simply contains style definitions just like the ones we used inside a JRXML template. These definitions must be nested inside a <jaspertemplate> tag.
Setting text style for individual report elements
Report styles can be shared among several report elements. JasperReports allows us to set some properties for individual report elements. This can be accomplished by setting attributes in the <textElement> subelement of <staticText> and <textField>. These attributes are outlined in the following table:
| Attribute | Description | Valid values |
|---|---|---|
lineSpacing
| Determines the spacing between lines of text. A value of 1_1_2 indicates a line and a half of space between lines of text.
| 1_1_2, Double, Single
|
rotation
| Indicates the text direction by rotating it 90 degrees in the specified direction. | Left, None, Right
|
textAlignment
| Indicates the horizontal alignment of the text. | Center, Justified, Left, Right
|
markup
| Allows the text to be styled using a markup language such as HTML or RTF. | none, html, rtf, styled
|
The following snippet of a JRXML template illustrates how to use these attributes:
<staticText> <reportElement x="0" y="0" width="555" height="60"/> <textElement lineSpacing="Double" textAlignment="Center" verticalAlignment="Middle"/> <text> <![CDATA[This text is not really important.Its only purpose is to illustrate text style.]]> </text> </staticText>
This snippet would generate text both horizontally and vertically centered using double-spacing.
Notice how the text is double-spaced and vertically and horizontally centered, like we specified in the attributes of the <textElement> JRXML element.
It is worth noting that because <textElement> is a subelement of both
<staticText> and <textField>, the technique described here can be applied to static text as well as to dynamic text coming from a report expression.
|
Use styles to create more maintainable reports In the short run, it is usually faster to set the text properties using the |
Using markup to style text
Like we briefly mentioned in past sections, JasperReports allows us to use markup languages such as HTML and RTF to style report text. The JasperReports specific XML <style> element can also be used to style report text.
Styled text
The text property modification techniques described so far apply the text properties to a complete text element. Sometimes we want certain segments of a text element to have a different style. For example, we might want to emphasize a word by making it bold or italic. JasperReports allows us to do this by using styled text.
As we have seen in previous sections, both the <textElement> and <style> elements contain a markup attribute, and we need to set this attribute to styled to use styled text. When this attribute is set to styled, the text inside a <textField> or <staticText> element is not interpreted as regular text, but as XML instead. The text to be styled needs to be nested between <style> elements to obtain a different style from the rest of the text. This <style> element contains attributes similar to the JRXML <style> element discussed previously.
The following table lists all the attributes available to this <style> element:
| Attribute | Description | Valid values |
|---|---|---|
fontName
| Indicates the font to be used for the element. | A string indicating the font to be used. |
size
| Indicates the size of the font. | An integer indicating the text size to be used. |
isBold
| Indicates whether the font is bold. | true, false
|
IsItalic
| Indicates whether the font is italic. | true, false
|
IsUnderline
| Indicates whether the font is underlined. | true, false
|
isStrikeThrough
| Indicates whether the font is strikethrough. | true, false
|
pdfFontName
| Indicates the name of the font to be used if the report is exported to PDF. | Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique, Helvetica, Helvetica Bold, Helvetica BoldOblique, Helvetica Oblique, Symbol, Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic, ZapfDingbats
|
pdfEncoding
| Indicates the encoding to be used if the report is exported to PDF. | A string indicating the encoding to be used when the report is exported to PDF. |
isPdfEmbedded
| Indicates whether the PDF font should be embedded in the document. | true, false
|
forecolor
| Indicates the color of the text. | See valid values for forecolor in the Styles section of this tutorial.
|
backcolor
| Indicates the background color of the text. | See valid values for backcolor in the Styles section of this tutorial.
|
The following example illustrates how to use the styled value for the markup attribute to style text in a report:
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns= "http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://jasperreports.sourceforge.net /jasperreports http://jasperreports.sourceforge.net/xsd /jasperreport.xsd" name="StyledTextMarkupDemoReport" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="30" bottomMargin="30"> <detail> <band height="50"> <staticText> <reportElement x="0" y="0" width="500" height="48"/> <textElement markup="styled"> <font size="10" fontName="Courier"/> </textElement> <text> <![CDATA[This text is <style isBold="true">styled</style> using the value of <style isItalic="true">styled</style> for the <style forecolor="blue">markup</style> attribute.]]> </text> </staticText> </band> </detail> </jasperReport>
As we can see in the above example, all we need to do is wrap the sections of text we want to style in <style> tags, and then use the appropriate attributes (isBold, isItalic, and so on) to style the text.
This JRXML template will generate a report containing text using the expected font styles.
HTML
In addition to using styled text to set text style, we can use HTML markup for the same purpose.
It allows us to use familiar HTML tags, such as (<code><b></code>), <code><font></code>, and (<code><i></code>) to style our text. The following example illustrates how to do this: <?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns= "http://jasperreports.sourceforge.net /jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://jasperreports.sourceforge.net /jasperreports http://jasperreports.sourceforge.net/xsd /jasperreport.xsd" name="HtmlMarkupDemoReport" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="30" bottomMargin="30"> <detail> <band height="50"> <staticText> <reportElement x="0" y="0" width="500" height="48"/> <textElement markup="html"> <font size="10" fontName="Courier"/> </textElement> <text> <![CDATA[This text is <b>styled</b> using the value of <i>html</i> for the <font color="blue"> markup</font> attribute.]]> </text> </staticText> </band> </detail> </jasperReport>
As we can see, all we need to do is set the value of the markup
attribute of the <textElement> element to "html".
After that, we can use HTML markup in the body of the <text> element,
which then will be rendered as expected in the report.
This JRXML template will generate a report containing text using the expected font styles.
Rich Text Format
The third markup style supported "out of the box" by JasperReports is Rich Text Format, or RTF. RTF is a format that is supported by almost all existing word processors. RTF markup is human readable; JasperReports is able to interpret RTF markup and render text as expected.
The following example illustrates how to format text using RTF:
<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns=
"http://jasperreports.sourceforge.net/jasperreports"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://jasperreports.sourceforge .net/jasperreports
http://jasperreports
.sourceforge.net/xsd/jasperreport.xsd"
name="RtfMarkupDemoReport" pageWidth="595" pageHeight="842"
columnWidth="555"
leftMargin="20" rightMargin="20"
topMargin="30" bottomMargin="30">
<detail>
<band height="50">
<staticText>
<reportElement x="0" y="0" width="500" height="48"/>
<textElement markup="rtf">
<font size="10" fontName="Courier"/>
</textElement>
<text>
{\rtf1\ansi\deff0\adeflang1025
{\fonttbl {\f0\froman\fprq2\fcharset0 Times New Roman;}
{\f1\froman\fprq2\fcharset0 Times New Roman;}
{\f2\fswiss\fprq2\fcharset0 Arial;}
{\f3\fnil\fprq2\fcharset128 AlMothnna;}
{\f4\fnil\fprq1\fcharset128 Courier 10 Pitch;}
{\f5\fmodern\fprq1\fcharset128 Courier New;}
{\f6\fmodern\fprq1\fcharset128 Courier {\*\falt Courier New}; }
{\f7\fnil\fprq2\fcharset0 DejaVu Sans;} }
{\colortbl;\red0\green0\blue0;\red35\green0\blue220;
\red128\green128\blue128;
}
{\stylesheet {\s1\cf0 {\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}
\rtlch\af7\afs24\lang255\ltrch\dbch\af7
\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24 \lang1033\snext1 Normal;
}
{\s2\sb240\sa120\keepn\cf0
{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}
\rtlch\afs28\lang255\ltrch\dbch\langfe255\hich
\f2\fs28\lang1033\loch\f2\fs28\lang1033 \sbasedon1\snext3 Heading;
}
{\s3\sa120\cf0 {\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}
\rtlch\af7\afs24\lang255\ltrch\dbch\af7
\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24
\lang1033\sbasedon1\snext3 Body Text;
}
{\s4\sa120\cf0 {\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}
\rtlch\af7\afs24\lang255\ltrch\dbch\af7
\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24 \lang1033\sbasedon3\snext4 List;
}
{\s5\sb120\sa120\cf0 {\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}
\rtlch\af7\afs24\lang255\ai\ltrch\dbch\af7
\langfe255\hich\f0\fs24\lang1033\i\loch\f0\fs24 \lang1033\i\sbasedon1\snext5 caption;
}
{\s6\cf0 {\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}
\rtlch\af7\afs24\lang255\ltrch\dbch\af7
\langfe255\hich\f0\fs24\lang1033\loch\f0\fs24 \lang1033\sbasedon1\snext6 Index;
}
}
{\info {\creatim\yr2009\mo3\dy29\hr17\min23}
{\revtim\yr0\mo0\dy0\hr0\min0}
{\printim\yr0\mo0\dy0\hr0\min0} {\comment StarWriter} {\vern3000} }
\deftab709 {\*\pgdsctbl {\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840
\marglsxn1134\margrsxn1134\margtsxn1134 \margbsxn1134\pgdscnxt0 Standard;
}
}
\paperh15840\paperw12240\margl1134\margr1134
\margt1134\margb1134\sectd\sbknone\pgwsxn12240
\pghsxn15840\marglsxn1134\margrsxn1134
\margtsxn1134\margbsxn1134\ftnbj\ftnstart1
\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1
\aftnnrlc\pard\plain\ltrpar\s1\cf0
{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}
\rtlch\af7\afs22\lang255\ltrch\dbch\af7\langfe255
\hich\f6\fs22\lang1033\loch\f6\fs22\lang1033 {
\rtlch \ltrch\loch\f6\fs22\lang1033\i0\b0 This text is
{\rtlch\ltrch\dbch\hich\b\loch\b styled}
using the value of {\rtlch\ltrch\dbch\hich\i\loch\i rtf}
for the {\cf2 markup} attribute. }
\par }
</text>
</staticText>
</band>
</detail>
</jasperReport>
The highlighted code is the RTF markup. When the report is rendered, the text inside the <textElement> and <text> elements will be rendered using the correct style.
[edit] Setting a report's background
Reports can have elements that appear in the report background, behind all other report elements. We can add any report element to the background by using the JRXML <background> element. The following JRXML template demonstrates how to do this:
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge .net/jasperreports http://jasperreports.sourceforge .net/xsd/jasperreport.xsd" name="BackgroundDemoReport" > <style name="centeredText" hAlign="Center" vAlign="Middle" /> <style name="boldCentered" style="centeredText" isBold="true" /> <style name="backgroundStyle" style="boldCentered" fontName="Helvetica" pdfFontName="Helvetica-Bold" forecolor="lightGray" fontSize="90"/> <background> <band height="782"> <staticText> <reportElement x="0" y="0" width="555" height="782" style="backgroundStyle" mode="Transparent" /> <textElement rotation="None"/> <text> <![CDATA[SAMPLE]]> </text> </staticText> </band> </background> <title> <band height="60"> <staticText> <reportElement x="0" y="0" width="555" height="60" style="boldCentered" /> <text> <![CDATA[Report Background Demo]]> </text> </staticText> </band> </title> <detail> <band height="600"> <staticText> <reportElement x="0" y="300" width="555" height="60" mode="Transparent" style="centeredText" /> <text> <![CDATA[This report demonstrates how to set the report background.]]> </text> </staticText> </band> </detail> </jasperReport>
The JRXML <background> element highlighted in this JRXML template just like all other JRXML elements that create a report section, contains a single <band> element as its only subelement. The <background> element is different from other section elements because it is designed to span a complete page, with its contents shown behind all other report elements. It is worth noting that, in order to allow report backgrounds to display correctly, the mode attribute of other report sections must be set to Transparent.
After compiling the last JRXML template and filling the resulting Jasper template, we should obtain a report like the following:
Notice how the background text appears to be behind the text in the <band> element.
[edit] Report expressions
Using report expressions, another feature of JasperReports, we can display calculated data on a report. Calculated data is the data that is not static and not specifically passed as a report parameter or a datasource field.
Report expressions are built from combining report parameters, fields, and static data. By default, report expressions can be built using the Java language, but JasperReports can support any other language supported by the JVM. The JasperReports project file includes examples of using BeanShell and Groovy to build report expressions.
We have already seen simple report expressions in the form of report parameters and fields. We can use any valid Java language expression that returns a string or a numeric value as report expressions. For example, we can concatenate strings or call any method in a report expression. The following JRXML template demonstrates these concepts:
<?xml version="1.0" encoding="UTF-8" ?>
<jasperReport xmlns=
"http://jasperreports.sourceforge.net/jasperreports"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jasperreports.sourceforge
.net/jasperreports http://jasperreports
.sourceforge.net/xsd/jasperreport.xsd"
name="ReportExpressionsDemo">
<queryString>
<![CDATA[SELECT (select count(*) from aircraft_models
am where am.aircraft_type_id = 4) AS fixed_wing_single_engine_cnt,
(select count(*) from aircraft_models am where am.aircraft_type_id = 5)
AS fixed_wing_multiple_engine_cnt,(select count(*)
from aircraft_models am where am.aircraft_type_id = 6)
AS rotorcraft_cnt]]>
</queryString>
<field name="fixed_wing_single_engine_cnt" class="java.lang.Integer" />
<field name="fixed_wing_multiple_engine_cnt"
class="java.lang.Integer" />
<field name="rotorcraft_cnt" class="java.lang.Integer" />
<detail>
<band height="100">
<textField>
<reportElement x="20" y="0" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Fixed Wing Single Engine Aircraft Models:
" + $F{fixed_wing_single_engine_cnt}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="20" y="20" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Fixed Wing Multiple Engine Aircraft " + "Models:" + $F{fixed_wing_multiple_engine_cnt}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="20" y="40" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Fixed Wing Aircraft Models:
" + ($F{fixed_wing_single_engine_cnt}.intValue() +
$F{fixed_wing_multiple_engine_cnt}.intValue())]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="20" y="60" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Rotorcraft Aircraft Models: " +
$F{rotorcraft_cnt}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="20" y="80" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Aircraft Models Reported: " +
($F{fixed_wing_single_engine_cnt}.intValue() +
$F{fixed_wing_multiple_engine_cnt}.intValue() +
$F{rotorcraft_cnt}.intValue())]]>
</textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
This JRXML generates a report on the total number of fixed-wing single engine, fixed-wing multiple engine, and rotorcraft aircraft in the flightstats database. It then calculates the total number of fixed-wing aircraft in the database by adding the first two fields. Lastly, it calculates the total number of aircraft reported by adding all three fields.
The following servlet generates a PDF report from the jasper file generated by the previous JRXML template and directs it to the browser:
package net.ensode.jaspertutorial;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JasperRunManager;
public class ReportExpressionsDemoServlet extends HttpServlet
{
protected void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException
{
Connection connection;
ServletOutputStream servletOutputStream = response .getOutputStream();
InputStream reportStream =
getServletConfig().getServletContext() .getResourceAsStream("/reports /ReportExpressionsDemo.jasper");
try
{
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection
("jdbc:mysql: //localhost:3306/flightstats? user=dbuser&password=secret");
JasperRunManager.runReportToPdfStream(reportStream,
servletOutputStream, new HashMap(), connection);
connection.close();
response.setContentType("application/pdf");
servletOutputStream.flush();
servletOutputStream.close();
}
catch (Exception e)
{
// display stack trace in the browser
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
response.setContentType("text/plain");
response.getOutputStream().print(stringWriter.toString());
}
}
}
In the above code, there is nothing that we haven't seen before. The logic to add report expressions is encapsulated in the JRXML template.
After deploying this servlet and directing the browser to its URL, we should see a report similar to the following:
[edit] Adding multiple columns to a report
JasperReports allows us to generate reports with multiple columns. Reports we have seen so far seem to have multiple columns. For example, the report we created in the previous section has a column for model, another column for tail number, and one more for serial number. However, all three of these fields are laid out in a single <band> element.
When we add multiple columns to a report, we should think of the data inside a band as a cell, regardless of how the data is laid out inside that band.
The flightstats database we used for the examples in Tutorial 4, Creating Dynamic Reports from Databases, contains the country, state, and city where an aircraft is registered. Let's create a report displaying the tail number of all aircraft registered in the state of New York in the United States. Our report will display the data in three columns. The following JRXML template will generate a report with the desired layout:
<?xml version="1.0" encoding="UTF-8" ?>
<jasperReport xmlns=
"http://jasperreports.sourceforge.net/jasperreports"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://jasperreports.sourceforge.net /jasperreports
http://jasperreports.sourceforge.net/xsd /jasperreport.xsd"
name="MultipleColumnDemo"
columnCount="3"
columnWidth="180">
<queryString>
<![CDATA[select a.tail_num from aircraft a where a.country = 'US'
and a.state = 'NY' order by a.tail_num]]>
</queryString>
<field name="tail_num" class="java.lang.String" />
<columnHeader>
<band height="20">
<staticText>
<reportElement x="0" y="0" height="20" width="84" />
<text>Tail Number</text>
</staticText>
</band>
</columnHeader>
<detail>
<band height="20">
<textField>
<reportElement x="0" y="0" height="20" width="84" />
<textFieldExpression>
<![CDATA[$F{tail_num}]]>
</textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
As we can see in this JRXML template, the number of columns and the column width are specified by the columnCount and columnWidth attributes of the <jasperReport> root element.
As can be seen in the last example, we can define a column header to be displayed at the top of every column. This can be accomplished by the <columnHeader> JRXML element. We can also choose to display a column footer at the bottom of every column by adding a <columnFooter> element to our JRXML template (not shown in the example). Just like all the other JRXML templates defining report sections, <columnHeader> and <columnFooter> contain a single <band> element as their only child element. This <band> element can contain report fields, static text, images, graphs, or anything else we can display in any of the other report sections.
The following servlet will generate a PDF report from the jasper file generated from the last JRXML template and direct it to the browser:
package net.ensode.jaspertutorial;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JasperRunManager;
public class MultipleColumnDemoServlet extends HttpServlet
{
protected void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException
{
Connection connection;
ServletOutputStream servletOutputStream = response .getOutputStream();
InputStream reportStream = getServletConfig().getServletContext()
.getResourceAsStream("/reports/MultipleColumnDemo.jasper");
try
{
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection
("jdbc:mysql: //localhost:3306/flightstats"
+ "?user=dbuser&password=secret");
JasperRunManager.runReportToPdfStream
(reportStream, servletOutputStream, new HashMap(), connection);
connection.close();
response.setContentType("application/pdf");
servletOutputStream.flush();
servletOutputStream.close();
}
catch (Exception e)
{
// display stack trace in the browser
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
response.setContentType("text/plain");
response.getOutputStream().print(stringWriter.toString());
}
}
}
There is nothing we haven't seen before in this servlet. The logic for multiple-column data is encapsulated in the JRXML. After deploying this servlet and directing the browser to its URL, we should see a report like the following:
As we can see, the data is displayed in three columns. This way, we can create the whole report using about one-third of the pages we would have had to use with one column. Please note that each column would show all the report elements defined inside the <band> element in the <detail> section of the report template. In this particular example, we have a single text field corresponding to each aircraft's tail number. If we would have defined additional report elements (for example, two more text fields for the aircraft model and serial number), each of these fields would be displayed in a single column. Adjusting the width of the column would be necessary to accommodate the additional data.
[edit] Final notes about report columns
There are a few more things we should know about report columns before we move on. Because these features are fairly straightforward, we decided not to show any examples. However, we should be aware of them.
Report columns by default have no space between them. (In the last report, the columns are wider than the displayed tail number. There is a lot of whitespace inside the columns.) We can change this default behavior by using the columnSpacing attribute of the root <jasperReport> element of the JRXML template.
By default, report columns are filled vertically, which means the first column is filled to completion first, then the second, then the third, and so on. If we want to fill the columns by row, that is, fill the first row first , then the second row, and so on, we can achieve this by setting the printOrder attribute of the root <jasperReport> element to Horizontal.
Column footers by default are printed at the bottom of the page. If a report column does not have enough data to fill a page, there will be some blank space between the end of the column and the column footer. If we want the column footer to be printed right after the end of the column, we can do it by setting the isFloatColumnFooter attribute of the <jasperReport> element to true.
[edit] Grouping report data
JasperReports allows us to group report data in a logical manner. For example, if we were creating a report about ford ka parts, we could group the data by ford ka parts make and/or model. If we were creating a report about sales figures, we could group the report data by geographical area.
The flightstats database we used for the examples in Tutorial 4, Creating Dynamic Reports from Databases, contains the country, state, and city where an aircraft is registered. Let's create a report displaying aircraft data registered in any state starting with the letter "A" in the United States. We will group the report data by state abbreviation. The JRXML template for the report is as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<jasperReport xmlns=
"http://jasperreports.sourceforge.net/jasperreports"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=
"http://jasperreports.sourceforge
.net/jasperreports
http://jasperreports .sourceforge.net/xsd/jasperreport.xsd"
name="DataGroupingDemo">
<queryString>
<![CDATA[select a.tail_num, a.aircraft_serial, am.model,
a.state from aircraft a, aircraft_models am
where a.aircraft_model_code = am.aircraft_model_code and a.country = US'
and state like A%' order by state, model]]>
</queryString>
<field name="tail_num" class="java.lang.String" />
<field name="aircraft_serial" class="java.lang.String" />
<field name="model" class="java.lang.String" />
<field name="state" class="java.lang.String" />
<group name="StateGroup">
<groupExpression>
<![CDATA[$F{state}]]>
</groupExpression>
<groupHeader>
<band height="40">
<staticText>
<reportElement x="0" y="10" width="115" height="20" />
<textElement>
<font isBold="true" />
</textElement>
<text>Aircraft Registered In:</text>
</staticText>
<textField>
<reportElement x="116" y="10" width="20" height="20" />
<textFieldExpression>$F{state}</textFieldExpression>
</textField>
</band>
</groupHeader>
<groupFooter>
<band height="40">
<staticText>
<reportElement x="0" y="10" width="140" height="20" />
<textElement>
<font isBold="true" />
</textElement>
<text>End Aircraft Registered In:</text>
</staticText>
<textField>
<reportElement x="141" y="10" width="20" height="20" />
<textFieldExpression>$F{state}</textFieldExpression>
</textField>
</band>
</groupFooter>
</group>
<detail>
<band height="20">
<staticText>
<reportElement x="20" y="0" height="20" width="35" />
<text>Model:</text>
</staticText>
<textField>
<reportElement x="56" y="0" height="20" width="164" />
<textFieldExpression>
<![CDATA[$F{model}]]>
</textFieldExpression>
</textField>
<staticText>
<reportElement x="220" y="0" height="20" width="65" />
<text>Tail Number:</text>
</staticText>
<textField>
<reportElement x="286" y="0" height="20" width="84" />
<textFieldExpression>
<![CDATA[$F{tail_num}]]>
</textFieldExpression>
</textField>
<staticText>
<reportElement x="380" y="0" height="20" width="75" />
<text>Serial Number:</text>
</staticText>
<textField>
<reportElement x="456" y="0" height="20" width="94" />
<textFieldExpression>
<![CDATA[$F{aircraft_serial}]]>
</textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
As can be seen in this example, a group is defined by the <group> element. The <group> element must contain a name attribute defining the group's name. A group must also contain a <groupExpression> subelement. This subelement indicates the data that must change to start a new data group. In this example, every time the state changes, we begin a new data grouping.
A group can optionally contain either a group header or a group footer. They are useful to place labels at the beginning and end of the grouped data. The group header and footer contain a single <band> element as their only child element. This is a regular <band> element. We can place any report element in it according to our wish, just as if it were inside any of the other report sections (title, page header, column header, detail, and so on). In the example just discussed, we chose to place some static text and report fields identifying the state to which the aircraft in the group are registered.
The servlet to generate a PDF report is virtually identical to the one we saw in the previous section, the only difference being the location of the jasper template. After deploying this servlet and directing the browser to its URL, we should see a report like the following:
We chose to display the third page on the screenshot to illustrate the group header and footer.
The <group> element contains attributes that allow us to control the layout of the group data. The following table summarizes these attributes:
| Attribute | Description |
|---|---|
isStartNewPage
| When set to true, each data group will begin on a new page.
|
isStartNewColumn
| When set to true, each data group will begin in a new column.
|
isReprintHeaderOnEachPage
| When set to true, the group header will be reprinted on every page.
|
isResetPageNumber
| When set to true, the report page number will be reset every time a new group starts.
|
Each of the attributes described in the table above default to false.
[edit] Report variables
When we wrote the report in the Report Expressions section, we had to type the following expression twice:
<code>$F{fixed_wing_single_engine_cnt}.intValue()
+ $F{fixed_wing_multiple_engine_cnt}.intValue())</code>
This expression was typed once to calculate the number of fixed-wing aircraft reported, and again to calculate the total number of aircraft reported. This duplication is not a good thing because, if we need to change the expression for any reason, we would have to do it twice. JasperReports allows us to assign report expressions to a variable, eliminating the need to type the expression multiple times. The following JRXML template is a modified version of the one we wrote in that section, this version takes advantage of report variables to eliminate the duplicate expression.
<?xml version="1.0" encoding="UTF-8" ?>
<jasperReport xmlns=
"http://jasperreports.sourceforge.net/jasperreports"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://jasperreports
.sourceforge.net/jasperreports
http://jasperreports .sourceforge.net/xsd/jasperreport.xsd"
name="ReportVariablesDemo">
<queryString>
<![CDATA[SELECT (select count(*)
from aircraft_models am where am.aircraft_type_id = 4)
AS fixed_wing_single_engine_cnt,
(select count(*)
from aircraft_models am where am.aircraft_type_id = 5)
AS fixed_wing_multiple_engine_cnt,
(select count(*) from aircraft_models am where
am.aircraft_type_id = 6) AS rotorcraft_cnt]]>
</queryString>
<field name="fixed_wing_single_engine_cnt"
class="java.lang.Integer" />
<field name="fixed_wing_multiple_engine_cnt"
class="java.lang.Integer" />
<field name="rotorcraft_cnt" class="java.lang.Integer" />
<variable name="fixed_wing_engine_cnt" class="java.lang.Integer">
<variableExpression>
<![CDATA[new Integer ($F{fixed_wing_single_engine_cnt}.intValue() + $F{fixed_wing_multiple_engine_cnt}.intValue())]]>
</variableExpression>
</variable>
<detail>
<band height="100">
<textField>
<reportElement x="20" y="0" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Fixed Wing Single Engine Aircraft Models:
" + $F{fixed_wing_single_engine_cnt}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="20" y="20" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Fixed Wing Multiple Engine Aircraft "
+ "Models: " + $F{fixed_wing_multiple_engine_cnt}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="20" y="40" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Fixed Wing Aircraft Models:
" + $V{fixed_wing_engine_cnt}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="20" y="60" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Rotorcraft Aircraft Models:
" + $F{rotorcraft_cnt}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="20" y="80" height="20" width="500" />
<textFieldExpression>
<![CDATA["Total Aircraft Models Reported:
" + ($V{fixed_wing_engine_cnt}.intValue()
+ $F{rotorcraft_cnt}.intValue())]]>
</textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
As can be seen in the above example, report expressions can be assigned to a variable by using the <variable> element in a JRXML file. We give the variable a name by using the name attribute of the <variable> field. The actual expression we want to assign to a variable must be enclosed inside a <variableExpression> element. Variable values can be accessed in other report expressions by using the $V{variable_name} notation, where variable_name is the name we gave the variable by using the name attribute within the <variable> element.
Output for the above example is identical to the output of the example given in the Report Expressions section.
The JRXML <variable> element contains a number of attributes, which are summarized in the following table:
| Attribute | Description | Valid values | Default value |
|---|---|---|---|
Name
| Sets the variable name.
| Any valid XML attribute value. | N/A |
Class
| Sets the variable class.
| Any Java class available in the CLASSPATH. | java.lang.String
|
calculation
| Determines what calculation to perform on the variable when filling the report.
| Variance variable value is the variance of all non-null values matching the report expression.
| Nothing
|
incrementGroup
| Determines the name of the group at which the variable value is recalculated, when incrementType is Group.
| The name of any group declared in the JRXML report template. | N/A |
resetType
| Determines when the value of a variable is reset.
| Report the variable value is recalculated once at the beginning of the report.
| Report
|
resetGroup
| Determines the name of the group where the variable value is reset, when resetType is Group.
| The name of any group declared in the JRXML report template. | N/A |
As can be inferred from the table, JasperReports variables can be used not only to simplify report expressions, but also to perform calculations and display the result of those calculations on the report.
Let's modify the report that we developed in the previous section so that it displays the total number of aircraft in each state. To accomplish this, we need to create a report variable and set its calculation attribute to Count. The following JRXML template illustrates this concept:
<?xml version="1.0" encoding="UTF-8" ?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jasperreports.sourceforge
.net/jasperreports http://jasperreports.sourceforge
.net/xsd/jasperreport.xsd"
name="VariableCalculationDemo">
<queryString>
<![CDATA[select a.tail_num, a.aircraft_serial,
am.model, a.state from aircraft a, aircraft_models
am where a.aircraft_model_code = am.aircraft_model_code
and a.country = US' and state like A%' order by state, model]]>
</queryString>
<field name="tail_num" class="java.lang.String" />
<field name="aircraft_serial" class="java.lang.String" />
<field name="model" class="java.lang.String" />
<field name="state" class="java.lang.String" />
<variable name="aircraft_count"
class="java.lang.Integer" calculation="Count"
resetType="Group" resetGroup="StateGroup">
<variableExpression>
<![CDATA[$F{aircraft_serial}]]>
</variableExpression>
<initialValueExpression>
<![CDATA[new java.lang.Integer(0)]]> </initialValueExpression>
</variable>
<group name="StateGroup">
<groupExpression>
<![CDATA[$F{state}]]>
</groupExpression>
<groupHeader>
<band height="40">
<staticText>
<reportElement x="0" y="10" width="115" height="20" />
<textElement>
<font isBold="true" />
</textElement>
<text>Aircraft Registered In:</text>
</staticText>
<textField>
<reportElement x="116" y="10" width="20" height="20" />
<textFieldExpression>$F{state}</textFieldExpression>
</textField>
</band>
</groupHeader>
<groupFooter>
<band height="40">
<textField>
<reportElement x="0" y="10" width="325" height="20" />
<textFieldExpression>
<![CDATA["Total Number Of Aircraft Registered In " + $F{state} + ": " + $V{aircraft_count}]]>
</textFieldExpression>
</textField>
</band>
</groupFooter>
</group>
<detail>
<band height="20">
<staticText>
<reportElement x="20" y="0" height="20" width="35" />
<text>Model:</text>
</staticText>
<textField>
<reportElement x="56" y="0" height="20" width="164" />
<textFieldExpression>
<![CDATA[$F{model}]]>
</textFieldExpression>
</textField>
<staticText>
<reportElement x="220" y="0" height="20" width="65" />
<text>Tail Number:</text>
</staticText>
<textField>
<reportElement x="286" y="0" height="20" width="84" />
<textFieldExpression>
<![CDATA[$F{tail_num}]]>
</textFieldExpression>
</textField>
<staticText>
<reportElement x="380" y="0" height="20" width="75" />
<text>Serial Number:</text>
</staticText>
<textField>
<reportElement x="456" y="0" height="20" width="94" />
<textFieldExpression>
<![CDATA[$F{aircraft_serial}]]>
</textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
In this report template, setting the calculation attribute of the <variable> field to Count allowed us to obtain the number of aircraft in each state. By setting the report expression to $F{aircraft_serial}, each time a serial number is displayed in the report, the variable value is increased by one. Setting the resetType attribute to Group allows us to reset the variable value to its initial value, which in turn is set by the <initialValueExpression> field.
The code for the servlet that fills and exports the jasper file generated by this JRXML has nothing we haven't seen before and, therefore, it is not shown. After directing the browser to its URL, we should see a report similar to the following:
The same concepts we saw here can be applied to the other calculation values and reset types.
[edit] Built-in report variables
JasperReports has a number of built-in report variables that we can use in our reports without having to declare them. They are listed and described in the following table:
| Built-In Variable | Description |
|---|---|
PAGE_COUNT
| Contains the total number of pages in the report. |
PAGE_NUMBER
| Contains the current page number. |
COLUMN_COUNT
| Contains the total number of columns in the report. |
COLUMN_NUMBER
| Contains the current column number. |
REPORT_COUNT
| Contains the total number of records in the report. |
NameOfGroup_COUNT
| Contains the total number of records in the group named NameOfGroup. The exact report variable name will match the group name in the report; for example, for a group named MyGroup, the variable name will be MyGroup_COUNT.
|
[edit] Stretching text fields to accommodate data
By default, <textField> elements have a fixed size. If the data they need to display does not fit in their defined size, it is simply not displayed in the report. This is rarely the behavior we would want. Luckily, JasperReports allows us to alter this default behavior. This is accomplished by setting the isStretchWithOverflow attribute of the <textField> element to true.
The following JRXML template demonstrates how to allow text fields to stretch so that they can accommodate large amounts of data:
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge .net/jasperreports http://jasperreports.sourceforge .net/xsd/jasperreport.xsd" name="TextFieldStretchDemo"> <field name="lots_of_data" class="java.lang.String" /> <detail> <band height="30">
<textField isStretchWithOverflow="true">
<reportElement x="0" y="0" width="100" height="24" />
<textFieldExpression class="java.lang.String">
<![CDATA[$F{lots_of_data}]]>
</textFieldExpression>
</textField>
</band> </detail> </jasperReport>
The following servlet fills the jasper template generated from the above JRXML and directs the generated report to the browser window in PDF format:
package net.ensode.jaspertutorial;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.data.JRMapCollectionDataSource;
public class TextFieldStretchDemoServlet extends HttpServlet
{
private JRDataSource createReportDataSource()
{
JRMapCollectionDataSource dataSource;
Collection reportRows = initializeMapCollection();
dataSource = new JRMapCollectionDataSource(reportRows);
return dataSource;
}
private Collection initializeMapCollection()
{
ArrayList reportRows = new ArrayList();
HashMap datasourceMap = new HashMap();
datasourceMap.put("lots_of_data", "This element contains so much data, " + "there is no way it will ever fit in the text field without it stretching.");
reportRows.add(datasourceMap);
return reportRows;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
ServletOutputStream servletOutputStream = response.getOutputStream();
InputStream reportStream = getServletConfig().getServletContext() .getResourceAsStream("/reports/TextFieldStretchDemo.jasper");
try
{
JRDataSource dataSource = createReportDataSource();
JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, new HashMap(), dataSource);
response.setContentType("application/pdf");
servletOutputStream.flush();
servletOutputStream.close();
}
catch (Exception e)
{
// display stack trace in the browser
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
response.setContentType("text/plain");
response.getOutputStream().print(stringWriter.toString());
}
}
}
We should see a report like the following after directing the browser to this servlet's URL:
When a <textField> element stretches to accommodate its data, its parent <band> element stretches accordingly. When a <band> element stretches due to one of its child <textField> elements stretching, JasperReports allows us to control how other child elements of the <band> element will be positioned when the band stretches. This will be discussed in detail in the next section.
[edit] Laying out report elements
As we saw in Tutorial 3, Creating your First Report, a report can contain the following sections: a report title, a page header, a page footer, a column header, a column footer, a detail section, a report summary, and a last page footer. These sections are defined by the <title>, <pageHeader>, <pageFooter>, <columnHeader>, <columnFooter>, <detail>, <summary>, and <lastPageFooter> JRXML elements, respectively.
Each of these elements contains a single <band> element as its only subelement. The <band> element can contain zero or more <line>, <rectangle>, <ellipse>, <image>, <staticText>, <textField>, <subReport>, or <elementGroup> subelements. Except for <elementGroup>, each of these elements must contain a single <reportElement> as its first element. The <reportElement> subelement determines how data is laid out for that particular element. In this section, we will see how the different attributes of <reportElement> affect the way data is laid out in its parent element.
The following table summarizes all the attributes of <reportElement>:
| Attribute | Description | Valid values |
|---|---|---|
x
| Specifies the x coordinate of the element within the band. | An integer value indicating the x coordinate of the element in pixels. This attribute is required. |
y
| Specifies the y coordinate of the element within the band. | An integer value indicating the y coordinate of the element in pixels. This attribute is required. |
width
| Specifies the width of the element. | An integer value indicating the element width in pixels. This attribute is required. |
height
| Specifies the height of the element. | An integer value indicating the element height in pixels. This attribute is required. |
| Attribute | Description | Valid values |
key
| Uniquely identifies the element within the band and does not affect layout. | A unique string used to identify the containing element. |
stretchType
| Specifies how the element stretches when the containing band stretches.
| RelativeToBand the element will stretch to fit the band's height.
|
positionType
| Specifies the element's position when the band stretches.
| FixRelativeToBottom the element will maintain a fixed position relative to the band's bottom.
|
isPrintRepeatedValues
| Specifies if repeated values are printed.
| false repeated values will not be printed.
|
mode
| Specifies the background mode of the element. | Opaque, Transparent
|
isRemoveLineWhenBlank
| Specifies whether the element should be removed when it is blank and there are no other elements in the same horizontal space. | true, false
|
| Attribute | Description | Valid values |
isPrintInFirstWholeBand
| Specifies whether the element must be printed in a whole band, which is aband that is not divided between report pages or columns. | true, false
|
isPrintWhenDetailOverFlows
| Specifies whether the element will be printed when the band overflows to a new page or column. | true, false
|
printWhenGroupChanges
| Specifies that the element will be printed when the specified group changes. | A string corresponding to the group that must change for the element to be printed. |
forecolor
| Specifies the foreground color of the element.
Either a hexadecimal RGB value preceded by the
| |
backcolor
| Specifies the background color of the element. | Refer to the valid values of forecolor above.
|
Most of the <reportElement> attributes described in the table are self-explanatory. We will discuss some of them in the next few sections.
[edit] Setting the size and position of a report element
The x and y attributes of <reportElement> specify the x and y coordinates (in pixels) of the element within the band. A common mistake in the beginning is to assume that the x and y coordinates defined here are absolute for the page. Again, the x and y coordinates defined by the x and y attributes are relative to the <band> where the element is contained. Coordinates (0, 0) are at the top left of the band. The x and y attributes of <reportElement> are required.
The width and height elements of <reportElement>, unsurprisingly, define the width and height (in pixels) of the element, respectively. The width and height attributes of <reportElement> are required. We have already seen several examples demonstrating the use of the x, y, width, and height elements of <reportElement>. Here is the JRXML template for the report we created in Tutorial 3, Creating your First Report:
<?xml version="1.0"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge .net/jasperreports http://jasperreports .sourceforge.net/xsd/jasperreport.xsd" name="FirstReport"> <detail> <band height="20"> <staticText>
<reportElement x="20" y="0" width="200" height="20"/>
<text> <![CDATA[If you don't see this, it didn't work]]> </text> </staticText> </band> </detail> </jasperReport>
In this example, the static text will appear 20 pixels from the left margin, aligned with the top of the band. Refer to Tutorial 3 to see a rendered report based on this template.
The positionType attribute defines the element's position when the band is stretched. As can be seen in the previous table, there are three legal values for this attribute: Float, FixRelativeToTop, and FixRelativeToBottom. Let's modify the example we discussed in the Stretching text fields to accommodate data section by adding some static text right under the existing text field. We will see the effect of the different positionType values on its positioning.
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge .net/jasperreports http://jasperreports.sourceforge .net/xsd/jasperreport.xsd" name="TextFieldStretchDemo"> <field name="lots_of_data" class="java.lang.String" /> <detail> <band height="55"> <textField isStretchWithOverflow="true"> <reportElement x="0" y="0" width="100" height="24" /> <textFieldExpression class="java.lang.String"> <![CDATA[$F{lots_of_data}]]> </textFieldExpression> </textField>
<staticText>
<reportElement width="500" y="25" x="0" height="30" positionType="FixRelativeToTop" />
<box>
<pen lineWidth="1"/>
</box>
<text>
<![CDATA[This staticText element has a default positionType of "FixRelativeToTop"]]>
</text>
</staticText>
</band> </detail> </jasperReport>
The <textField> element in the JRXML template has a y position of zero and a height of 24 pixels. We positioned the new <staticText> element to have a y position of 25, just below the text field.
Notice the <box> element we added to the <textField> and <staticText> elements. This <box> field allows us to display a border around the elements, making very clear where the element starts and ends. We chose to do this to be able to easily see the position of the elements within the report.
Again, the code to fill and export the report shows nothing we haven't seen before; therefore, we chose not to display it. The generated report should look like the following:
As the FixRelativeToTop value of the positionType attribute of <reportElement> forces the element to stay in the same position whether or not any other element stretches. We ended up with the two elements overlapping each other, that is probably not what we want.
It would be nice if the <staticText> element could be pushed down in case the <textField> element stretches. We can accomplish this by setting positionType to Float.
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge .net/jasperreports http://jasperreports.sourceforge .net/xsd/jasperreport.xsd" name="TextFieldStretchDemo"> <field name="lots_of_data" class="java.lang.String" /> <detail> <band height="55"> <textField isStretchWithOverflow="true"> <reportElement x="0" y="0" width="100" height="24" /> <textFieldExpression class="java.lang.String"> <![CDATA[$F{lots_of_data}]]> </textFieldExpression> </textField>
<staticText>
<reportElement width="500" y="25" x="0" height="30" positionType="Float" />
<box>
<pen lineWidth="1"/>
</box>
<text>
<![CDATA[This staticText element has a default positionType of "Float"]]>
</text>
</staticText>
</band> </detail> </jasperReport>
After compiling, filling, and exporting this JRXML template, we should get a report that looks like this:
As we can see, setting the positionType attribute of <reportElement> to Float made JasperReports ignore the y position of the <staticText> element, which was "pushed" down by the stretched <textField> element.
The third possible value for positionType is FixRelativeToBottom. This value is similar to FixRelativeToTop, with the only difference being that the element keeps its position relative to the bottom of the band as opposed to its top.
When an element of a band stretches, it is possible to control not only the position but also the size of the elements inside the band. This is accomplished by the stretchType attribute of <reportElement> element. The following example demonstrates how we can set a report element to stretch in order to match the tallest element in its group:
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport xmlns="http://jasperreports.sourceforge.net /jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net /jasperreports http://jasperreports.sourceforge.net/xsd /jasperreport.xsd" name="RelativeToTallestObjectDemo"> <field name="lots_of_data" class="java.lang.String" /> <detail> <band height="50">
<elementGroup>
<textField isStretchWithOverflow="true">
<reportElement x="0" y="0" width="100" height="24" />
<box>
<pen lineWidth="1"/>
</box>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{lots_of_data}]]>
</textFieldExpression>
</textField>
<textField isStretchWithOverflow="true">
<reportElement x="101" y="0" width="150" height="24" />
<box>
<pen lineWidth="1"/>
</box>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{lots_of_data}]]>
</textFieldExpression>
</textField>
<staticText>
<reportElement width="300" y="0" x="252" height="24" stretchType="RelativeToTallestObject" />
<box>
<pen lineWidth="1"/>
</box>
<text>
<![CDATA[staticText element stretchType is "RelativeToTallestObject"]]>
</text>
</staticText>
<staticText>
<reportElement width="250" y="25" x="0" height="24" positionType="Float" />
<box>
<pen lineWidth="1"/>
</box>
<text>
<![CDATA[This text is here to stretch the band a bit more.]]>
</text>
</staticText>
</elementGroup>
</band> </detail> </jasperReport>
After compiling the above JRXML template and filling the resulting jasper template, we should see a report like the following:
Once again, we decided to display borders around every element to demarcate the boundaries of an element. As we can see in the screenshot, the static text stretched to match the height of the tallest object. This is because we set the value of the stretchType property of <reportElement> to be RelativeToTallestObject.
Notice the <elementGroup> element in this JRXML template. The purpose of this element is to group elements together so that we can control the behavior of report elements better when one of them stretches. The stretchType property RelativeToTallestObject will stretch the appropriate element to match the height of the tallest object in the element's group. All elements between <elementGroup> and </elementGroup> are in the same group. The <elementGroup> element can have other nested <elementGroup> elements. If no <elementGroup> element is defined inside a <band>, then all elements inside the band are considered to be in the same group.
[edit] Setting common element properties
JasperReports 1.1 introduced a new report element, the <frame> element, allowing us to group elements together and give them a common look. For example, we can set the background color of the frame, and it will be inherited across all the elements contained within the frame. Frames also provide a straightforward way of placing a border around multiple report elements. The following JRXML template is a new version of the example in the previous section. It has been modified to illustrate the use of frames.
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://jasperreports.sourceforge .net/jasperreports http://jasperreports.sourceforge .net/xsd/jasperreport.xsd" name="FrameDemo"> <field name="lots_of_data" class="java.lang.String" /> <detail> <band height="60">
<frame>
<reportElement x="0" y="0" width="555" height="60" mode="Opaque" backcolor="lightGray" />
<box padding="1">
<pen lineStyle="Dotted" lineWidth="1"/>
</box>
<textField isStretchWithOverflow="true">
<reportElement x="0" y="0" width="100" height="24" />
<box>
<pen lineWidth="1"/>
</box>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{lots_of_data}]]>
</textFieldExpression>
</textField>
<textField isStretchWithOverflow="true">
<reportElement x="101" y="0" width="150" height="24" />
<box>
<pen lineWidth="1"/>
</box>
<textFieldExpression class="java.lang.String">
<![CDATA[$F{lots_of_data}]]>
</textFieldExpression>
</textField>
<staticText>
<reportElement width="290" y="0" x="252" height="24" stretchType="RelativeToTallestObject" />
<box>
<pen lineWidth="1"/>
</box>
<text>
<![CDATA[staticText element stretchType is "RelativeToTallestObject"]]>
</text>
</staticText>
<staticText>
<reportElement width="250" y="25" x="0" height="24" positionType="Float" />
<box>
<pen lineWidth="1"/>
</box>
<text>
<![CDATA[This text is here to stretch the band a bit more.]]>
</text>
</staticText>
</frame>
</band> </detail> </jasperReport>
In this JRXML template, we replaced the <elementGroup> element of the previous example with a <frame> element, and slightly modified some of the elements' sizes. We added a <reportElement> subelement to the <frame> element to set the frame to a light gray background. We then added a <box> element to set the frame's element. Because the <reportElement> and box apply to the whole frame, they are applied to all the elements inside the frame. After compiling and filling this JRXML template, it should generate a report as the following:
The code to generate the report has nothing we haven't seen before. Therefore, we are not showing it here.
[edit] Hiding repeated values
Sometimes report elements can have the same value over and over. For example, the report we created in the Grouping report data section is sorted by model number. For airplanes that are the same model, we see the model number repeated over and over again. Perhaps the report would be easier to read if we printed the model number only when it is different from the previous one. This will add to report readability, as the person reading the report would not have to look at the model number unless it is different from the previous one. In the following example, we will modify the JRXML template discussed in that section to accomplish this:
<?xml version="1.0" encoding="UTF-8" ?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge .net/jasperreports http://jasperreports .sourceforge.net/xsd/jasperreport.xsd" name="IsPrintRepeatedValuesDemo"> <queryString> <![CDATA[select a.tail_num, a.aircraft_serial, am.model, a.state from aircraft a, aircraft_models am where a.aircraft_model_code = am.aircraft_model_code and a.country = US' and state like A%' order by state, model]]> </queryString> <field name="tail_num" class="java.lang.String" /> <field name="aircraft_serial" class="java.lang.String" /> <field name="model" class="java.lang.String" /> <field name="state" class="java.lang.String" /> <group name="StateGroup"> <groupExpression> <![CDATA[$F{state}]]> </groupExpression> <groupHeader> <band height="40"> <staticText> <reportElement x="0" y="10" width="115" height="20" /> <textElement> <font isBold="true" /> </textElement> <text>Aircraft Registered In:</text> </staticText> <textField> <reportElement x="116" y="10" width="20" height="20" /> <textFieldExpression>$F{state}</textFieldExpression> </textField> </band> </groupHeader> <groupFooter> <band height="40"> <staticText> <reportElement x="0" y="10" width="140" height="20" /> <textElement> <font isBold="true" /> </textElement> <text>End Aircraft Registered In:</text> </staticText> <textField> <reportElement x="141" y="10" width="20" height="20" /> <textFieldExpression>$F{state}</textFieldExpression> </textField> </band> </groupFooter> </group> <detail> <band height="20">
<textField>
<reportElement x="56" y="0" height="20" width="164" isPrintRepeatedValues="false" />
<textFieldExpression>
<![CDATA["Model: " + $F{model}]]>
</textFieldExpression>
</textField>
<staticText>
<reportElement x="220" y="0" height="20" width="65" />
<text>Tail Number:</text>
</staticText>
<textField>
<reportElement x="286" y="0" height="20" width="84" />
<textFieldExpression>
<![CDATA[$F{tail_num}]]>
</textFieldExpression>
</textField>
<staticText>
<reportElement x="380" y="0" height="20" width="75" />
<text>Serial Number:</text>
</staticText>
<textField>
<reportElement x="456" y="0" height="20" width="94" />
<textFieldExpression>
<![CDATA[$F{aircraft_serial}]]>
</textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
There are two main differences between the above JRXML template and the one discussed in the Grouping report data section. The first difference is that we consolidated the <staticText> element rendering the string Model: and the <textField> element rendering the model field into a single <textField> element. The other, more significant difference is that we set the isPrintRepeatedValues element in the corresponding <reportElement> element to false. After compiling the above JRXML template, filling the resulting jasper template, and exporting the resulting report, we should see a report like the following:
As we can see from the screenshot, the aircraft model is displayed only when it changes. This layout makes it a lot easier to see aircraft of the same model.
[edit] Subreports
One nice feature of JasperReports is that it allows incorporating a report within another report. That is, one report can be a subreport of another. Subreports allow us to keep report designs simple, as we can create many simple reports and encapsulate them into a master report.
Let's create a more detailed version of the report discussed in the previous section. This new version divides the reported aircraft into the city to which they are registered. We will create one report that displays the aircraft registered in each city for a particular state. Then, we'll use that report as a subreport for a master report that divides the aircraft by state. The JRXML template for the subreport is as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jasperreports.sourceforge
.net/jasperreports http://jasperreports.sourceforge .net/xsd/jasperreport.xsd" name="AircraftCityReport">
<parameter name="state" class="java.lang.String" />
<parameter name="city" class="java.lang.String" />
<queryString>
<![CDATA[select a.tail_num, a.aircraft_serial, am.model,
a.state from aircraft a, aircraft_models am
where a.aircraft_model_code = am.aircraft_model_code
and a.country = US' and a.state = $P{state} and a.city =
$P{city} order by model]]>
</queryString>
<field name="tail_num" class="java.lang.String" />
<field name="aircraft_serial" class="java.lang.String" />
<field name="model" class="java.lang.String" />
<title>
<band height="30">
<textField>
<reportElement x="0" y="0" width="300" height="24" />
<textElement markup="styled" />
<textFieldExpression>
<![CDATA["<style isBold=\"true\"
pdfFontName=\ "Helvetica-Bold\"> Aircraft Registered in
" + $P{city} + ", " + $P{state} + "</style>"]]>
</textFieldExpression>
</textField>
</band>
</title>
<pageHeader>
<band height="30">
<staticText>
<reportElement width="100" x="0" y="0" height="30" />
<textElement markup="styled" verticalAlignment="Middle" />
<text>
<![CDATA[<style isBold="true" pdfFontName="Helvetica-Bold">Model</style>]]>
</text>
</staticText>
<staticText>
<reportElement width="100" x="110" y="0" height="30" />
<textElement markup="styled" verticalAlignment="Middle" />
<text>
<![CDATA[<style isBold="true" pdfFontName="Helvetica-Bold">
Tail Number</style>]]>
</text>
</staticText>
<staticText>
<reportElement width="105" x="220" y="0" height="30" />
<textElement markup="styled" verticalAlignment="Middle" />
<text>
<![CDATA[<style isBold="true" pdfFontName="Helvetica-Bold">
Serial Number</style>]]>
</text>
</staticText>
</band>
</pageHeader>
<detail>
<band height="24">
<textField>
<reportElement x="0" y="0" width="100" height="24" />
<textElement verticalAlignment="Middle" />
<textFieldExpression>
<![CDATA[$F{model}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="110" y="0" width="100" height="24" />
<textElement verticalAlignment="Middle" />
<textFieldExpression>
<![CDATA[$F{tail_num}]]>
</textFieldExpression>
</textField>
<textField>
<reportElement x="220" y="0" width="100" height="24" />
<textElement verticalAlignment="Middle" />
<textFieldExpression>
<![CDATA[$F{aircraft_serial}]]>
</textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
As we can see, we didn't have to do anything special to make this report a subreport.
This is because any report can be used as a subreport.
Let's see what the parent report's JRXML looks like.
<?xml version="1.0" encoding="UTF-8" ?>
<jasperReport xmlns="http://jasperreports.sourceforge.
net/jasperreports"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jasperreports.sourceforge
.net/jasperreports http://jasperreports.sourceforge
.net/xsd/jasperreport.xsd"
name="AircraftStateReport">
<parameter name="state" class="java.lang.String" />
<queryString>
<![CDATA[select city from aircraft where state = $P{state}]]>
</queryString>
<field name="city" class="java.lang.String" />
<title>
<band height="30">
<textField>
<reportElement x="0" y="0" width="300" height="24" />
<textElement markup="styled" />
<textFieldExpression>
<![CDATA["<style isBold=\"true\" pdfFontName=\"Helvetica-Bold\"> Aircraft Registered in " + $P{state} + "</style>"]]>
</textFieldExpression>
</textField>
</band>
</title>
<detail>
<band height="10">
<subreport>
<reportElement x="0" y="0" height="10" width="500"
isPrintWhenDetailOverflows="true" />
<subreportParameter name="state">
<subreportParameterExpression>
<![CDATA[$P{state}]]>
</subreportParameterExpression>
</subreportParameter>
<subreportParameter name="city">
<subreportParameterExpression>
<![CDATA[$F{city}]]>
</subreportParameterExpression>
</subreportParameter>
<connectionExpression>
<![CDATA[$P{REPORT_CONNECTION}]]>
</connectionExpression>
<subreportExpression class="java.lang.String">
<![CDATA["http://localhost:8080/reports/reports/
AircraftCityReport.jasper"]]>
</subreportExpression>
</subreport>
</band>
</detail>
</jasperReport>
As can be seen in the above JRXML, we place a subreport into a master report by using the <subreport> element. The <subReportParameter> element is used to pass parameters to the subreport. The <connectionExpression> element is used to pass a java.sql.Connection to the subreport. It needs to be used only if the subreport template requires a database connection (as opposed to a datasource) to be filled. Recall from Tutorial 5, Working with Other Datasources, that the built-in report parameter REPORT_CONNECTION resolves into a reference to the instance of java.util.Connection passed to the report. If the parent report uses a datasource instead of a connection and the subreport needs a connection, the easiest way to pass the connection to a subreport is to pass it as a parameter to the parent report, which can then pass it to the subreport by using the corresponding parameter name in <connectionExpression>. The <subReportExpression> element indicates where to find the compiled report template for the subreport.
When the class attribute of <subreportExpression> is a string, JasperReports attempts to resolve a URL for the string contents. If that fails, it then assumes that the string contents represent the template's location in the filesystem and tries to load the report template from disk. If that also fails, it assumes that the string represents a CLASSPATH location and attempts to load the report template from the CLASSPATH. If all of these fail, JasperReports will throw an exception because, in that case, it will not be able to find the template for the subreport.
Other valid values for the class attribute of report expressions include net.sf.jasperreports.engine.JasperReport, java.io.File, java.io.InputStream, and java.net.URL. The most common way to obtain these values is to have the Java code filling the report pass them as a parameter and resolve them inside the <subreportExpression> tags using the $P{paramName} syntax we have seen before.
After compiling, filling, and exporting the last JRXML template, the following report will be generated:
The Model, Tail Number, and Serial Number section of the above report is an embedded report within the main report. In JasperReports jargon, we call it a subreport. Each time we passed a different city as a parameter, it generated a report for the appropriate city.
The <subreport> JRXML element can contain a number of subelements that were not used in the above example. These subelements include:
- l
<dataSourceExpression>: This is used to pass a datasource to the subreport. This datasource is usually obtained from a parameter in the master report or by using the built-inREPORT_DATA_SOURCEparameter to pass the parent report's datasource to the subreport. -
<parametersMapExpression>: This is used to pass a map containing report parameters to the subreport. The map is usually obtained from a parameter in the master report or by using the built-inREPORTS_PARAMETERS_MAPparameter to pass the parent report's parameters to the subreport. -
<returnValue>: This is used to assign the value of one of the subreport's variables to one of the master report's variables. ThesubreportVariableattribute is used for indicating the subreport variable to be used, and thetoVariableattribute is used to indicate the master report variable to be used.
Keep in mind that subreports can have other subreports, which in turn can have more subreports. There is no limit for the subreport nesting level.
[edit] Source
The source of this content is Chapter 6: Designing reports using JasperReports 3.5 of JasperReports 3.5 for Java Developers by David Heffelfingerr (Packt Publishing, 2009).
Executive Editor Sean Lopez own Logo Designby ThemesWiki.org Kevin Josh 2010
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like Costumes and Halloween Costumes and criar sites
And Like The Global Information Network and Global Information Network
