Lift + Maven で始める Webサイト開発
先日のScalaハッカソンでは、あまりコーディングはできませんでしたが、LiftWebフレームワークを使っての開発を @NKJason さんにいろいろ教えて頂いたので、忘れないうちに書いておきます。LiftとATNDのAPIを使ってATNDのイベント検索機能を実装しました。自分でも実装してみながら、流れを書きます。ビルドツールは何でもいいのだと思いますが、今回はMavenです。
環境は、
- MacOSX10.6
- Maven2.2.1
- Scala2.8.0
プロジェクトの準備
MavenのリポジトリからデフォルトのLiftプロジェクトをダウンロードして配置します。
#!/bin/bash mvn archetype:generate -U \ -DarchetypeGroupId=net.liftweb \ -DarchetypeArtifactId=lift-archetype-basic_2.8.0.RC7 \ -DarchetypeVersion=2.1-SNAPSHOT \ -DarchetypeRepository=http://scala-tools.org/repo-snapshots \ -DremoteRepositories=http://scala-tools.org/repo-snapshots \ -DgroupId=$2 -DartifactId=$1
何度も使いそうなので、シェルにしました。
この辺の設定内容は、もう少し詳しく確認してから追記します。
ひとまず、-DgroupIdはパッケージ名を、-DartifactIdはプロジェクト名を
指定するところなので、オプションで指定するようにしました。
lift_setup Hello net.knserve.lift.hello
上記のコマンドを実行するとカレントディレクトリにデフォルトのプロジェクトが作られます。
ソースを変更する前にとりあえず動かしてみましょう。
作成されたプロジェクトのルートディレクトリ(pom.xmlがある場所)に移動して、
mvn package mvn jetty:run
と順番に打つとビルドされ、jettyが起動した状態になります。
localhost:8080にアクセスすれば、何も変更されていないLiftによる画面が見えるはずです。
開発作業
Liftでは主にテンプレートとスニペットというクラスを使った開発を行うようです。
- スニペットのクラスの中でビューとなるhtmlタグをbindするように書く。
- bindしたhtmlタグをテンプレートから呼び出す。
というような開発手順になります。その辺りの情報は公式wikiで言うとこの辺りでしょうか。
webapp配下です
─ webapp ├── WEB-INF │ └── web.xml ├── images │ └── ajax-loader.gif ├── index.html ├── static │ └── index.html └── templates-hidden ├── default.html └── wizard-all.html
Scalaのソースコードが置かれているパッケージ配下です。
─ net └── knserve └── lift └── hello ├── comet ├── lib │ └── DepencyFactory.scala ├── model │ └── User.scala ├── snippet │ └── HelloWorld.scala └── view
HelloWrold.scalaをSample.scalaという名前にコピーして編集していきます。
編集前のソースです。
package net.knserve.lift.hello { package snippet { import _root_.scala.xml.{NodeSeq, Text} import _root_.net.liftweb.util._ import _root_.net.liftweb.common._ import _root_.java.util.Date import net.knserve.lift.hello.lib._ import Helpers._ class HelloWorld { lazy val date: Box[Date] = DependencyFactory.inject[Date] // inject the date def howdy(in: NodeSeq): NodeSeq = Helpers.bind("b", in, "time" -> date.map(d => Text(d.toString))) /* lazy val date: Date = DependencyFactory.time.vend // create the date via factory def howdy(in: NodeSeq): NodeSeq = Helpers.bind("b", in, "time" -> date.toString) */ } } }
どういうページにするか考え中...。
結局あんま思いつかなかったのでソースを解説します。
基本的に@NKJason さんのコードのままですが、
メソッド名などは変えて、コメントを加えました。
package com.snssuite.atnd { package snippet { import _root_.scala.xml.{NodeSeq, Text} import _root_.net.liftweb.util._ import _root_.net.liftweb.common._ import _root_.java.util.Date import com.snssuite.atnd.lib._ import Helpers._ //追加でインポート import scala.xml._ import net.liftweb.util.HttpHelpers._ import net.liftweb.http._ class AtndSearch { def searchBox( in: NodeSeq ): NodeSeq = { //searchパラメータを取得して格納 //検索窓のデフォルト値として利用 var keyword = S.param("search") openOr "" //検索パラメータを付けたURLへリダイレクト def search() = { S.redirectTo("/static/index?search=" + urlEncode( keyword )) } //コンポーネントをバインド Helpers.bind("searchbox", in , "input" -> SHtml.text( keyword, keyword = _ ) , "submit" -> SHtml.submit("検索", search)) } def resultList( in: NodeSeq ): NodeSeq = { //searchパラメータを取得 val keyword = S.param("search") openOr "" //searchパラメータからURLを作成して、xmlで結果を得る val xml = XML.load("http://api.atnd.org/events/?keyword_or=" + urlEncode( keyword ) + "&format=xml") //events配下のeventの一覧をリストで取得 val xmlList = ( xml \\ "events" \\ "event" ) xmlList.flatMap( xm => Helpers.bind("resultlist", in , "title" -> (xm \\ "title").map(_.text).mkString , "event_id" -> SHtml.link("http://atnd.org/events/" + (xm \\ "event_id").map(_.text).mkString , () =>"" , scala.xml.Text((xm \\ "event_id").map(_.text).mkString)) )) } } } }
<lift:surround with="default" at="content"> <!-- searchBoxメソッドのバインド --> <lift:AtndSearch.searchBox form="POST"> <searchbox:input /> <searchbox:submit /> </lift:AtndSearch.searchBox> <table border="1"> <tr> <td>title</td> <td>eventLink</td> </tr> <!-- resultListメソッドのバインド --> <lift:AtndSearch.resultList> <tr> <td><resultlist:title /></td> <td><resultlist:event_id /></td> </tr> </lift:AtndSearch.resultList> </table> </lift:surround>