Skip to content

Instantly share code, notes, and snippets.

@luizkowalski
Forked from massahud/1-README.md
Created March 1, 2013 23:40
Show Gist options
  • Save luizkowalski/5068821 to your computer and use it in GitHub Desktop.
Save luizkowalski/5068821 to your computer and use it in GitHub Desktop.

Filter to generate PDF from Servlet dynamic pages

This filter intercepts the response and runs Flying Saucer ITextRenderer on it, returning a pdf instead.

Configuration

Just put the filter on your code and configure the url patterns where it will run on web.xml. The filtered pages will return as pdf documents.

If your webserver does not resolve locally to 'localhost', change line #60 to a address that resolves to itself.

Maven dependency:

<dependency>
  <groupId>com.lowagie</groupId>
  <artifactId>itext</artifactId>
  <version>2.1.7</version>
</dependency>
<dependency>
  <groupId>org.xhtmlrenderer</groupId>
  <artifactId>flying-saucer-pdf</artifactId>
  <version>9.0.1</version>
</dependency>

Page

The page can be configured using the CSS3 page rule (http://www.w3.org/TR/css3-page/)

Example:

@page {
  size: A4 portrait;
  @bottom-right {
    content: "Page " counter(page) " of " counter(pages);
  };
}

Header and footer

Simple headers and footers can be generated using the content property on the @page rule, but you can also use html elements. To use HTML elements, you must use the CSS3 Generated Content For Paged Media module (http://www.w3.org/TR/css3-gcpm/)

Basically, declare an html element with the value running(nameOfReference) on the position property and, inside the @page rule, call the element using element(nameOfReference).

Example:

HTML:

<div id="footer" >
  Page </span><span class="page"/> de <span class="pages"/>
</div>

CSS:

#footer {
  position: running(footer);
  font-weight: bold;
  font-size: 9pt;
}

@page {
  size: A4 portrait;
  @bottom-right {
    content: element(footer)
  };
}

span.page:before {
  content: counter(page);
}

span.pages:before {
  content: counter(pages);
}

Filtro para gerar PDF de páginas dinâmicas do servlet

Esse filtro intercepta a resposta e executa o ITextRenderer do Flying Saucer, retornando um pdf no lugar do XHTML gerado.

Configuração

Simplesmente coloque o filtro no seu código e configure os url patterns no web.xml. As páginas que ele filtrar serão retornadas como documentos pdf.

Se o seu webserver não resolver localmente 'localhost', modifiquea linha #60 do .java para um endereço que o webserver resolva para ele mesmo.

Dependência Maven:

<dependency>
  <groupId>com.lowagie</groupId>
  <artifactId>itext</artifactId>
  <version>2.1.7</version>
</dependency>
<dependency>
  <groupId>org.xhtmlrenderer</groupId>
  <artifactId>flying-saucer-pdf</artifactId>
  <version>9.0.1</version>
</dependency>

Página

A página pode ser configurada usando o CSS3 Page Rule (http://www.w3.org/TR/css3-page/)

Exemplo:

@page {
  size: A4 portrait;
  @bottom-right {
    content: "Página " counter(page) " de " counter(pages);
  };
}

Cabeçalho e rodapé

Cabeçalhos e rodapés simples podem ser gerados usando a propriedade content nas regras @page, como no exemplo anterior, mas também é possível utilizar elementos html.

Para usar elementos html, deve-se utilizar o módulo CSS3 Generated Content For Paged Media (http://www.w3.org/TR/css3-gcpm/)

Basicamente, declare um elemento html com o valor running(nomeDeReferencia) na propriedade position, e dentro da regra @page, chame o elemento usando element(nomeDeReferencia).

Exemplo:

HTML::

<div id="footer" >
  Página </span><span class="pagina"/> de <span class="paginas"/>
</div>

CSS:

#footer {
  position: running(footer);
  font-weight: bold;
  font-size: 9pt;
}

@page {
  size: A4 portrait;
  @bottom-right {
    content: element(footer)
  };
}

span.pagina:before {
  content: counter(page);
}

span.paginas:before {
  content: counter(pages);
}
package com.massahud.web.filter.pdf;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.net.URL;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.DefaultPDFCreationListener;
import org.xhtmlrenderer.pdf.ITextRenderer;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Adaptado de http://today.java.net/pub/a/today/2006/10/31/combine-facelets-and-flying-saucer-renderer.html
*
* @author Geraldo Massahud
*/
public class FiltroPdfRenderer implements Filter {
private DocumentBuilder documentBuilder;
private FilterConfig config;
public void init(FilterConfig config) throws ServletException {
try {
this.config = config;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
documentBuilder = factory.newDocumentBuilder();
} catch (ParserConfigurationException ex) {
throw new ServletException(ex);
}
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
URL urlDocumento = new URL(request.getProtocol(), "localhost", request.getLocalPort(), request.getRequestURI());
//Capture the content for this request
ContentCaptureServletResponse capContent = new ContentCaptureServletResponse(response);
filterChain.doFilter(request, capContent);
try {
//Parse the XHTML content to a document that is readable by the XHTML renderer.
StringReader contentReader = new StringReader(capContent.getContent());
InputSource source = new InputSource(contentReader);
ITextRenderer renderer = parse(source, urlDocumento);
response.setContentType("application/pdf");
OutputStream browserStream = response.getOutputStream();
renderer.createPDF(browserStream);
return;
} catch (SAXException e) {
throw new ServletException(e);
} catch (DocumentException e) {
throw new ServletException(e);
}
}
public void destroy() {
}
private synchronized ITextRenderer parse(InputSource source, URL urlDocumento) throws SAXException, IOException {
Document xhtmlContent = documentBuilder.parse(source);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(xhtmlContent, urlDocumento.toExternalForm());
renderer.layout();
return renderer;
}
}
class ContentCaptureServletResponse extends HttpServletResponseWrapper {
private ByteArrayOutputStream contentBuffer;
private PrintWriter writer;
public ContentCaptureServletResponse(HttpServletResponse originalResponse) {
super(originalResponse);
}
@Override
public PrintWriter getWriter() throws IOException {
if (writer == null) {
contentBuffer = new ByteArrayOutputStream();
writer = new PrintWriter(contentBuffer);
}
return writer;
}
public String getContent() {
writer.flush();
String xhtmlContent = new String(contentBuffer.toByteArray());
return xhtmlContent;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment