Platinum Solutions Corporate Website


PDF generation w/ Apache FOP

The answer you entered to the math problem is incorrect.

My current project requires the generation of PDF reports in a web-based J2EE app, using free tools. Everyone knows about Jasper and iText, but our requirements are for a small number of somewhat simple reports, so I thought those would be overkill. Not to mention the fact that my preference is to use presentation technology that is familiar without any custom coding.

We are using Spring Web Flow, so I decided to try and use Velocity templates to build the reports and let SWF render them through its MVC architecture. Instead of rendering that view directly to the browser in HTML, I made sure that the output was in XHTML and then passed it to Apache FOP to do an XSL-FO transform and generate a PDF, based on a slightly modified freely available XHTML-to-FO stylesheet I found on Antenna House's website.

It turns out, this all worked pretty well. The only struggle I faced was that most of the examples of using Apache FOP out there on the internet are for version 0.20. The current version, 0.90, is drastically different. However, after I read a bit of the documentation, it was easy enough to figure out. In order to get SWF to do this, I had to write my own ViewResolver and View classes and then wire it all up in Spring. Below is a snippet from View class and then the method that actually does the parsing:

public class VelocityToPdfView extends VelocityView {

private static String PDF_MIMETYPE = 	"application/pdf";
private static String XSL_STYLESHEET_CLASSPATH = "/xhtml2fo.xsl";
	
 @Override
protected void mergeTemplate(Template template, 
    Context context, HttpServletResponse response) 
    throws Exception {

	 try 
	 {
		 ByteArrayOutputStream stream = new ByteArrayOutputStream();
		 PrintWriter pw = new PrintWriter(stream);
		 template.merge(context, pw);
		 pw.flush();
		 InputStream inputStream = 
                     new ByteArrayInputStream(stream.toByteArray());
		 response.setContentType(PDF_MIMETYPE);
		 Html2Pdf.htmlToPdf(
                     inputStream,
                     (OutputStream)response.getOutputStream(),
                     XSL_STYLESHEET_CLASSPATH);
		 
	 }	 
         catch (MethodInvocationException ex) {
	     throw new NestedServletException( 
                 "Method invocation failed during rendering " + 
                 "of Velocity view with name '" +
                 getBeanName() + 
                 "': " + ex.getMessage() + 
                 "; reference [" + ex.getReferenceName() +
                 "], method '" + ex.getMethodName() + "'",
                 ex.getWrappedThrowable());
        }
    }	
 
}

html2Pdf method:

	public static void htmlToPdf(InputStream input,
            OutputStream pdfOutputStream,String styleSheet) {

		try {
			// Setup a buffer to obtain the content length
			ByteArrayOutputStream out = new ByteArrayOutputStream();

			// Setup FOP
			Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);

			// Setup Transformer
			Source xsltSrc = new StreamSource(
                            Html2Pdf.class.getResourceAsStream(styleSheet));
			Transformer transformer = tFactory.newTransformer(xsltSrc);

			// Make sure the XSL transformation's result is piped 
                        // through to FOP
			Result res = new SAXResult(fop.getDefaultHandler());

			// Setup input
			Source src = new StreamSource(input);

			// Start the transformation and rendering process
			transformer.transform(src, res);
			pdfOutputStream.write(out.toByteArray());
			pdfOutputStream.flush();

		} catch (Exception e) {
			e.printStackTrace(System.err);
		}

	}

Comments

Post new comment

Please solve the math problem above and type in the result. e.g. for 1+1, type 2.
The content of this field is kept private and will not be shown publicly.
  • Lines and paragraphs break automatically.

More information about formatting options