SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Google App Engine/JavaによるScala/Liftアプリケーション開発

Google App Engine/JavaによるScala/Liftアプリケーション開発(前編)

Liftアプリケーション開発の基本とDataStoreの利用

ViewとTemplateの作成

 Modelができたところで、Modelを利用して検索や保存を行う画面を作成します。ViewとTemplateの詳細については「Scala+LiftフレームワークのView/Template」を参照してください。

登録されているイベントを一覧表示するTopページ

 まずは、Topページです。このページでは、登録されているイベントの一覧を表示するようにします。

図3:Topページ
図3:Topページ

 最初に、テンプレートを作成しましょう。src/main/webapp/index.htmlを、ダウンロードサンプルに含まれる同名のファイルと同じ内容に置き換えます。このテンプレートは、次に作成するEventSnippetのlist関数を呼び出して、イベントの一覧が出力されるようになっています。

 次は、このindex.htmlから呼び出されているEventSnippetの作成です。"src/main/scala/demo/snippet"に、以下の内容でEventSnippet.scalaを作成します。

[リスト7]EventSnippet.scala
package demo.snippet
  ...中略...
// イベントの情報を表示するSnippet
class EventSnippet{
  /** 日付フォーマット */
  val formatter = new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm")
  formatter.setTimeZone( TimeZone.getTimeZone( "Asia/Tokyo" ))

  // implicit conversionを利用して,自動的にStringとDateが変換されるように定義
  implicit def date2String( d:Date ):String = formatter.format( d ) // *1   implicit def string2Date( s:String ):Date = formatter.parse( s ) 

  // イベントの一覧を表示します。
  def list(xhtml: NodeSeq): NodeSeq = { // *2
    // maxで30件を検索し、bind関数で一覧を出力
    Event.findAll(30) flatMap { e =>
      bind( "event", xhtml,
        "id" -> e.id.get,  "name" -> e.name, "description" -> e.description,
        "fromDate" -> date2String( e.fromDate ), "toDate" -> date2String( e.toDate ),
        "place" -> e.place, "join" -> e.join, "count" -> e.count,
        "save" -> SHtml.link("save/"+ e.id.get, () =>{} , Text("編集する") )
      )
    }
  }
}

 *1で、implicit conversionを利用してString型とDate型が自動的に変換されるようにしています。

 *2が、index.htmlから呼び出されるlist関数です。Modelとして作成したEventオブジェクトのfindAll関数を呼び出して、一覧に表示するEvent情報をListで取得し、bind関数で内容を出力しています。

イベントを登録/修正するページ

 イベントを登録するフォームを作成します。

図4:登録画面
図4:登録画面

 まずは、「src/main/webapp」フォルダにsave.htmlというファイル名で、ダウンロードサンプルに含まれる同名のファイルと同じ内容のものを用意します。このテンプレートファイルは、EventSnippetのsave関数でフォームが出力されるようになっています。

 フォームを出力するsave関数を、先ほど作成したEventSnippet.scalaに追加しましょう。追加する内容は、リスト8の通りです。

[リスト8]EventSnippet.scalaへ保存用の関数を追加
  //  イベント登録フォームの表示と、Submit時の保存を行います。
  def save( xhtml:NodeSeq ) = {
    // urlからidを取得し、idが指定されていたら
    // データストアから検索する
    val event =  S.param("id") match {
      case Full(id) =>  Event.find( id.toLong )
      case Empty => None
      case Failure(msg, _, _ ) =>
        S.error( msg )
        None
    } // *1

    // フォームの入力内容を保持するための変数 *2     val id = event map{ _.id } getOrElse( None )
    var name = event map{ _.name } getOrElse("")
    var description = event map{ _.description } getOrElse("")
    var fromDate = event map{ _.fromDate } getOrElse( new Date )
    var toDate = event map{ _.toDate } getOrElse( new Date )
    var place = event map{ _.place } getOrElse("")
    val join = event map{ _.join } getOrElse( 0L )
    var count = event map{ _.count } getOrElse( 10 ) toString

    // Submit時に呼び出されて、入力内容を基にデータストアへ保存する関数
     def doSave = { // *5
      Event.save(
        Event( id, name, description, fromDate,toDate,
          place, join, count.toLong )
      )
      redirectTo("/index") // 保存後はTopページへリダイレクト
    }

    // bind関数を利用してフォームを出力
    bind( "event" , xhtml, // *3
      "name" -> SHtml.text( name, name = _ ),
      "description" -> SHtml.textarea( description, description = _,
        "cols" -> "40",  "rows" -> "6" ),
      "fromDate" -> SHtml.text( fromDate, fromDate = _ ),
      "toDate" -> SHtml.text( toDate, toDate = _ ),
      "place" -> SHtml.text( place, place = _ ),
      "join" -> join,
      "count" -> SHtml.text( count, count = _ ),
      "save" -> SHtml.submit( "Save", doSave _, "class"->"button") // *4
    )
  }

 このsave関数は、リクエストパラメータにidがある場合は、*1でidを基にEventオブジェクトのfind関数を呼び出してデータストアを検索します。idに対応するデータがある場合は、フォームの初期値として設定しておくことで、修正画面としても利用できるようになっています。

 *2から始まるvar変数は、フォームの入力内容を保存しておくための変数です。bind関数でフォームの各コンポーネントに割り当てられた関数オブジェクトは、入力値をこのvar変数に代入するようになっているため、submitされた時にはvar変数にはフォームの入力値が設定されていることになります。

 *3は、おなじみのbind関数でフォームを出力しています。*4でsubmitボタンを生成し、submit時の処理として*5のdoSave関数が登録されています。

 doSave関数は、フォームの入力値が保存されているvar変数の値を基にEventクラスを作成して、Eventオブジェクトのsave関数に渡してデータストアへの保存を実行しています。保存後は、Topページへリダイレクトされるようになっています。

 このような、bind関数でのフォームの出力と、submit時にdoSave関数が呼び出されて保存を実行するような実装の形は、Liftのフォーム処理の基本形といってもよいでしょう。

次のページ
動作確認

この記事は参考になりましたか?

Google App Engine/JavaによるScala/Liftアプリケーション開発連載記事一覧
この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 尾崎 智仁(オザキ トモヒト)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/5004 2010/04/16 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー