Thymeleaf をPlayframework2.2.Xで無理やり使ってみた。
Java のテンプレートエンジン - 謎言語使いの徒然 でさくっと見たテンプレートを、じゃぁPlayframeworkでどうやるんだろうと、ドキュメント眺めながらやってみた。
で、まずはファイルが何処に配置されてるのかを返すクラスを作成。
package utils import org.thymeleaf.resourceresolver.{FileResourceResolver, IResourceResolver} import org.thymeleaf.TemplateProcessingParameters import java.io.InputStream class PlayThymeResourceResolver(viewPath: String) extends IResourceResolver { lazy val fileResourceResolver = new FileResourceResolver def getName: String = "PLAY_RESOURCE_RESOLVER" def getResourceAsStream(templateParameters: TemplateProcessingParameters, resourceName: String): InputStream = { this.fileResourceResolver.getResourceAsStream(templateParameters, s"$viewPath:$resourceName") } }
それをテンプレートで食うようにして
package utils import org.thymeleaf.templateresolver.TemplateResolver class PlayThymeTemplateResolver(val viewLookupPath: String) extends TemplateResolver { setResourceResolver(new PlayThymeResourceResolver(viewLookupPath)) }
テンプレートエンジンでは多言語化対応と、Mapで突っ込めるようにしておく
package utils import org.thymeleaf.{Arguments, TemplateEngine} import org.thymeleaf.messageresolver.{MessageResolution, AbstractMessageResolver} import play.api.i18n.Messages import org.thymeleaf.context.Context import scala.collection.JavaConversions._ class PlayTemplateEngine extends TemplateEngine { setMessageResolver(new AbstractMessageResolver { def resolveMessage(p1: Arguments, p2: String, p3: Array[AnyRef]): MessageResolution = { new MessageResolution(Messages(p2, p3)) } }) def process(path:String, variables: Map[String, AnyRef]):String = { val ctx = new Context() ctx.setVariables(variables) process(path, ctx) } }
後はこれをシングルトンにでもしておけば
package utils import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver import org.thymeleaf.resourceresolver.ClassLoaderResourceResolver import org.thymeleaf.TemplateEngine import play.api.Play object PlayTemplateEngine { lazy val templateEngine = { val config = Play.current.configuration val engine = new PlayTemplateEngine val path = config.getString("thymeleaf.path").getOrElse("app/views/") val suffix = config.getString("thymeleaf.suffix").getOrElse(".html") val mode = config.getString("thymeleaf.mode").getOrElse("HTML5") val ttl = config.getLong("thymeleaf.ttl").getOrElse(60000L) // default 1minute val templateResolver = new PlayThymeTemplateResolver(path) templateResolver.setSuffix(suffix) templateResolver.setTemplateMode(mode) templateResolver.setCacheTTLMs(ttl) templateResolver.setCharacterEncoding("UTF-8") engine.setTemplateResolver(templateResolver) engine } }
Controller で呼べる
def sample = Action { implicit request => val ctx = new Context() ctx.setLocale(lang.toLocale) ctx.setVariable("name", "行くぜおい!") val res = Template.templateEngine.process("sample", ctx) Ok(res).as("text/html") }
そして、views にテンプレートを配置して出来上がり。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Test</title> </head> <body> <h1 th:text="${name}">Hello Sample</h1> </body> </html>
日本語化対応の扱いが Play と Thymeleaf で異なるので作ったメソッドがそのまま呼べない図。 ただ、レスポンスに「as」入れないと、text/plain で返ってしまうので、何か考えないとだめっぽい。