Lift で PDF を出力する [1]

今回は、Scala言語ベースのWebフレームワークである、LiftをつかってPDF生成をしてみたいと思います。

最近では,foursquareのような有名サイトなどもLiftで構築されているようです.

今回もsbtが必要になってきます.sbtについては公式サイト以前の記事に添付したzipに同梱してあるものなどを利用してください。

手順は次の通りです.

  1. 1. sbtを準備する
  2. 2. LiftのGetting startedページにあるアーカイブ(zip or tar)をダウンロードし,展開する
  3. 3. 下記コードとHTMLを上記ディレクトリへ追加する
  4. 4. sbtでupdateを実行する
  5. 5. sbtでjetty-runを実行する

出力例は次のとおりです.


生成されたPDF

《 生成されたPDF 》


本Webアプリは、始めの画面は次のようなものになります.


アクセス直後

《 アクセス直後 》


まず,左側にあるSign Upをクリックし,ユーザ情報を登録します.


サインアップ

《 サインアップ 》


ユーザ情報の登録が完了すると,自動的にログインされ,左下にWelcomeと表示されます.


ログインされた状態

《 ログインされた状態》


この状態でPDFを生成ボタンをクリックすると,ログインしているユーザの情報が透かしとして印字されたPDFがサーバのテンポラリディレクトリ内に出力されます.


PDF生成後

《 PDF生成後 》


基本的にLiftの場合は,ビューの部分を(一部Liftのタグが混入した)XHTMLで記述し,そのビューへ流し込むデータの作成と,フォームからの入力情報を処理するためのSnippetコードを組み合わせて,Webアプリを作成していきます.


Lift の Snippet ソースコードは次のようになります.

こちらのファイルは新規作成します.


《 src/main/scala/code/snippet/GeneratePDF.scala 》
package code.snippet

import scala.xml.{ NodeSeq, Text }

import net.liftweb.util._
import net.liftweb.common._
import net.liftweb.http.SHtml._
import net.liftweb.http.js.JsCmds._
import net.liftweb.util.Helpers._

import java.io.{ StringReader, File }
import java.util.Hashtable
import javax.xml.parsers.DocumentBuilderFactory
import org.xml.sax.InputSource

import com.brainsellers.xml.JaxpXML
import com.brainsellers.xml.page.PDFEngine
import com.brainsellers.xml.datatypes.{ HashtableType, RecordType }

import code.lib._
import code.model._


class GeneratePDF {

  val layoutXml =
    <Layout width="210mm" height="297mm">
      <Star Radius="70mm" FillColor="#99ccff" X="105mm" Y="148.5mm"/>
      <watermark fit="horizon" align="vertical" text-align="center" rate="80" line-align="center">
        <watermark-text name="watermarkText1" font-color="red" text-rendering="stroke"></watermark-text>
      </watermark>
    </Layout>

  def nodeSeqToDocument(xml: NodeSeq) =
    DocumentBuilderFactory.newInstance.newDocumentBuilder.parse(
      new InputSource(new StringReader(xml.toString)))

  def getPDF(in: NodeSeq): NodeSeq = {
    bind("getPDF", in,
      "button" -> ajaxButton(Text("PDFを生成"), { () =>
        {
          val name = User.currentUser.dmap("Guest") { _.niceName }
          val file = File.createTempFile("generate_pdf_", ".pdf")
          file.deleteOnExit()
          val ht = new Hashtable[String, String]
          ht.put("watermarkText1", name)

          val bizLib = new JaxpXML(nodeSeqToDocument(layoutXml), file.getAbsolutePath())
          bizLib.parse
          bizLib.calcDataSize
          bizLib.toPDF(ht)
          bizLib.close

          SetHtml("getPDF-div",
            Text("PDFの生成が完了しました。"))
        }
      }))
  }
}

  • 26行: レイアウト定義(透かしと星)を行っています.
  • 34行: JavaのXML型からScalaのXML型へ変換しています.
  • 38行: PDFを生成ボタンが押された際の動作を定義しています.

HTML テンプレートは次のようになります.

こちらのファイルは,既存のファイルを次のものに置き換えます.


《 src/main/webapp/index.html 》
<lift:surround with="default" at="content">
  <lift:generatePDF.getPDF>
    <div id="getPDF-div"></div>
    <getPDF:button></getPDF:button>
  </lift:generatePDF.getPDF>
</lift:surround>

  • 1行: デフォルトのテンプレートを適用しています.
  • 2行: SnippetのGeneratePDFクラスのgetPDFメソッドとマッピングさせています.
  • 3行: Snippetから文字列を設定するための領域を定義しています.
  • 4行: ボタンを定義しています.

今回はサーバ上にPDFファイルが出力されていますが,次回はブラウザからダウンロードするように修正していきたいと思います.

biz-Stream詳細情報  biz-Stream資料請求

超高速!!高機能!! Web帳票ソリューション biz-Stream

オンデマンドかつリアルタイムにビジネスドキュメントを生成する帳票ソリューション