logo
header art

Creating Reports with iReports and JasperReports

June 23, 2005

Serving the Report

Serving JasperReports From a Web Server Using Tomcat

The next thing we will look at is serving our report from a webserver using the Apache Tomcat webserver / servlet container. Installing and configuring Tomcat is beyond the scope of this article. The official Tomcat site can be found at http://jakarta.apache.org/tomcat/index.html.

Once you have Tomcat up and running, it's time to write the servlet: ReportEngine.

001 package com.skillfusion.articles.jasper.example.servlets;
002 
003 import java.io.IOException;
004 import java.io.PrintWriter;
005 import java.sql.Connection;
006 import java.sql.SQLException;
007 import java.util.HashMap;
008 
009 import javax.naming.Context;
010 import javax.naming.InitialContext;
011 import javax.naming.NamingException;
012 import javax.servlet.ServletException;
013 import javax.servlet.ServletOutputStream;
014 import javax.servlet.http.HttpServlet;
015 import javax.servlet.http.HttpServletRequest;
016 import javax.servlet.http.HttpServletResponse;
017 import javax.sql.DataSource;
018 
019 import net.sf.jasperreports.engine.JRException;
020 import net.sf.jasperreports.engine.JasperExportManager;
021 import net.sf.jasperreports.engine.JasperFillManager;
022 import net.sf.jasperreports.engine.JasperPrint;
023 
024 /**
025  * The <code>ReportEngine</code> class serves html and pdf reports using
026  * Jasper reports.
027  
028  @author SkillFusion
029  */
030 public class ReportEngine extends HttpServlet {
031     /**
032      * Called by the server to allow a servlet to handle a GET request.
033      
034      @param request
035      *            the request the client has made of the servlet
036      @param response
037      *            the response the servlet sends to the client
038      @throws ServletException
039      @throws IOException
040      */
041     public void doGet(HttpServletRequest request, HttpServletResponse response)
042             throws ServletException, IOException {
043 
044         // Pass this request off to the handleSubmit method. It's an accepted
045         // best pracice to handle GET and POST submissions the same way unless
046         // there's a good reason not to do so.
047         this.handleSubmit(request, response);
048 
049     }
050 
051     /**
052      * Called by the server to allow a servlet to handle a POST request.
053      
054      @param request
055      *            the request the client has made of the servlet
056      @param response
057      *            the response the servlet sends to the client
058      @throws ServletException
059      @throws IOException
060      */
061     public void doPost(HttpServletRequest request, HttpServletResponse response)
062             throws ServletException, IOException {
063         // Pass this request off to the handleSubmit method. It's an accepted
064         // best pracice to handle GET and POST submissions the same way unless
065         // there's a good reason not to do so.
066         this.handleSubmit(request, response);
067     }
068 
069     /**
070      * Handles form submissions for <code>#doGet</code> and
071      <code>#doPost</code>.
072      
073      @param request
074      *            The <code>HttpServletRequest</code> wrapping the HTTP
075      *            request that triggered this method.
076      @param response
077      *            The <code>HttpServletResponse</code> that gives this method
078      *            access to the HTTP response the servlet container will send
079      *            back to the user agent.
080      @throws IOException
081      *             when an error occurs while trying to access the output stream
082      *             to notify the user of an error.
083      */
084     protected void handleSubmit(HttpServletRequest request,
085             HttpServletResponse responsethrows IOException {
086         // Declare the printwriter (which we'll use if an error occurs), but
087         // don't instantiate it yet because instantiating it will prevent us
088         // from streaming the PDF back to the client if everything else works.
089         PrintWriter out = null;
090 
091         Connection conn = null;
092         try {
093             // Get a JDBC Connection
094             Context initContext = new InitialContext();
095             DataSource dataSource = (DataSourceinitContext
096                     .lookup("java:comp/env/jdbc/jasper_example");
097             conn = dataSource.getConnection();
098 
099             // Get report file name from params
100             String rptfilename = request.getParameter("rptfilename");
101 
102             // get the name filter
103             String namefilter = request.getParameter("NameFilter");
104 
105             // Add filter value to a hashtable of report parameters
106             HashMap params = new HashMap();
107             params.put("NameFilter", namefilter);
108             params.put("testing""some stuff");
109 
110             // fill the report
111             JasperPrint jasperprint = JasperFillManager.fillReport(
112                     getServletContext().getRealPath("/"+ rptfilename, params,
113                     conn);
114 
115             // export report to pdf and stream back to browser
116             byte[] pdfasbytes = JasperExportManager
117                     .exportReportToPdf(jasperprint);
118 
119             ServletOutputStream outstream = response.getOutputStream();
120             response.setContentType("application/pdf");
121             response.setContentLength(pdfasbytes.length);
122 
123             response.setHeader("Content-disposition",
124                     "inline; filename=\"Report.pdf\"");
125             outstream.write(pdfasbytes);
126 
127         catch (NamingException ne) {
128             // Get the writer from the response so we can output markup
129             out = response.getWriter();
130 
131             // There was a problem, either in retrieving the initial context, or
132             // looking for a specific JNDI resource inside that context. Either
133             // way, let the user know.
134             out.println("<html>");
135             out.println("\t<body>");
136             out.println("\t\t<br /><br />");
137             out.println("\t\tDue to a naming problem with this servlet's"
138                     "initial context, the system is unable to display"
139                     "the report at this time.");
140             out.println("\t\t<br /><br />");
141             out.println("\t\tError Message ==> " + ne.getLocalizedMessage());
142             out.println("\t\t<br />");
143             out.println("\t\tCause of Error ==> " + ne.getCause());
144             out.println("\t</body>");
145             out.println("</html>");
146         catch (SQLException sqle) {
147             // Get the writer from the response so we can output markup
148             out = response.getWriter();
149 
150             // Start the html, but don't fill in the juicy bits yet
151             out.println("<html>");
152             out.println("\t<body>");
153 
154             // SQLExceptions can be chained. We have at least one exception, so
155             // set up a loop to make sure we let the user know about all of them
156             // if there happens to be more than one.
157             SQLException tempException = sqle;
158             while (null != tempException) {
159                 // work
160                 // Write out the useful info on this exception to the response
161                 out.println("\t\t<br /><br />");
162                 out.println("\t\tThe following database error occurred:");
163                 out.println("\t\t<br /><br />");
164                 out.println("\t\tError Message ==> "
165                         + sqle.getLocalizedMessage());
166                 out.println("\t\t<br />");
167                 out.println("\t\tCause of Error ==> " + sqle.getCause());
168                 out.println("\t\t<br />");
169                 out.println("\t\tSQL State ==> " + sqle.getSQLState());
170                 out.println("\t\t<br />");
171                 out.println("\t\tVendor Error Code ==> " + sqle.getErrorCode());
172 
173                 // loop to the next exception
174                 tempException = tempException.getNextException();
175             }
176 
177             // Write out the closing tags to the response
178             out.println("\t</body>");
179             out.println("</html>");
180         catch (JRException jre) {
181             // Get the writer from the response so we can output markup
182             out = response.getWriter();
183 
184             // Jasper had an internal error when filling the report. Give the
185             // user the lowdown.
186             out.println("<html>");
187             out.println("\t<body>");
188             out.println("\t\t<br /><br />");
189             out.println("\t\tJasper encountered a problem when attempting"
190                     "to populate the report.");
191             out.println("\t\t<br /><br />");
192             out.println("\t\tError Message ==> " + jre.getLocalizedMessage());
193             out.println("\t\t<br />");
194             out.println("\t\tCause of Error ==> " + jre.getCause());
195             out.println("\t</body>");
196             out.println("</html>");
197         catch (IOException ioe) {
198             // Get the writer from the response so we can output markup
199             out = response.getWriter();
200 
201             // This was an IO error, so it quite possibly resulted from an error
202             // creating the print writer, but we're still gonna give it the old
203             // college try and attempt to send back useful info to the user
204             out.println("<html>");
205             out.println("\t<body>");
206             out.println("\t\t<br /><br />");
207             out.println("\t\tDue to a naming problem with this servlet's"
208                     "initial context, the system is unable to display"
209                     "the report at this time.");
210             out.println("\t\t<br /><br />");
211             out.println("\t\tError Message ==> " + ioe.getLocalizedMessage());
212             out.println("\t\t<br />");
213             out.println("\t\tCause of Error ==> " + ioe.getCause());
214             out.println("\t</body>");
215             out.println("</html>");
216         finally {
217             try {
218                 // We're done here, so clean up the connection
219                 conn.close();
220             catch (SQLException sqle) {
221                 // We don't actually care, we were just trying to clean up an
222                 // expensive DB connection
223             }
224         }
225     }
226 }
Java2html

Best practices tell us that when the doGet and doPost methods exhibit the same behavior, they should delegate the implementation of that behavior to a helper method. In keeping with that ideal, all the actual work in this servlet is done in the handleSubmit method, which is called by both doGet and doPost.

Inside handleSubmit, we establish a JDBC database connection by looking up a JNDI resource named jdbc/jasper_example, which defines the DataSource for our JDBC connection. Once the connection has been established, handleSubmit begins pulling required information out of the HttpRequest's parameters. Once all the necessary info has been extracted from the HttpRequest and pushed into a Map of parameters, handleSubmit makes a call to JasperFillManager.fillReport. Next, we pass the results of that call to JasperExportManager.exportReportToPdf to convert the report to PDF format. Once that's done, it's a simple matter to write the resulting document back to the HttpResponse as an array of bytes.

To try it out, you can just invoke the deploy target of the Ant buildfile shipped with the sample application. It uses standard Ant targets, along with a few targets provided by Tomcat, to compile the whole webapp into a standard WAR file and deploy it into the servlet container. After that, you should be able to serve up PDF reports using an open-source solution based on Jasper Reports and iReport.