Although the jrxml template is just a text file, it is easier to use a tool such as iReport. iReport is good for general layout and can save you from tedious work but it is not perfect. Occasionally it is better to edit the xml file directly. GVim is an excellent text editor if you have a Linux background but any other text editor will do the job.
The jrxml file should be copy into a directory readable by the class loader. I put mine in /WEB-INF/reports. You can use the ReportGenerator class included to generate the desired report.
Typically a report is generated when a user clicks a button or a link which invoke an action listener. The action listener method then calls the ReportGenerator’s printReport() and a report in the desired format (HTML, PDF, CSV, EXEL) is returned to the user. PDF format with JasperReports is excellent as it uses absolute positioning. However HTML and EXEL are not very good as the outcomes can be surprisingly different. I recommend that you provide PDF for printing and CSV for data manipulations to the users as those two formats seem to work best.
Below is an example on the variation that a report should be opened on a new window after user fill out the criteria on a form. To make it a little more user friendly, error checks were performed on the back end and will be displayed on the same page. Therefore, we can’t just set the target to _blank to force the browser to open a new window whenever an action is submitted.
In your form, you might have a button like this:
<h:commandButton value="Generate" action="#{report.submit}"/>
Your action listener then validates the inputs and if there is any error, it will be sent back to the same page:
public final String submit() {
if (!criteria.isValid()) {
facesMessages.add(Severity.ERROR, "Some error messages"
return ERROR;
}
return NEXT;
}
When everything is well, we can pass control to the report generator. Wait! What if users had some errors previously which where displayed on the form? Clearing them would be good.
<navigation from-action="#{report.submit}">
<rule if-outcome="next">
<redirect view-id="/app/report/report.jsp"/>
</rule>
</navigation>
Below is the content for report.jsp. It refreshes the main form (reportForm.jsp) and opens display.jsp.
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script language="JavaScript">
function displayReport() {
reportUrl = "display.x";
newWin = window.open(reportUrl,"_blank",
"location=0,resizable=1,status=1,scrollbars=1,menubar=1,toolbar=0");
newWin.focus();
document.getElementById("report:location").click();
}
</script>
</head>
<body onload='displayReport()'>
<h:form id="report">
<s:button id="location" style="display:none" view="/app/report/reportForm.jsp" value="return" propagation="join">
</s:button>
</h:form>
</body>
</html>
</ui:composition>
Below is the content for display.jsp:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Expires" content="-1"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script language="JavaScript">
function displayReport() {
document.getElementById("report:location").click();
}
</script>
</head>
<body onload="document.body.style.cursor='wait'; displayReport();">
<h:form id="report" >
<div style="width:90%; padding:5px; margin:40px; border: 1px solid #FFCC00; background-color: #F0F8FF;">
<h:outputText value="Please wait..."/>
<h:commandButton id="location" style="display:none" action="#{report.display}"/>
</div>
</h:form>
</body>
<header>
<meta http-equiv="Expires" content="-1"/>
</header>
</html>
</ui:composition>
Displaying a message with some progress indicator would be even better on this last page. To do that, you can specify a refresh rate in this last page to get the progress. This is much easier than create a thread on the server end.
<meta http-equiv="refresh" content="1"/>
And here is the method display invoking the report generator:
public final String display() {
ReportPreparer prep = new ReportPrepFactory().getPreparer(criteria);
String template = "sample"; // Suppose your jrxml file is sample.jrxml
Map p = new HashMap(); // if your report has parameters, they should be set here
ReportGenerator gen = new ReportGenerator();
if (gen.printReport(
"P", // P for PDF
p,
new StringBuffer("/WEB-INF/reports/").append(template)
.append(".jrxml").toString(),
template)) {
return NEXT;
}
return ERROR;
}
This is the code to generate report: