• ログインログイン
  • 新規登録新規登録

MENU

流行の技術に実際に触れてみよう 「Scala」と「PlayFramework」(7)

連載流行の技術に実際に触れてみよう 「Scala」と「PlayFramework」

ScalaとはJVM上で動作する関数型オブジェク指向言語です。簡潔な文法と実効速度に定評があり、国内でも徐々に浸透してきています。 流行の技術に実際に触れてみながら、動くものを作っていく開発レシピです。

前回までのプログラミング学習コラムに続き7回目の勉強内容です。

今回はこれまでの連載の締めくくりとして、PlayFrameworkを使用して実際に簡単なWebアプリケーションを作ってみようと思います。

今回の記事では、以下のような流れで説明を進めていければと思います。

■目次

  • 制作するWebアプリケーションの概要
  • 設定ファイル
  • モデル(Anorm)
  • コントローラ
  • View(テンプレート)
  • おまけ:テキストエディタ

※今回はかなりコードを編集するので、何かしらの統合開発環境かテキストエディタを用意することをおすすめします。

制作するアプリケーションの概要

1回目の連載で予告した通り、Twitterライクなミニブログアプリケーションを作ってみようと思います。 トップ画面につぶやきフォームがあり、つぶやくとつぶやきがブラウザに反映される簡単なものです。

またAPIを利用して、データベースに入っているつぶやきをJSONにして配信する処理も作ってみたいと思います。

$ play new miniblog

設定ファイル

application.conf を開き、データベースの設定ファイルを編集します。

# The application languages
# ~~~~~
# 日本語に設定
application.langs="ja"
# Database configuration
# ~~~~~
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
#
db.default.driver=org.h2.Driver #ここのコメントアウトを外す
db.default.url="jdbc:h2:mem:play" #ここのコメントアウトを外す
# db.default.user=sa
# db.default.password=""

これでJ2DBという仕組みを使ってデータベースアクセスを行えます。更にconfディレクトリにdefaultフォルダを作成し、その中に 1.sql を作成します。

モデル

今回はモデルにAnormを使用する関係でデータベースのテーブル定義などをSQLで記述します。データベースはJava内蔵のH2 Databaseです。

今回製作するアプリケーションに必要なテーブルはツイートを登録するテーブル1つだけです。1.sqlに以下のSQLを記述してください。

# --- !Ups
CREATE SEQUENCE tweet_id_seq;
CREATE TABLE tweet(
 id integer NOT NULL DEFAULT nextval('tweet_id_seq'),
 body varchar(140) NOT NULL,
 created timestamp NOT NULL
);
# --- !Downs
DROP TABLE tweet;
DROP SEQUENCE tweet_id_seq;

テーブル内容ははつぶやきId,つぶやき本文、作成日時となっております。 注目すべき点はコメントアウトされた、 !Ups と !Downs です。

!Ups 以下は前回の状態から更新する最新の状態について記述します。!Downs 以下は今回の状態から前回の状態へ戻すためのSQLを書きます。

DBの構成管理SQLで行うようなものです。今回は起動時にツイートテーブルを作成し、終了時にドロップするという処理が入っていますね。

次はこのテーブルと対応したモデルクラスを作っていきましょう。/app ディレクトリ以下にmodelsフォルダを作成します。その中に Tweet.scala を作成します。さて、モデルの定義をしていきましょう。

# Tweet.scala
package models
import anorm._
import anorm.SqlParser._
import java.util.Date
import org.joda.time._
import play.api.db._
import play.api.Play._
case class Tweet(
 id:Long,
 body:String,
 created:Date)
object Tweet{
 val simple = {
 get[Long]("id") ~
 get[String]("body") ~
 get[Date]("created") map{
 case id~body~created =>
 Tweet(id,body,created)
 }
 }
 def get_all = {
 DB.withConnection { implicit c =>
 SQL(
 "select * from tweet order by created desc"
 ).as(simple *)
 }
 }
}

今回はケースクラスにテーブル定義を書いて、オブジェクトにモデルの機能を書くことにします。Playt2.1に標準搭載されている、Anormというモデルライブラリを使用します。

Anormは基本的にプログラマがSQLを直接書く事を強要し、Anormはそれを書きやすくする機能を提供します。ORマッパーが生成したSQLがわからずにデバッグに苦しんだことがある人はこのような実装になる理由がわかると思います。

次はこのモデルを操作するコントローラを実装してみましょう。

コントローラ

app/controllers/以下に TweetController.scala を作成してください。

package controllers
import play.api._
import play.api.mvc._
import models._
import play.api.data._
import play.api.data.Forms._
import play.api.libs.json.Json
object TweetController extends Controller {
 def timeline = TODO
 def tweet = TODO
 def deleteTweet = TODO
 def rest = TODO
}

routes を開き、コントローラのアクションを関連つけていきましょう。

GET / controllers.Application.index
GET /timeline controllers.TweetController.timeline
# crud
POST /tweet controllers.TweetController.tweet
POST /tweet/:id/delete controllers.TweetController.deleteTweet(id: Long)
# rest
GET /rest controllers.TweetController.rest
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)

routes の書き方は前回の記事で紹介した通りなので割愛させて頂きます。今回はタイムラインとつぶやく処理、つぶやき削除、最新のつぶやきを公開ApiとしてJSONで返す処理を実装していきます。

ここで、一旦 $ play run して、 localhost:9000/timelie などにアクセスしてみましょう。すると、青い画面にTODOと書かれた画面が映ると思います。

