unhurried

コンピュータ関連ネタがほとんど、ときどき趣味も…

Play Framework

ここのところJava製のWebアプリケーションフレームワークについて調べていました。 最近OSS系のイベントでもよく耳にする「Play Framework」について少し整理できたのでまとめてみます。

概要

  • JavaScalaでのWebアプリケーションにおける開発生産性(開発スピード)と柔軟性(変更に対する強さ)の向上を目指すフレームワーク
  • JavaScalaのどちらでもアプリケーションを開発できるが、テンプレートはScalaでのみ記述できる。
  • 「設定より規約」や「MVC」など、Ruby on Railsの設計思想に影響を受けている。

インストール方法

よく使うコマンド

コマンド 説明
activator new [アプリ名] play-java 新しいプロジェクトを作成する
run [port番号] アプリを起動する
compile コンパイルする(通常はアプリへアクセス時に自動で実行される)
eclipse Eclipseプロジェクトに変換する

Eclipseへのインポート方法

  • eclipseコマンドでEclipseプロジェクトに変換する。
  • Eclipseの「インポート」から既存プロジェクトとして取り込む。
  • 自動でimport文を削除する設定をオフにする。
    • プロジェクトプロパティ→Javaエディター→保管アクション→「インポートの編成」のチェックを外す。
  • ビュー用のクラスフォルダーを追加する。
    • プロジェクトプロパティ→Javaのビルド・パス→ライブラリー→クラス・フォルダーの追加
    • 「target/target/scala-2.11/classes_managed」を追加する。
  • (おまけ)SBTを利用してMavenリポジトリから依存関係を解決する方法
    • ※ SBT(Simple Build Tool)はPlayで推奨されているビルドツール
    • Mavenリポジトリで利用したいライブラリを探す
    • SBTタブの内容をコピーし、build.scalaに貼り付ける。
    • プロジェクトを再コンパイルする

build.scala

libraryDependencies ++= Seq(
  javaJdbc,
  ...,
  "com.nimbusds" % "oauth2-oidc-sdk" % "4.13"
)

コマンド

$ clean
$ compile
$ eclipse with-source=true
# Eclipseプロジェクトをリフレッシュする

ビューの作成

  • app/viewsにテンプレート(*.scala.html)を作成する。
    コンパイルが実行されるとviews.html.{ビュー名}というクラスが作成される。
  • 利用できる制御構文
    • if/for/関数/変数/インポート
  • ヘルパーメソッド
    • @helper.form
  • 他のエンドポイントをリンク、フォーム送信先に指定する方法
    • @routes.{Controllerクラス}.{メソッド}
      (routeファイルを逆引きしている?)

Ebean(O/Rマッパー)を利用したDBアクセス

  • DB接続設定

conf/application.conf

db.default.driver = {JDBCドライバ}
db.default.url = {jdbc:で始まるURL}

PlayにバンドルされているH2データベースを利用する場合:

db.default.driver = org.h2.Driver
#データを永続化したい場合は”mem”を”file”に変更する
db.default.url = jdbc:h2:mem:play
  • Ebeanクラス
    • パッケージ名:「models.{クラス名}」(変更可能)
    • play.db.ebean.Modelを継承する。
    • 利用できるアノテーション
アノテーション 説明
@Entity Ebeanクラスに指定する
@Id プライマリーキーを格納するメンバに指定する
@NotNull NotNull制約を利用するメンバに指定する
@CreatedTimestamp 作成日時を格納するメンバに指定する
@Version 更新日時を格納するメンバに指定する
  • 基本的なDB操作
操作 メソッド
INSERT save()
UPDATE update()
DELETE delete()
  • 検索処理
    • play.db.ebean.Finderを利用する。
メソッド 説明
all() 全件検索を行う
byId(Long id) Primary keyでの検索を行う
where(String arg) 任意条件での検索を行う
  • テーブル間の関連 1:N(親子関係)
@Entity public class Child extends Model {
  @Id public Long id;
  @ManyToOne
  @JoinColmunName(name=”parent_id”)
  public Parent parent;
  ...
}
@Entity publi class Parent extends Model {
  @Id public Long id;
  @OneToMany(cascade=CascadeType.ALL, mappedBy=”parent”)
  public List<Child> children = new ArrayList<Child>();
}
Ebean.execute(new TxRunnable() {
  //トランザクションで実行するEbean処理を記述する
});

コントローラの使い方

  • conf/routesにルーティング設定を記述する。
{HTTPメソッド} {パス} {メソッド}
#単純な例
GET /list controllers.Page.showList()
# Pathパラメータ、クエリパラメータを引き渡す
GET /search/:id controllers.Page.search(id :Integer, name :String)
  • Controllerクラスのメソッド
    • play.mvc.Resultを返却するstaticメソッドを作成する。
    • play.mvc.Resultsにレスポンス用のヘルパーメソッドが用意されている。
      • ok, redirect, badRequest, internalServerError, …

セッションとフラッシュスコープ

  • セッションスコープ
    • ユーザーの1セッション中保持される。
    • 最大4KBの文字列のみ格納できる。
  • 動作の仕組み
    • HTTP Cookieを利用して”クライアント”に保存される。
    • クッキーの値は秘密鍵により署名される。(署名が無効な場合は値が無効化される)
    • (クライアントが破棄しない限り)セッションに有効期限が存在しない。
      → セッションにタイムスタンプを格納して独自に有効期間を管理する必要がある。
  • コード例
#セッションへの値の保存
session(“key”, “value”);
#セッションからの値の読み込み
String value = session(“key”);
#セッションの値の削除
session.remove(“key”);
#セッションの破棄
session().clear();
  • フラッシュスコープ(セッションとの違い)
    • データは次のリクエストまで保持される。
    • クッキーの値は署名されない。(ユーザーによって書き換えられる可能性がある)
      → 非Ajaxアプリケーションでのメッセージ(成功/失敗など)のやり取りに利用する。

confファイルの参照

Configuration.root().getString("application.langs")

Bootstrapを利用する方法