scalatra で作ったプロジェクトを stand alone で使用できるように
scalatra で作ったプロジェクトを jetty の stand alone 環境で使用できるようにする。
jetty を組込み standalone で使いたい。
仕事のチーム内の情報共有用のサイトを scalatra で作ってみたのですが、実際に稼働させるのに jetty の standalone な状態で稼働させたいので scalatra のGuide の deployment -> standalone を参考に設定しました。
まずは jetty ランチャーをドキュメント通りに追加。 次に project/build.scala を これまた ドキュメント通りに変更 その後 プロジェクト全体を一つの jar ファイルにまとめて実行できるように sbt のプラグインである sbt-assembly を組み込む。
project/plugins.sbt に
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.9.0")
を追加
build.sbt
import AssemblyKeys._ import sbtassembly.Plugin._ seq(assemblySettings: _*) test in assembly := {} mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) => { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case _ => MergeStrategy.first } }
mergeStrategy の設定はファイルが重複した場合にどれを優先するかの設定となります。
jar ファイル作成
sbt clean assembly
で target/scala2.10/ の下に **-assembly-**.jar
というファイルが作成されました。
作成に結構時間がかかりました。10分ぐらい。
実行
java -jar **-assembly-**.jar
localhost:8080 にアクセスしてみる。
動いているが。。。
問題発生
css がまったく反映されてません。。。
かなり 質素な感じになってます。
Javascript も image も読み込めてませんし。
どうやら
CSS,JS,IMG のディレクトリに格納しているファイルが読めてない
ようです。
そんなの 見たままで当たり前か。
どう設定する
どうやって 使えるようにするのか
今まで tomcat ばかり使っていて jetty 単独で使ったことなかったので
ちょっとはまりましたが jetty のランチャーの設定に {css,js,img}へアクセスできるように
サーブレットの設定を追加するのと、それらをサーブレットがそれらを読み込む設定を行う必要があるようです。
JettyLaunchar.scala を変更
css,js,img については src/main/webapp/{css,js,img} という構造でディレクトリを作っています。
[src] -> [main] -> [webapp] -> [WEB-INF] -> [css] -> [js] -> [img]
これらの ディレクトリの内容にアクセスできるように、最初にドキュメントの見て作った JettyLaunchar.scala を修正します。
FROM
context.addServlet(classOf[DefaultServlet],"/")
…
TO
context.addServlet(classOf[DefaultServlet],"/") context.addServlet(new ServletHolder(new DefaultServlet), "/css/*") context.addServlet(new ServletHolder(new DefaultServlet), "/js/*") context.addServlet(new ServletHolder(new DefaultServlet), "/img/*")
{css,js,img} 用に addServlet で追加します。
最終的には 上のように 3つ追加するのもアレなので、src/main/webapp/assets を作りそこに {css,js,img} を配置し 下のような1行だけ追加することにしました。
[配置]
[src] -> [main] -> [webapp] -> [WEB-INF] -> [assets] -> [css] -> [js] -> [img]
[変更後のソース]
context.addServlet(new ServletHolder(new DefaultServlet), "/assets/*")
リソースを読み込む為のServletを用意
MyDefaultServlet.scala
package refxml import org.eclipse.jetty.servlet.DefaultServlet import org.eclipse.jetty.util.resource.Resource class MyDefaultServlet extends DefaultServlet { override def getResource(resourceString: String): Resource = { val url = this.getClass().getResource(resourceString) Resource.newResource(url) } }
次に JettyLaunchar.scala から 作成した MyDefaultServlet を呼び出すように変更します。
DefaultServlet のところを MyDefaultServlet に変更します。
修正後の JettyLaunchar.scala
package refxml import org.eclipse.jetty.server.Server import org.eclipse.jetty.servlet.{DefaultServlet, ServletContextHandler, ServletHolder} import org.eclipse.jetty.webapp.WebAppContext import org.scalatra.servlet.ScalatraListener object JettyLauncher { def main(args: Array[String]) { val port = if(System.getenv("PORT") != null) System.getenv("PORT").toInt else 8080 val server = new Server(port) val context = new WebAppContext() context setContextPath "/" context.setResourceBase("src/main/webapp") context.addEventListener(new ScalatraListener) context.addServlet(classOf[MyDefaultServlet], "/") context.addServlet(new ServletHolder(new MyDefaultServlet), "/assets/*") server.setHandler(context) server.start server.join } }
build.sbt も修正
assets をリソースに取り込むように build.sbt に以下の設定を追加
... resourceGenerators in Compile <+= (resourceManaged, baseDirectory) map { (managedBase, base) => val webappBase = base / "src" / "main" / "webapp" for { (from, to) <- webappBase ** "*" x rebase(webappBase, managedBase / "main/" ) } yield { Sync.copy(from, to) to } } ...
を追加
再度 jar つくって実行
sbt clean assembly
java -jar **-assembly-**
localhost:8080 にアクセス
今度は スタイルシートも反映された期待通りの動作となりました。
ソースはこちらで公開してます。