Olá!

GrailsBem, compartilhando uma dica interessante, que pode ajudar várias pessoas: Geração de PDF através das view GSPs de uma aplicação Grails. E o que é melhor: em 5 minutos!!

Então vamos lá:

1) Baixe o pacote Flying Saucer: https://xhtmlrenderer.dev.java.net/

2) Dentro do pacote, você encontrará dois arquivos: core-renderer.jar e iText-2.0.8.jar – Adicione estes arquivos dentro do diretório lib da sua aplicação Grails

3) Imagine uma aplicação Biblioteca, onde você deseja exportar a visualização das informações de um livro através de um arquivo pdf. Definindo uma URL de acesso a esta funcionalidade, podemos criar o link:

http://seudominio.net/book/<CODIGO>/pdf

Nossa classe “Book”:

class Book {
   String title
   String author
   String description
   int year

   static constraints = {
      title blank:false
      author blank:false
      year nullable:true
      description nullable:true
   }
}

O Pdf que vamos gerar será um arquivo html simples, salvo como o template grails-app/views/book/_pdf.gsp:

${book.title}

${book.author}, ${book.year}

${book.description}

Até ai nada de novo. (Para deixar a coisa mais chique, leia sobre Content Negotiation em Grails – mas para este exemplo 5 minutos, isso tá otimo)

4) O processo de geração do PDF será:

  • Extrair o resultado de uma view para uma String
  • Invocar o Flying Saucer/iText para que a mágica aconteça
  • Retornar o Arquivo para o usuário

Para isso, a action pdf, dentro do controller BookController será implementada assim:

def toPdf = {
   def baseUri = request.scheme + "://" + request.serverName + ":" + request.serverPort + grailsAttributes.getApplicationUri(request)

    // Rendering View
    def book = Book.get(params.id)
    def render_result = g.render(template:"/book/pdf.gsp", model: [book: book])

    // creating PDF
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ITextRenderer renderer = new ITextRenderer();
    byte[] b
    renderer.setDocumentFromString(render_result.toString(), baseUri);
    renderer.layout();
    renderer.createPDF(baos);
    b = baos.toByteArray();

    // Sending file to the user
    response.setContentType("application/pdf")
    response.setHeader("Content-disposition", "attachment; filename=${book.title}.pdf")
    response.setContentLength(b.length)
    response.getOutputStream().write(b)
}

Pronto! Está Feito!

Considerações

  • Transforme a geração do PDF em um serviço dentro da sua aplicação, deixando o código mais organizado e com uma melhor performance
  • É possível generalizar o código acima para funcionar com mais objetos do domínio, ampliando reuso, separando as responsabilidade de rendering da view e escrita do arquivo no response através de classes separadas. O PDF Plugin citado abaixo pode te dar algumas ideias
  • Possui algum comentário sobre a solucao acima? Comente!!

Aprofundando o seu conhecimento sobre o tema


Victor Hugo Germano

CEO da Lambda3