今度は、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ディレクトリはできてしまうという…。