Scalatra + Scalate + Morphia 㧠MongoDB ã使ã£ã Web ã¢ããªéçº
以åãSinatraï¼id:fits:20110306ï¼ã expressï¼id:fits:20110409ï¼ã§ä½æãããµã³ãã«ã¨åããã®ã Scalatra + Scalateï¼Scaml 使ç¨ï¼+ Morphia ã®æ§æã§ä½æãã¦ã¿ã¾ããã
ç°å¢ã¯ä»¥ä¸ã®éãã§ãã
- Scala 2.9.0.1
- sbt 0.7.7
- Scalatra 2.0 Snapshot
- Scalate 1.6 Snapshot
- Morphia 1.0 Snapshot
- MongoDB 1.9.0
ãµã³ãã«ã®ã½ã¼ã¹ã¯ http://github.com/fits/try_samples/tree/master/blog/20110521/
ãªããã½ã¼ã¹ã«ã¯ Servlet 3.0 çï¼scalatra-scalate-morphia_servlet3ï¼ãç¨æãã¦ãã¾ããããã¡ã㯠sbt ã® jetty-run ã§ã¯æ£å¸¸ã«åä½ããªãã®ã§ sbt package 㧠war åã㦠Tomcat çã§å®è¡ããå¿
è¦ãããã¾ãã
è¨å®ãã¡ã¤ã«ã®ä½æ
ã¾ããsbt ã使ã£ã¦ããã¸ã§ã¯ããä½æãã以ä¸ã®ããã« Scalatra, Scalate, Morphia ã使ãããã®è¨å®ãè¡ãã¾ããï¼Scala2.9.0.1ã使ç¨ããã«ã¯ãsbt ã§ã®ããã¸ã§ã¯ãä½ææã« 2.9.0-1 ã¨ãããã¼ã¸ã§ã³ãå ¥åããç¹ã«æ³¨æï¼
Web ã¢ããªä½æç¨ã® DefaultWebProject ã extends ããjetty ã§åä½ç¢ºèªããã®ã§ jetty ã®è¨å®ãè¡ãã¾ãã
ãªããsbt package 㧠war ãã¡ã¤ã«ãä½ãå ´åãããã©ã«ãã§ã¯ scala-compiler.jar ãå«ã¾ããã« Scalate ãæ£å¸¸ã«åä½ããªããããwebappClasspath ããªã¼ãã¼ã©ã¤ãã㦠war ãã¡ã¤ã«ã« scala-compiler.jar ã追å ããããã«ãã¦ããç¹ã«æ³¨æã
project/build/ScalatraMorphiaSampleProject.scala
import sbt._ class ScalatraMorphiaSampleProject(info: ProjectInfo) extends DefaultWebProject(info) { //以ä¸ã®è¨å®ã§ war ãã¡ã¤ã«ã« scala-compiler.jar ãå ¥ãããã«ãªã override def webappClasspath = super.webappClasspath +++ buildCompilerJar val jettyVersion = "8.0.0.M3" val scalatraVersion = "2.0.0-SNAPSHOT" val scalateVersion = "1.6.0-SNAPSHOT" val morphiaVersion = "1.00-SNAPSHOT" //jetty 8 ã使ãããã®è¨å® //ï¼groupId ã org.eclipse.jetty ã¨ããç¹ã«æ³¨æï¼ val jettyWebapp = "org.eclipse.jetty" % "jetty-webapp" % jettyVersion % "test" val servletapi = "javax.servlet" % "servlet-api" % "2.5" % "provided" //Scalatra val scalatra = "org.scalatra" %% "scalatra" % scalatraVersion //Scalatra ã® Scalate ãµãã¼ãã¢ã¸ã¥ã¼ã« val scalatraScalate = "org.scalatra" %% "scalatra-scalate" % scalatraVersion //Scalate val scalate = "org.fusesource.scalate" % "scalate-core" % scalateVersion //Morphia val morphia = "com.google.code.morphia" % "morphia" % morphiaVersion //Scalatra ã®ãªãã¸ããªè¨å® val sonatypeNexusSnapshots = "Sonatype Nexus Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" val sonatypeNexusReleases = "Sonatype Nexus Releases" at "https://oss.sonatype.org/content/repositories/releases" //Scalate ã®ãªãã¸ããªè¨å® val fuseSourceSnapshots = "FuseSource Snapshot Repository" at "http://repo.fusesource.com/nexus/content/repositories/snapshots" //Morphia ã®ãªãã¸ããªè¨å® val morphiaSnapshot = "Morphia Repo at Google Code" at "http://morphia.googlecode.com/svn/mavenrepo" }
次㫠web.xml ãã¡ã¤ã«ãä½æãã以éã§ä½æãã Servlet ã®è¨å®ãè¡ãã¾ãã
src/main/webapp/WEB-INF/web.xml
<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_2_5.xsd" version="2.5"> <servlet> <servlet-name>sample</servlet-name> <servlet-class>fits.sample.ScalatraMorphiaSample</servlet-class> </servlet> <servlet-mapping> <servlet-name>sample</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
ã¢ãã«ã¯ã©ã¹ã®ä½æ
ã¢ãã«ã¯ã©ã¹ã¯ id:fits:20110515 ã§ä½æãããã®ãããã±ã¼ã¸åã ããå¤æ´ãã¦ãã®ã¾ã¾ä½¿ãäºã«ãã¾ãã
src/main/scala/models/Book.scala
package fits.sample.models import java.util.{List, ArrayList} import com.google.code.morphia.annotations._ import org.bson.types.ObjectId @Entity(value = "books", noClassnameStored = true) class Book(var title: String, var isbn: String) { def this() = this("", "") @Id var id: ObjectId = null @Embedded var comments: List[Comment] = new ArrayList[Comment]() }
Scalatra ã«ãã Web ãµã¼ãã¼å¦ç
Scalatra ã使ã£ãå¦çã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
Scalate ã使ãããã« ScalateSupport ã with ããã¬ã¤ã¢ã¦ããã¡ã¤ã«ãé©ç¨ãããã templateEngine.layout() ã使ã£ã¦ãã¾ããï¼renderTemplate() ã ã¨ã¬ã¤ã¢ã¦ããã¡ã¤ã«ãé©ç¨ãããªã模æ§ï¼
src/main/scala/ScalatraMorphiaSample.scala
package fits.sample import scala.collection.JavaConverters._ import org.scalatra.ScalatraServlet import org.scalatra.scalate.ScalateSupport import com.google.code.morphia.Morphia import com.mongodb.Mongo import org.bson.types.ObjectId import fits.sample.models._ class ScalatraMorphiaSample extends ScalatraServlet with ScalateSupport { //MongoDBã¸ã®æ¥ç¶è¨å® val db = new Morphia().createDatastore(new Mongo("localhost"), "book_review") beforeAll { contentType = "text/html" } //Topãã¼ã¸è¡¨ç¤º get("/") { //å ¨Bookåå¾ val books: Iterable[Book] = db.find(classOf[Book]).order("title").asList.asScala //å ¨Useråå¾ val users: Iterable[User] = db.find(classOf[User]).order("name").asList.asScala //ã¬ã¤ã¢ã¦ããã¡ã¤ã«ã使ã£ããã¼ã¸æç» templateEngine.layout("index.scaml", Map( "books" -> books, "users" -> users )) } //Bookãã¼ã¸è¡¨ç¤º get("/books") { val books: Iterable[Book] = db.find(classOf[Book]).order("title").asList.asScala templateEngine.layout("book.scaml", Map( "books" -> books )) } //Book追å post("/books") { db.save[Book](new Book(params("title"), params("isbn"))) redirect("books") } //Comment追å post("/comments") { val book = db.get(classOf[Book], new ObjectId(params("book"))) val user = db.get(classOf[User], new ObjectId(params("user"))) book.comments.add(new Comment(params("content"), user)) db.save[Book](book) redirect(".") } ã»ã»ã» }
Scalate(Scaml) ã«ãããã¼ã¸ã®å®ç¾©
Scaml ã§ã® HTML ã¨ã¹ã±ã¼ãå¦çã®åä½ã¯ Haml.js ã¨åãããã§ãã
- = 㧠HTML ã¨ã¹ã±ã¼ãããã
- != 㧠HTML ã¨ã¹ã±ã¼ããããªã
ç¹°ãè¿ãå¦ç㯠Scala ã® for ã使ãã¾ãã
ãªãã使ç¨ããå¤æ°ã®å®£è¨ï¼ä¸è¨ãµã³ãã«ã® "-@ val body: String" ç®æï¼ãå¿ è¦ãªç¹ã«æ³¨æã
ã¬ã¤ã¢ã¦ããã¡ã¤ã«ã¯ WEB-INF/scalate/layouts/ ã«é ç½®ãã¾ããHaml.js ã¨åæ§ã« body å¤æ°ã«åã ã®ãã¼ã¸å 容ãè¨å®ããã¾ãã
src/main/webapp/WEB-INF/scalate/layouts/default.scaml (ã¬ã¤ã¢ã¦ãå®ç¾©)
-@ val body: String !!! 5 %html %title Scalatra + Scalate + Morphia Sample %body != body
body ã®å 容㯠HTML ã¨ã¹ã±ã¼ããããã«ãã®ã¾ã¾åºåããããã®ã§ != ã使ã£ã¦ãã¾ãã
Top ãã¼ã¸ã¯ä»¥ä¸ã®éãã§ãã
templateEngine.layout() ã®ç¬¬äºå¼æ°ã§è¨å®ããããã¤ã³ãå¤æ°ã使ãããã«ãå¤æ°å®£è¨ãå¿
è¦ã¨ãªãç¹ã«æ³¨æãå¿
è¦ã§ãã
ãªããHaml ã¨åæ§ã« #{ã»ã»ã»} ã®è¨è¿°ã使ãã¾ãã
src/main/webapp/WEB-INF/index.scaml (Topãã¼ã¸å®ç¾©)
- import fits.sample.models._ -@ val books: Iterable[Book] -@ val users: Iterable[User] .menu Menu %ul %li %a(href="books") Books List %li %a(href="users") Users List .list Book Comments %form.post(action='comments' method='post') %select(name='user') - for(u <- users) %option(value='#{u.id}')= u.name %select(name='book') - for(b <- books) %option(value='#{b.id}')= b.title %input(name='content' type='text') %input(type='submit' value='Add') - for(b <- books) %ul %li= b.title %ul - for(c <- b.comments) %li #{c.content} : #{c.user.name}, #{c.createdDate}
å®è¡
ã¾ããMongoDB ãå®è¡ãã¦ããã¾ãã
MongoDB å®è¡ä¾
> mongod -dbpath db
次ã«ãsbt ã® jetty-run ã³ãã³ãã§ãã«ãã¨å®è¡ãè¡ãã¾ãã
jetty-run ã«ããå®è¡ä¾
ã»ã»ã»> sbt [info] Building project scalatra-scalate-morphia-sample 1.0 against Scala 2.9.0-1 [info] using ScalatraMorphiaSampleProject with sbt 0.7.7 and Scala 2.7.7 > jetty-run
åæ¢ãããã¨ã㯠jetty-stop ãå®è¡ãã¾ããï¼jetty-restart ã jetty-reload ãããã¾ãï¼
http://localhost:8080/ ã«æ¥ç¶ãã㨠Sinatra çï¼id:fits:20110306ï¼ã express çï¼id:fits:20110409ï¼ã®ãµã³ãã«ã¨åæ§ã®ç»é¢ã表示ããã¾ãã
Top ãã¼ã¸ã®è¡¨ç¤º HTML ä¾
<!DOCTYPE html> <html> <title>Scalatra + Scalate + Morphia Sample</title> <body> <div class="menu">Menu</div> <ul> <li> <a href="books">Books List</a> </li> <li> <a href="users">Users List</a> </li> </ul> <div class="list">Book Comments</div> <form class="post" action="comments" method="post"> <select name="user"> <option value="4dd13c6a3d297b41fda3ca3f">tester1</option> <option value="4dd13c723d297b41fea3ca3f">ãã¹ã¿ã¼</option> </select> <select name="book"> <option value="4dd149893d297b41def1f261">ãã¡ã¤ã³é§åè¨è¨</option> <option value="4dd149663d297b41ddf1f261">ããã°ã©ãã³ã°Scala</option> </select> <input name="content" type="text"/> <input type="submit" value="Add"/> </form> <ul> <li>ãã¡ã¤ã³é§åè¨è¨</li> <ul> <li> 1 : tester1, 2011å¹´5æ17æ¥ </li> <li> test : ãã¹ã¿ã¼, 2011å¹´5æ17æ¥ </li> </ul> </ul> <ul> <li>ããã°ã©ãã³ã°Scala</li> <ul> <li> aaa : tester1, 2011å¹´5æ17æ¥ </li> <li> ãã¹ãã³ã¡ã³ã : ãã¹ã¿ã¼, 2011å¹´5æ17æ¥ </li> </ul> </ul> </body> </html>