これは実装していないけど、今後実装する予定の部分を明示的に示すことができるPlayFrameworkの機能です。コントローラの関数を定義しておきたい場合はとても便利に使えます。

今回は全てのコントローラのアクションをTODOにしてしまったので、早速タイムラインから実装していきましょう。

# TweeetController.scala
/**
** フォームを定義
** Validationもここに書きます。
**/
tweetForm = Form(
 "body" -> nonEmptyText(maxLength=140)
)
def timeline = Action{
 Ok(views.html.index(tweetForm, Tweet.get_all))
}

Twitterのタイムラインにはつぶやく画面とタイムラインのつぶやきを表示する機能があります。 つぶやきを取得する処理はモデルで作成しましたので、それをViewにバインドする部分とつぶやくフォームをここに定義しました。

今回はTwitterはひとつのつぶやきにつき140文字の制限とつぶやきの内容がブランクだと投稿できないように設定しました。つぶやきのPOST処理も一緒に作ってしまいましょう。

def tweet = Action{ implicit c =>
 tweetForm.bindFromRequest.fold(
 errors=> BadRequest(
 views.html.index(errors, Tweet.get_all)),
 body => {
 Tweet.post_tweet(body)
 Redirect(routes.TweetController.timeline)
 })
}
def deleteTweet(id:Long) = Action{
 Tweet.delete_tweet(id) 
 Redirect(routes.TweetController.timeline)
}

名前の通りの処理です。Tweet.scalaにつぶやき削除のSQLも足しましょう。

def delete_tweet(id:Long) = {
 DB.withConnection { implicit c =>
 SQL(
 """
 delete from tweet where id={id}
 """
 ).on(
 'id -> id
 ).executeUpdate()
 }
}

on以下で文字列と変数のバインドを行っています。ここではidをバインドして、Whereに使用してつぶやきを取得。それをDeleteしています。

ビュー

ビューに反映していきましょう。main.scala.htmlはひな形のまま使用し、こちらでは main.scala.htmlをカスタマイズしていきます。テンプレートについては前回の記事で説明しましたので、細かな説明は割愛します。

今回、コントローラからビューに渡したいデータはつぶやきのリストとフォームデータですので、ビュー側でそれを受け取るようにします。

@(tweetForm: Form[String], tweets: List[Tweet])
@import helper._
@main("TwitterApplication") {
 @form(routes.TweetController.tweet()){
 @textarea(tweetForm("body"))
 <input type="submit" value="tweet" />
 }
 @for(tweet <- tweets){
 <div>
 <div class="body">@tweet.body</div>
 <div class="created">@tweet.created</div>
 @form(routes.TweetController.deleteTweet(tweet.id)){
 <input type="submit" value="delete" />
 })
 </div>
 }
}

1行目で引数を受け取り、@form でroutesからActionを参照し、それに合ったバインドを行っています。 とてもシンプルな記法ですね。興味のある方はHTMLタグと比較しながら呼んでみてください。

完成

これでTwitterのつぶやき、つぶやき削除、つぶやき一覧の処理が実装できました。しかし、これでは物足りないので、データベースのつぶやきをJSONとして返し、擬似公開APIを作ってみようと思います。

JSONを返す

実はroutesやTweetControllerにはあらかじめ書いてありましたので、引き続き穴埋める形式で続けていきます。

# TweetController.scala
def rest = Action{
 val tweets : List[Tweet]= Tweet.get_all
 val list = for( e <- tweets) yield {
 Map(
 "id" -> e.id.toString,
 "body" ->e.body.toString,
 "created" -> e.created.toString
 )
 }
 Ok(Json.toJson(list))
}

ツイートを全てリストで受け取り、リストの中のデータを辞書としてバインドさせています。最後に辞書をJSON形式に出力する関数を渡し、200を返せば実装完了です。

まとめ

いかがでしたか? ScalaとPlayFrameworkを6回に分けて紹介させて頂きました。最後まで呼んで頂いた方にはScalaやPlayFrameworkの魅力の一部は伝わったと思います。

しかし、内容としてはScalaやPlayFrameworkのほんの一部しか紹介できていません。次は是非自分で調べ、手を動かしながら実践してみてください。

今回のサンプルソースはこちらにアップロードしておきました。 ぜひ参考にして頂ければと思います。

おまけ:ScalaやPlayFrameworkに対応しているテキストエディタ

Scalaに対応しているエディターは自分の知る限りだと、EmacsVimSublimeText2TextMateIntelliJ IDEAEclipseと人気のあるエディタの多くは対応しています。

中でも特にのおすすめなものはIntelliJ IDEA(有料)とSublimeText2EmacsのScala向け開発環境のENSIMEです。

JavaやC++など静的な型付けでコンパイルする言語は統合開発環境ととても相性が良いのでIDE(統合開発環境)が好きな人にはIntelliJ IDEAがおすすめです。IntelliJ IDEAは有料になるのですが、魅力はScalaだけでなく、PlayFrameworkにも対応している点で、ファイル移動や補完、デバッガーなどIDEらしい機能を提供してくれます。

また、エディター派の人にはSublimeText2やTextMateが良いと思います。SublimeText2のPlayFramework向けの拡張は株式会社シャノンさんのブログがとても参考になります。参考までに。

オススメ記事一覧

もっと見る
完全無料!

1で登録完了!

エンジニアの仕事・年収や選考ノウハウ記事が読めるほか、
会員にはプログラミング講習やES・面接対策などリアルな無料サポートも充実。
ここだけの求人情報も多数。

今すぐ新規会員登録
Page Top