前回までのプログラミング学習コラムに続き6回目の勉強内容です。
PlayFrameworkを使ってみよう
PlayFrameworkは、非常に強力なWebフレームワークです。今回は以下のような流れに沿って、実際にPlayFrameworkについてコードを交えながら解説してみたいと思います。今回はPlayFrameworkの基本的な考え方や特徴を説明し、次回の記事で実践的なWebアプリケーションを作っていきます。
- PlayFrameworkとは
- PlayFrameworkの特徴
- PlayFrameworkを動かす環境の構築
- HelloWorld!をPlayFrameworkでやってみよう
1. PlayFrameworkとは
PlayFrameworkとはオープンソースのScala・JavaのWebフレームワークです。バージョン1の頃はJavaで実装されていて、パッチでScalaをサポートするスタイルでしたが、2以降はScalaでの実装でJavaもサポートというスタイルにシフトしました。
現在は全面的にScalaに書きなおされています。 また、Play2からはScalaの提供企業であるTypeSafeのTypeSafeStackの一部として提供されています。
コーディングの上での「PlayFramework」は一言で言うと「Scala on Rails」です。Ruby on Rails のように楽しく、高速に”高速な”Webアプリケーションを作ることができます。
Ruby on Rails についてはエンジニアインターンにおいて連載されている文系の私がエンジニアになっていくお話を読んで頂けばと思います。
2. PlayFrameworkの特徴
PlayFrameworkは、以下のような特徴を持っています。
- Railsライクな構成
ScalaはJVM上で動作するWebフレームワークですが、Javaのサーブレットを使用していません。 なので、大量のXmlファイルに悩まされる心配は不要です。 また、構成がほぼRailsと同じなのでRailsに慣れている人はすぐに馴染めると思います。
- 非同期処理モデル
PlayFrameworkは標準で非同期処理をサポートしています。 デフォルトで非同期処理をサポートしているので、C10K問題の対処もバッチリです。 特に自分でなにか特別なコードを書く必要なく、フレームワークが非同期に処理するため、導入の敷居が低いです。
- LLのようなブラウザホットリロード
ソースコードを変更するたびにTomCatを再起動するような事が必要ありません。従来のScalaやJavaのWebアプリケーション開発においてはソースコードをコンパイルし、Warファイルにしてから、TomCatやGlassFishにデプロイし、サーバを再起動し、ブラウザを再起動するという手順で変更を確認していましたが、PlayFrameworkはソースコードを変更すると自動でコンパイルを行うため、ブラウザを再起動するだけで変更を確認することができます。
- 幅広いクラウドサービスがサポートしている
HerokuをはじめとするクラウドサービスがScalaをサポートしているので、Heroku使いの方はすぐにデプロイできます。
3. PlayFrameworkを動かす環境の構築
ここからUnixコマンドを使って環境構築していきます。 PlayFrameworkのバージョンは最新版の2.1で進めさせて頂きます。
(1)最新版のPlayFrameworkをインストール
$ brew install play
(2)新規プロジェクト作成 (お好きなプロジェクト名でどうぞ)
$ play new ApplicationName
コマンドを打つとプロジェクト名とJavaとScalaどちらのバージョンか問い合わせが来るので今回はScalaを選択してください。
(3)サーバを起動
$ cd ApplicationName $ play run
これでScalaのサーバが起動します。 デフォルトではlocalhostの9000番に割り当てられます。 http://localhost:9000/ にアクセスしてください。ページを開くとスタートページが表示されます。
これでScalaとPlayFrameworkの環境構築が完了しました。
4. HelloWorld!をPlayFrameworkでやってみよう
PlayFrameworkのディレクトリ構成は以下のようになっています。
├── README ├── app │ ├── controllers │ │ └── Application.scala │ └── views │ ├── index.scala.html │ └── main.scala.html ├── conf │ ├── application.conf │ └── routes ├── project │ ├── Build.scala │ ├── build.properties │ └── plugins.sbt ├── public │ ├── images │ │ └── favicon.png │ ├── javascripts │ │ └── jquery-1.9.0.min.js │ └── stylesheets │ └── main.css └── test ├── ApplicationSpec.scala └── IntegrationSpec.scala
(注)今回は関係のないフォルダは除外しています
Rails経験者はすぐに同じようなディレクトリ構成になっていることがわかると思います。appディレクトリ以下にモデル、ビュー、コントローラ、confにルーティング処理、projectにビルド設定のファイル、publicに静的なファイルが設置されています。今回は画面にHelloWorldを表示させるところまでやってみたいと思います。
まず、 conf/routes を確認します。
# Routes # This file defines all application routes (Higher priority routes first) # ~~~~ # Home page GET / controllers.Application.index # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.at(path="/public", file)
ここにScalaのルーティングの設定の全てが記述されています。
今回は # HomePageの部分を見ていきます。 ここにGET / controllers.Application.indexを記述されていますが、こちらは ”/” にGETアクセスされた際は controllersフォルダの中にある、Applicationクラスを探索し、index関数を実行すると書いてあります。
Applicationクラスを見てみましょう。
//Application.scala package controllers import play.api._ import play.api.mvc._ object Application extends Controller { def index = Action { Ok(views.html.index("Your new application is ready.")) } }
ここに定義されているindex 関数がOkオブジェクトを返し、Okオブジェクトの中を実行しています。 こちらはviewフォルダにある、 index.scala.html を呼び出しています。index.scala.htmlはPlayFrameworkのテンプレートです。
@(message: String) @main("Welcome to Play 2.1") { @play20.welcome(message) }
@(message: String)でviews.html.indexの引数の文字列を受け取り、 @mainでmain.scala.htmlテンプレートを継承した上で受け取ったmessageを基底テンプレートに渡しています。
※Playのテンプレートは@内にScalaのテンプレートの機能、それ以外はHTMLを書きます。 ※ 分かる人は{{ variable }} や<=% %=>,<?php ?> のようなイメージです。
main.scala.htmlを見てみましょう。
@(title: String)(content: Html) <!DOCTYPE html> <html> <head> <title>@title</title> <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")"> <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")"> <script src="@routes.Assets.at("javascripts/jquery-1.9.0.min.js")" type="text/javascript"></script> </head> <body> @content </body> </html>
1行目に注目です。 titleとContent変数を引数として受け取っています。 タイトルタグとボディの中身を子テンプレートで実装です。再び、index.scala.htmlに戻ります。
@main("Welcome to Play 2.1") { @play20.welcome(message) }
こちらで最初に1つ目の引数であるタイトルにWelcome to Play2.1を渡し、Contentに変数messageを代入したPlay20を代入しています。 ※Play20.welcomeはあらかじめ定義されているテンプレートです。
本当かどうか検証するためにHTMLを見てみましょう。
<!DOCTYPE html> <html> <head> <title>Welcome to Play 2.1</title> <link rel="stylesheet" media="screen" href="/assets/stylesheets/main.css"> <link rel="shortcut icon" type="image/png" href="/assets/images/favicon.png"> <script src="/assets/javascripts/jquery-1.9.0.min.js" type="text/javascript"></script> </head> <body> <link rel="stylesheet" media="screen" href="/@documentation/resources/style/main.css"> <section id="top"> <div class="wrapper"> <h1><a href="/@documentation">Your new application is ready.</a></h1> <nav> <span class="versions"> <span>Browse APIs</span> <select onchange="document.location=this.value"> <option selected disabled>Select language</option> <option value="/@documentation/api/scala/index.html">Scala</option> <option value="/@documentation/api/java/index.html">Java</option> </select> </span> </nav> </div> </section> <div id="news"> <iframe src="http://www.playframework.org/widget?uid=11d0633fe49a6678290079e8ec8681de7174cc3f&version=2.1.3&tag=SCALA" scrolling="no" style="overflow: hidden; display: block; margin: 0 auto; width: 960px; height: 60px"></iframe> </div> <div id="content" class="wrapper doc"> <article> <h1>Welcome to Play 2.1</h1> <p> Congratulations, you’ve just created a new Play application. This page will help you with the few next steps. </p> <blockquote> <p> You’re using Play 2.1.3 </p> </blockquote> <h2>Why do you see this page?</h2> <p> The <code>conf/routes</code> file defines a route that tells Play to invoke the <code>Application.index</code> action whenever a browser requests the <code>/</code> URI using the GET method: </p> <pre><code># Home page GET / controllers.Application.index</code></pre> <p> Play has invoked the <code>controllers.Application.index</code> method to obtain the <code>Action</code> to execute: </p> <pre><code>def index = Action { Ok(views.html.index("Your new application is ready!")) }</code></pre> <p> An action is a function that handles the incoming HTTP request, and returns the HTTP result to send back to the web client. Here we send a <code>200 OK</code> response, using a template to fill its content. </p> <p> The template is defined in the <code>app/views/index.scala.html</code> file and compiled as a Scala function. </p> <pre><code>@(message: String) @main("Welcome to Play 2.1") { @play20.welcome(message) }</code></pre> <p> The first line of the template defines the function signature. Here it just takes a single <code>String</code> parameter. This template then calls another function defined in <code>app/views/main.scala.html</code>, which displays the HTML layout, and another function that displays this welcome message. You can freely add any HTML fragment mixed with Scala code in this file. </p> <h2>Is this your first time?</h2> <p> You can now continue with the <a href="/@documentation/ScalaTodoList">first tutorial</a>, which will guide you through the basics of creating a Play 2.1 application. </p> <h2>Need to set up an IDE?</h2> <p> You can start hacking your application right now using any text editor. Any changes will be automatically reloaded at each page refresh, including modifications made to Scala source files. </p> <p> If you want to set-up your application in <strong>Eclipse</strong> or any other Scala IDE, check the <a href="/@documentation/IDE">Setting up your preferred IDE</a> page. </p> <h2>Need to connect to a database?</h2> <p> You can quickly set-up a development database (either in-memory or written to the file system), by adding these lines to the <code>conf/application.conf</code> file: </p> <pre><code>db.default.driver=org.h2.Driver db.default.url="jdbc:h2:mem:play"</code></pre> <p> If you need to connect to another JDBC-compliant database, first add the corresponding driver library to your application dependencies: </p> <pre><code>val appDependencies = Seq( "mysql" % "mysql-connector-java" % "5.1.18" )</code></pre> <p> Then add the corresponding JDBC configuration to the <code>conf/application.conf</code> file: </p> <pre><code>db.url=jdbc:mysql:database_name db.driver=org.mysql.Driver db.user=root db.pass=secret</code></pre> <h2>Need more help?</h2> <p> When your application is run from the Play console, you can access the current documentation directly, at the <a href="/@documentation">/@documentation</a> URL or go to <a href="http://www.playframework.org">http://www.playframework.org</a>. </p> <p> The <a href="http://groups.google.com/group/play-framework">Play Google Group</a> is where Play users come to seek help, announce projects, and discuss issues and new features. If you don’t have a Google account, you can still join the mailing list by sending an e-mail to <strong>play-framework+subscribe@googlegroups.com</strong>. </p> </article> <aside> <h3>Browse</h3> <ul> <li><a href="/@documentation">Local documentation</a></li> <li><a href="/@documentation/api/scala/index.html">Browse the Scala API</a></li> </ul> <h3>Start here</h3> <ul> <li><a href="/@documentation/PlayConsole">Using the Play console</a></li> <li><a href="/@documentation/IDE">Setting up your preferred IDE</a></li> <li><a href="/@documentation/ScalaTodoList">Your first application</a></li> </ul> </aside> </div> </body> </html>
とても長いコードですが、見るべき所はタイトルタグの中とbodyの中がWelcome to Play2.1になっている事とsection topにYour new application is readyがしっかりと代入されていることです。
※また、このテンプレートサイトにPlayFrameworkのチュートリアルが書いてあるのでよろしければ実践してみてください。
さて、Playの内部構造が少しわかってきた所でHelloWorldが映るようにコードを編集しようと思います。
/app/controllers/Application.scalaを開きます。これを以下のように編集します。
package controllers import play.api._ import play.api.mvc._ object Application extends Controller { def index = Action { Ok("<p>HelloWorld</p>").as(HTML) } }
こちらは引数の文字列をHTMLとしてOKリクエストと一緒に返しています。HTMLを見てみましょう。
<p>HelloWorld</p>
自分の入力したHTMLがそのまま出力されている事を確認し、見事画面にHelloWorldを出力できるところまで確認して下さい。
まとめ
今回はPlayの処理の流れだけ簡単に説明させて頂いただけなので、是非自分でパラメータを変更して実行結果の変化を確認しながら実践して頂ければと思います。
次回はデータベースとGET/POSTを取り扱いかんたんな掲示板やTwitterらしきものを作っていきたいと思います。