Play frameworkでisucon2アプリを書く-3

このエントリはPlay frameworkひとりアドベントカレンダーの18日目です。

今日はトップページを動的にしてみましょう。

といっても左枠の「最近購入されたチケット」は実装がややこしそうなのでとりあえず放置。 まずは右側のみ実装してみます。

と、ここでおもむろに移植元のperlのコードを見てみます。
/webapp/perl/lib/Isucon2.pm にあります。

get '/' => [qw(recent_sold)] => sub {
    my ($self, $c) = @_;
    my $rows = $self->dbh->select_all(
        'SELECT * FROM artist ORDER BY id',
    );
    $c->render('index.tx', { artists => $rows });
};

※recent_soldのところは無視しましょう

artistテーブルからデータをとってきて表示してるだけですね。

続いてartistテーブルの定義を見ておきましょう。 /webapp/config/database/isucon2.sql にあります。

CREATE TABLE IF NOT EXISTS isucon2.artist (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

そんなわけで、今日は

  • modelを書く
  • viewを書く
  • controllerを書く

の順番でやりましょう。

modelを書く

それではさっそくmodelを作りましょう。

modelといえばEBeanなので、まずはmodelが使えるように /conf/application.conf を設定します。

playでDBを使う設定は下記の通りでした。

とりあえず今はDBはHDBでいいにしましょう。

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
ebean.default="models.*"

ここまで設定できたら、 /app/models/Artist.java を作成しましょう。
modelなクラスは、ひとまず下記を守って作りましょう

  • /app/models/ 直下に作る
  • play.db.ebean.Model を継承する
  • @Entity アノテーションをつける
  • finder を定義する

スクリーンショット 2012-12-15 15.59.05

続いて属性を定義しましょう。 id , name の2つですね。
idはprimary keyなので @Id のアノテーションをつけておきましょう。

package models;

import javax.persistence.Entity;
import javax.persistence.Id;

import play.db.ebean.Model;

@Entity
public class Artist extends Model {

	@Id
	public Integer id;

	public String name;

	public static Finder find = new Finder(
			Integer.class, Artist.class);

}

viewを書く

それでは定義したArtistを使う部分から書いていきましょう。

index.scala.html を更新します。ポイントは2箇所。

  • viewが List を受け取るよう1行目に定義
  • List の中身をとりだしてくるくる回す
@(artists :List[Artist])
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>isucon 2</title>
    <link type="text/css" rel="stylesheet" href="https://netmark.jp/css/ui-lightness/jquery-ui-1.8.24.custom.css">
    <link type="text/css" rel="stylesheet" href="https://netmark.jp/css/isucon2.css">
    <script type="text/javascript" src="https://netmark.jp/js/jquery-1.8.2.min.js"></script>
    <script type="text/javascript" src="https://netmark.jp/js/jquery-ui-1.8.24.custom.min.js"></script>
    <script type="text/javascript" src="https://netmark.jp/js/isucon2.js"></script>
  </head>
  <body>
    <header>
      <a href="https://netmark.jp/">
        <img src="https://netmark.jp/images/isucon_title.jpg">
      </a>
    </header>
    <div id="sidebar">
      <table>
        <tr><th colspan="2">最近購入されたチケット</th></tr>
        <tr>
          <td class="recent_variation">はだいろクローバーZ 横浜アリーナライブ アリーナ席</td>
          <td class="recent_seat_id">00-01</td>
        </tr>
        <tr>
          <td class="recent_variation">はだいろクローバーZ 横浜アリーナライブ アリーナ席</td>
          <td class="recent_seat_id">00-00</td>
        </tr>
      </table>
    </div>
    <div id="content">
<h1>TOP</h1>
<ul>
@for(artist <- artists){
  <li>
    <a href="https://netmark.jp/artist/@artist.id">
      <span class="artist_name">@artist.name</span>
    </a>
  </li>
}
</ul>
    </div>
  </body>
</html>

controllerを書く

定義したmodelをcontrollerで呼び出して、viewに渡しましょう。

package controllers;

import java.util.List;

import models.Artist;
import play.mvc.Controller;
import play.mvc.Result;

public class Application extends Controller {

	public static Result index() {
		List artists = Artist.find.all();
		return ok(views.html.index.render(artists));
	}

}

renderのところでコンパイルエラーが出る場合、 play run して一度アクセスしてからeclipseでプロジェクトを Refresh(F5) すると消えるとおもいます。

それではアクセスしてみましょう。

スクリーンショット 2012-12-16 21.06.52

なにやら怪しいエラー画面が出ました。

これは Evolution なるものでmodelとschemaを連携させているから表示されてます。
いまはschemaがないというエラーが出ているので Apply this script now! をクリックしましょう。

スクリーンショット 2012-12-16 21.09.05

エラーなく表示できました! (ただしデータがありません)

mysqlを使うようにする

ではおもむろにmysqlを使うようにしましょう。

更新するのは2箇所。

  • /project/Build.scala でmysqlドライバを取得するように定義
  • /conf/application.conf でmysqlを使うように定義

下記を更新してplayを再起動すると良い感じにアクセスできるようになります。

import sbt._
import Keys._
import PlayProject._

object ApplicationBuild extends Build {

    val appName         = "isucon2-play"
    val appVersion      = "1.0-SNAPSHOT"

    val appDependencies = Seq(
      // Add your project dependencies here,
      "mysql" % "mysql-connector-java" % "5.1.21"
    )

    val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
      // Add your own project settings here      
    )

}
db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://127.0.0.1:3306/isucon2?useUnicode=true&characterEncoding=UTF-8"
db.default.user=isucon2app
db.default.password=isunageruna

※macのばあい、mysqlはbrewで入れちゃいましょう

brew install mysql
/usr/local/bin/mysql.server start

そして本家isucon2アプリのschema定義とデータを投入します。

/usr/local/bin/mysql -u root < isucon2/webapp/config/database/isucon2.sql
/usr/local/bin/mysql -u root < isucon2/webapp/config/database/initial_data.sql

そしたらブラウザでアクセスして、例のApply〜ボタンを押してみましょう。

スクリーンショット 2012-12-16 21.22.09

あら、なんか出ましたね。もう別途schema定義したので Mark it resolved しちゃいましょう。

スクリーンショット 2012-12-16 21.25.57

デターヽ(`▽´)/

明日からもこの調子で作っていきましょう。


See also