【PlayFramework 2.5】データベースへの接続

 Play Frameworkでは、EbeanというORMライブラリが利用できます。SQL文をハードコーディングしなくても、簡単なことはメソッドのみで出来てしまうというメリットがあります。今回は、このEbeanを使って、モデル定義から動作確認までを行います。

設定

 Play Framework2.5では、そのままの状態でデータベースを使うことが出来ません。全てplugins.sbtおよびbuild.sbtに定義し、必要なものを有効化していくという手順をとっています。

 まずは、EbeanをPlay Frameworkから利用できるように、設定を変更する必要があります。

/project/target/plugins.sbtの内容を変更する

// Play Ebean support, to enable, uncomment this line, and enable in your build.sbt using
// enablePlugins(PlayEbean).
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "1.0.0") // コメントアウト解除

/build.sbtの内容を変更する

lazy val root = (project in file(".")).enablePlugins(PlayJava)

 ↓

lazy val root = (project in file(".")).enablePlugins(PlayJava, PlayEbean)

/conf/application.confの内容を変更する

db {
  # You can declare as many datasources as you want.
  # By convention, the default datasource is named `default`

  # https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database
  default.driver = org.h2.Driver    # コメントアウト解除
  default.url = "jdbc:h2:mem:play"  # コメントアウト解除
  default.username = sa             # コメントアウト解除
  default.password = ""             # コメントアウト解除

  # You can turn on SQL logging for any datasource
  # https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements
  #default.logSql=true
}

ebean.default = ["models.*"]        # 追記

 これでH2 Databaseというインメモリデータベースが利用できるようになりました。耳慣れないデータベースですが、各DBの動作を真似るモードもあり、データベースソフトウェア固有の関数などを使わない限りはこのままで十分開発が出来ますので、データベースの選定を遅らせることが出来ます。

 設定が全て完了したら、サーバーを再起動します。基本的には、拡張子.sbtを変更したら、サーバーを再起動する、と覚えてください。

モデルを定義する

 Play Frameworkでは、Ebean ORMを使って、モデルとデータベースを結びつけることができ、データベース上でCREATE文を発行したり、テーブル定義を考えたりといった煩雑な作業が、すべてモデル定義で実現できてしまいます。

 今回は、ユーザー認証のためにユーザー名とパスワードというフィールドを持ったエンティティを定義してみましょう。

ファイルの作成

 /app/配下に、modelsという名前のディレクトリを作成します。

 そこに、User.javaというファイルを作ってください。

モデルの定義

 単純にid、ユーザー名、パスワードのフィールドを定義します。以下のようにしてください。

package models;

import java.util.*;
import javax.persistence.*;
import javax.validation.constraints.NotNull;

import com.avaje.ebean.Model;
import play.data.format.*;
import play.data.validation.*;

@Entity
public class User extends Model {

    @Id
    public Long id;

    @NotNull
    public String userName;

    @NotNull
    public String password;

    public static Finder<Long, User> find = new Finder<Long,User>(User.class);
}

 いくつか、見慣れないアノテーションが出てきたので、解説します。

  • @Entityアノテーションは、これがデータベースに紐づくエンティティであることを示しています。

  • @Id アノテーションは、そのフィールドがプライマリキーであることを示します。これにより、データベース上で列にPRIMARY KEY制約を付与することができます。

  • @NotNullアノテーションは、そのフィールドがNot Nullであることを表します。これにより、データベース上で列にNOT NULL制約を付与することができます。

 保存したら、ページをリロードしてみましょう。ホットリロード機能により、自動的にリコンパイルされ、サーバーを再起動しなくても変更が反映されています。

Database 'default' needs evolution!

 というメッセージが表示されます。発行されるSQL文を読み、問題なければ、Apply this script now!ボタンをクリックします。これでデータベース上にuserテーブルが作成されました。

レコードをINSERTする

 非常に簡単にレコードをINSERTすることができます。簡単に確認するために、ためしにHomeController.javaを編集してみます。

package controllers;

import java.util.*;

import play.mvc.*;
import play.Logger;
import javax.inject.*;

import views.html.*;

import models.*;

/**
 * This controller contains an action to handle HTTP requests
 * to the application's home page.
 */
public class HomeController extends Controller {

    /**
     * An action that renders an HTML page with a welcome message.
     * The configuration in the <code>routes</code> file means that
     * this method will be called when the application receives a
     * <code>GET</code> request with a path of <code>/</code>.
     */
    public Result index() {
        User user = new User();
        user.userName = "username";
        user.password = "password";
        user.save();

        List<User> userList = User.find.all();

        userList.forEach(u->logger.debug(u.userName + " : " + u.password));
        Logger.debug("-- record : " + userList.size());

        return ok(index.render("Your new application is ready."));
    }

}

 追加箇所を順に解説します。

        User user = new User();
        user.userName = "username";
        user.password = "password";
        user.save();

 空のUserインスタンスを作成し、userNameとpasswordフィールドに値をセットします。
 その後のsave()メソッドにより、INSERT文が発行されます。

 このsave()メソッドは、insert/updateをモデルの状態によって適切に発行してくれる優れたメソッドで、レコードの更新時は積極的に使用することになるでしょう。

        List<User> userList = User.find.all();

 ここでは、findというstaticオブジェクトを使い、検索を行います。all()メソッドは、List形式でテーブルのレコードを全件取得するメソッドです。

 Finderクラスは多彩なメソッドを持っており、簡単なSQL文であればメソッドチェーンのみで簡潔にコーディングすることができます。複雑な処理はどうしてもSQL文を書かざるを得ませんが、そうでないなら非常に有効な手段です。
 よければ、ここにAPI仕様書が載っていますので、一読することをお勧めします。

        userList.forEach(u->logger.debug(u.userName + " : " + u.password));
        Logger.debug("-- record : " + userList.size());

 forEachによって順次ログに吐き出していき、内容を確認できるようにします。Playのロガーは、主要な関数がstaticで実装されています。余計なインスタンスを持たなくてよいので、簡潔なコーディングが実現できますね。

確認する

 開いているindexページを更新してみましょう。コンパイルが走った後、以下のログが出力されるはずです。

[debug] application - username : password
[debug] application - -- record : 1

 さらに、もう一度更新してみます。レコードが1件増えることを確認してください。

[debug] application - username : password
[debug] application - username : password
[debug] application - -- record : 2

 更新するたびにレコード件数が1件ずつ増えることが確認できると思います。

最後に

 今回は、Play FrameworkのEbean ORM関連の動作確認を行いました。
 次回は、これらを使って簡単なログイン処理を組んでみたいと思います。

 今回は、PlayFramework2.5で、簡易的なユーザー登録画面を実装します。  前回はこちら Modelを作成する  ログ...