- It's free
- It's easy to use
- It has a nice plugin that works inside Netbeans: iReport
To get started, you have to add JasperReports dependency in your POM.xml:
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
The commons-collections might be needed to fix a transitive dependency error that you might get with Tapestry5 and JasperReports.
The next part is the report template (jrxml) needs to be created. I just put it template in the WEB-INF folder so to access it is: /WEB-INF/reports/report1.jrxml
The report template is a rather rich XML file with a lot of moving parts but it shouldn't be that hard since we do have the iReport plugin to "visually" create the reports. Here is an example: test_jasper.jrxml. And here is a full working example.
The next piece of the puzzle is a custom Tapestry5 StreamResponse for PDF files. The idea is after we generate the report, we are going to send it to the client as a PDF file so they can print it.
import java.io.IOException;
import java.io.InputStream;
import org.apache.tapestry5.StreamResponse;
import org.apache.tapestry5.services.Response;
/**
*
* @author jaypax
*/
public class PDFStreamResponse implements StreamResponse {
private InputStream is;
private String filename="default";
/**
* Constructor
* @param is
* @param args (http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
*/
public PDFStreamResponse(InputStream is, String... args) {
this.is = is;
if (args != null) {
this.filename = args[0];
}
}
public String getContentType() {
return "application/pdf";
}
public InputStream getStream() throws IOException {
return is;
}
public void prepareResponse(Response arg0) {
arg0.setHeader("Content-Disposition", "attachment; filename="
+ filename + ".pdf");
}
}
Then we can now add a event handler for that button when clicked sends the report. In my scenario, its inside a onSubmit event. This is on a page class that's populated with services injected via Tapestry's IOC. I also injected the report form as an asset.
@Property
private int id;
@Inject
@Path(value = "context:WEB-INF/reports/report1.jrxml")
private Asset ReportForm;
....
....
....
public StreamResponse onSubmitFromReportForm() throws IOException,JRException{
InputStream is = ReportForm.getResource().openStream();
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(someDAO.findAllEntriesById(id));
Map reportParams = new HashMap();
reportParams.put("TITLE", "SOME REPORT TITLE");
JasperDesign reportDesign = JRXmlLoader.load(is);
JasperReport reportCompiled = JasperCompileManager.compileReport(reportDesign);
JasperPrint reportPrinted = JasperFillManager.fillReport(reportCompiled, reportParams,ds);
ByteArrayInputStream bais = new ByteArrayInputStream(JasperExportManager.exportReportToPdf(reportPrinted));
return new PDFStreamResponse(bais, "Some Report");
}
Notice the PDFStreamResponse as the return object, without that then browser will mishandle the return stream.
Turning this into a service shouldn't be that hard which I will probably do in a coming iteration.
No comments:
Post a Comment