Using JasperReports in a Java EE application
Prerequisistes
JRE
Servlet engine
RDBMS + JDBC driver for a database
Apache Ant
Versions used
JRE 1.6.0_21
Apache Tomcat 6.0.29
MySQL 5.1.50
MySQL connector/J 5.1.13
JasperReports 3.7.0
Apache Ant 1.8.1
Steps
- Download the jasperreports project zip file from sourceforge, http://sourceforge.net/projects/jasperreports/
- Extract the zip file to a temporary location e.g. C:\temp
- Open a command prompt
- Navigate to c:\temp\jasperreports-3.7.0-project\jasperreports-3.7.0\demo\samples\webapp
- Type the command ant javac [the path to the ant bin folder needs to be in the system path]
- Create a folder in the tomcat webapps directory e.g. jasper
- Copy the contents of the webapp directory to the webapps\jasper directory. This sample web application can serve as a guide on how to integrate jasperreports into your own web application.
Using in a custom application
- Copy the following files from the webapps\jasper\web-inf\lib\ directory to your application's web-inf\lib directory. commons-beanutils-1.8.0.jar, commons-collections-2.1.1.jar, commons-digester-1.7.jar, commons-logging-1.0.4.jar, jasperreports-3.7.0.jar, iText-2.1.0.jar (for pdf export), poi-3.2-FINAL-20081019.jar (for xls export). For generating charts you'll need jfreechart and jcommon.
Generating a report
import net.sf.jasperreports.engine.*; //for main jasper objects import net.sf.jasperreports.engine.export.*; //for exporters JasperReport jasperReport; JasperPrint jasperPrint; JRResultSetDataSource ds; ServletContext context = this.getServletConfig().getServletContext(); String fileBase="report1"; String fileName=context.getRealPath("/reports/"+fileBase+".jasper"); File reportFile = new File(context.getRealPath("/reports/"+fileBase+".jasper")); if (!reportFile.exists()) { //compile file fileName=JasperCompileManager.compileReportToFile(context.getRealPath("/reports/"+fileBase+".jrxml")); } //rs is a resultset generated by your application. You can also pass a connection instead of a resultset if you want to use the query as it is in the repoort template ds = new JRResultSetDataSource(rs); HashMap parameters=new HashMap(); //use a map to pass report parameters jasperPrint = JasperFillManager.fillReport(fileName, parameters,ds); //export to pdf JasperExportManager.exportReportToPdfFile(jasperPrint,fullFileName); //export to html JRXhtmlExporter exporter = new JRXhtmlExporter(); exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint); exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, fullFileName); exporter.exportReport(); //export to xls JRXlsExporter exporter = new JRXlsExporter(); exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint); exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, fullFileName); exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE); exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE); exporter.exportReport();
Passing parameters
- If passing parameters, the parameter value data type in the parameters map must match the data type of the parameter as declared in the report template.
Example template query using a single value parameter
select * from customers where customer_id = $P{customer_id_param}Example template query using a multi value parameter
select * from products where $X{IN, category, categories_param} select * from products where $X{NOTIN, category, categories_param}For multi value parameters, define the parameter class in the jrxml file as java.util.List. Pass values using an array list e.g
List categories = new ArrayList(); categories.add("Laptop"); categories.add("PC"); categories.add("Printer"); parameters.put("categories_param", categories);
Using virtualizers
- A virtualizer can be used to enable large reports to be generated successfully, without resulting in out of memory errors. Using a virtualizer doesn't guarantee filling of arbitrarily large reports. Heap memory is still needed but memory requirements are reduced.
- Also, once a report is filled, whether it can be exported successfully depends on the export format and library. e.g. Filling may be successful, generating a jasper print object but exporting to excel may fail because poi puts all the data in memory before generating the final file. Adding available heap memory may help to have a successful export.
- If a report contains images, this may also be a cause of out of memory errors. In such a case, the virtualizer doesn't help until you set the image's properties "isUsingCache" to false and "isLazy" to true in the report template.
import net.sf.jasperreports.engine.fill.*; //for virtualizers import net.sf.jasperreports.engine.util.*; //for jrswapfile //use virtualizer if required JRAbstractLRUVirtualizer virtualizer=null; if(!props.getProperty(VIRTUALIZER).equals("none")){ if(props.getProperty(VIRTUALIZER).equals("file")){ int maxSize=Integer.parseInt(props.getProperty(FILE_MAX_SIZE)); virtualizer=new JRFileVirtualizer(maxSize,System.getProperty("java.io.tmpdir")); params.put(JRParameter.REPORT_VIRTUALIZER, virtualizer); } else if(props.getProperty(VIRTUALIZER).equals("gzip")){ int maxSize=Integer.parseInt(props.getProperty(GZIP_MAX_SIZE)); virtualizer=new JRGzipVirtualizer(maxSize); params.put(JRParameter.REPORT_VIRTUALIZER, virtualizer); } else { //use swap virtualizer by default int maxSize=Integer.parseInt(props.getProperty(SWAP_MAX_SIZE)); int blockSize=Integer.parseInt(props.getProperty(SWAP_BLOCK_SIZE)); int minGrowCount=Integer.parseInt(props.getProperty(SWAP_MIN_GROW_COUNT)); JRSwapFile swapFile=new JRSwapFile(System.getProperty("java.io.tmpdir"),blockSize,minGrowCount); virtualizer=new JRSwapFileVirtualizer(maxSize,swapFile); params.put(JRParameter.REPORT_VIRTUALIZER, virtualizer); } } //fill report with data JasperPrint jasperPrint; if(rs==null){ //use template query connQuery = ArtDBCP.getConnection(datasourceId); jasperPrint = JasperFillManager.fillReport(jasperFileName, params,connQuery); } else { //use recordset based on art query JRResultSetDataSource ds; ds = new JRResultSetDataSource(rs); jasperPrint = JasperFillManager.fillReport(jasperFileName, params,ds); } //set virtualizer read only to optimize performance. must be set after print object has been generated if(virtualizer!=null){ virtualizer.setReadOnly(true); } //export report ... //clean up if(virtualizer!=null){ virtualizer.cleanup(); }
Notes
- If the resultset is null, by default, the generated report will consist of a completely blank page. To display other report sections and only have the data section blank, if using iReport, change the report properties "when no data" option to "all sections, no detail".
- If the report contains images, the image files should be located in the same directory as the jrxml file
- If a parameter is used in a query and is not provided, it will be ignored, as if the condition didn't exist
Hello Timothy, very informative post. I was looking for exactly this code sample. Thanks for sharing.
ReplyDeleteI have one issue. In my case code to fill report is kept on the server. This code returns the object of type JasperPrint to client. Client then exports a report.
So part upto filling report and virtualizer read only to true is OK. But how can I clean up the virtualizer after report is exported (as export code is on client and virtualizer was created and used on server).
What if I clean up the virtualizer before I export the report?
Not sure what should happen. You can try out the different scenarios and see what happens.
ReplyDeleteHello Timothy, Very nice and helpful blog, I do have a out of memory exception but the data is very small. say 2 - 3 rows. But still i am getting out of memory exception. Do you have any inputs on this?
ReplyDeleteI don't know why that would be happening.
ReplyDelete