CLOVER🍀

That was when it all began.

ScalateをWebアプリに使ってみる

今度は、Scalateとサーブレットを組み合わせてみます。

最初は、こちらを参考に。

Using Scalate as Servlet filter in your Web Application
http://scalate.fusesource.org/documentation/user-guide.html#using_scalate_as_servlet_filter_in_your_web_application

今回もビルドにはsbtを使用しますが、Webアプリになるのでxsbt-web-pluginも合わせて使用します。

build.sbt

name := "scalate-servlet-example"

version := "0.0.1"

organization := "littlewings"

scalaVersion := "2.9.2"

seq(webSettings :_*)

classpathTypes ~= (_ + "orbit")

libraryDependencies ++= Seq(
  "org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "provided" artifacts (Artifact("javax.servlet", "jar", "jar")),
  "org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "container",
  "org.fusesource.scalate" % "scalate-core" % "1.5.3"
)

Jettyは、8を選びました。Jetty 9は、xsbt-web-pluginが対応していませんでした…。

project/plugins.sbt

libraryDependencies += "com.github.siasia" %% "xsbt-web-plugin" % "0.12.0-0.2.11.1"

では、まずはweb.xmlの用意。
src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
  <servlet>
    <servlet-name>scalateExample</servlet-name>
    <servlet-class>example.servlet.ScalateExampleServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>scalateExample</servlet-name>
    <url-pattern>/scalate-example</url-pattern>
  </servlet-mapping>

  <filter>
    <filter-name>TemplateEngineFilter</filter-name>
    <filter-class>org.fusesource.scalate.servlet.TemplateEngineFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>TemplateEngineFilter</filter-name>
    <url-pattern>*.ssp</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
  </filter-mapping>
</web-app>

サーブレットが1度受けて、そこからフォワードする想定で書いています。

続いて、サーブレット。
src/main/scala/example/servlet/ScalateExampleServlet.scala

package example.servlet

import java.io.IOException
import java.util.Date

import javax.servlet.ServletException
import javax.servlet.annotation.WebServlet
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}

class ScalateExampleServlet extends HttpServlet {
  @throws(classOf[ServletException])
  @throws(classOf[IOException])
  override protected def doGet(request: HttpServletRequest, response: HttpServletResponse): Unit = {
    response.setCharacterEncoding("UTF-8")


    request.setAttribute("now", new Date)
    request.setAttribute("languages", List("Java", "Groovy", "Scala", "Clojure"))

    request.getRequestDispatcher("/WEB-INF/template/web-sample.ssp").forward(request, response)
  }
}

テンプレートで使用したい値を、HttpServletRequest#setAttributeでバインドして、SSPにフォワードします。

SSPテンプレートはこちら。

#import(java.util.Date)
<%@ val now: Date %>
<%@ val languages: List[String] %>
<html>
  <head><title>Scalate SSP Example</title></head>
  <body>
    <h1>Scalate SSPのサンプルです</h1>
    <p>現在時刻:${now.toString}</p>
    <p>JavaVMプログラミング言語:</p>
    <ul>
      #for (l <- languages)
        <li>${l}</li>
      #end
    </ul>
  </body>
</html>

これでsbtでcontainer:startした後に、http://localhost:8080/scalate-exampleにアクセスすると結果を確認することができます。

この状態だとテンプレートの変換結果およびコンパイル結果が/tmpにできてしまうので、TemplateEngineの設定をします。

Configuring the TemplateEngine in your web app
http://scalate.fusesource.org/documentation/user-guide.html#Configuring_the_TemplateEngine_in_your_web_app

こちらのドキュメントによると、scalate.Bootというクラスを作成して、runメソッドを実装すればいいようです。Liftっぽいですね。
src/main/scala/scalate/Boot.scala

package scalate

import java.io.File

import org.fusesource.scalate.TemplateEngine
import org.fusesource.scalate.util.Logging

class Boot(engine: TemplateEngine) extends Logging {
  def run: Unit = {
    engine.workingDirectory = new File("./tmp")
  }
}

ドキュメントにimportなしで突然書かれているLoggingというトレイトは、org.fusesource.scalate.util.Loggingらしいです。
これで、TemplateEngineをカスタマイズすることができます。

ただ、こう設定しても、確かにテンプレートの変換結果は設定した場所に出力されるのですが、/tmp/scalate-xxxxx-workdirディレクトリはできてしまうという…。