Play Framework で「Hello World!!」
Play Framework の環境構築については、
id: hidemium の下記記事を参照されたい。
Play Framework(Java)の開発環境を構築する - hidemium's blog
上記手順でEclipse 上にPlay Framework のプロジェクトが作成された状態からスタートする。
何はともあれ、お決まりの「Hello World !!」アプリを作っていこう。
作成したプロジェクトのappフォルダ以下のviews => index.scala.html を
以下の様に編集しよう。
■index.scala.html
@(message: String)
Hello World!!
上記コードを保存し下記URLでアクセスしてみよう。
http://localhost:9000/
これで、無事「Hello World!!」 が表示されたはずだ。
Play Framework の世界へようこそ。
ところで、何も説明せずに「Hello World!!」を作ってみたが、簡単に処理の流れを説明する。
まず、ユーザのhttp://localhost:9000/に対するリクエストがどの様に処理されるかを順を追って説明する。
(1) フレームワークの入口はroutesファイル
ユーザのhttp://localhost:9000/に対するリクエストにより、どのようなプログラムが呼び出されるかは、
routes ファイルを見れば分かる。
※Java EE 開発の経験があるならば、このroutes ファイルが web.xml に相当するものと理解して良い。
プロジェクトフォルダ => app => conf => routes ファイルを参照すると、
下記の記載があるはずだ。
■routes
GET / controllers.Application.index()
"/" つまり、http://localhost:9000/にアクセスした場合、「controllers.Application.index()」を呼び出すと
読むことができる。
次に「controllers.Application.index()」がどこで実装されているかを説明する。
(2) リクエストの受け手(Controller)
app => controllers => Application.java を見て欲しい。
package controllers; import play.*; import play.mvc.*; import views.html.*; public class Application extends Controller { public static Result index() { return ok(index.render("Your new application is ready.")); } }
当該クラスで index() というメソッドが定義されている。つまり、先ほどのroutes ファイルに従って呼び出されるメソッドは、このApplication.index()メソッドとなる。
つまり、
http://localhost:9000/
というURLでアクセスするとApplication.index()メソッドが呼び出される流れとなる。
(3) ブラウザへ表示するためのView
Application.index() の下記記載を見て欲しい。
return ok(index.render("Your new application is ready."));
上記行により、ブラウザで表示するHTMLを作成するプログラム(View)の「index.scala.html」が呼び出され、その結果ブラウザ上に「Hello World!!」が表示されるのである。
■index.scala.html
@(message: String)
Hello World!!
(4) Controller からView への値の受け渡しについて
下記コードのindex.render(***)の引数を見て欲しい。ここで、"Your new application is ready." という文字列をView に渡している。
return ok(index.render("Your new application is ready."));
それでは、この文字列をView 側で受け止めて表示してみよう。下記の通りView を編集する。
■index.scala.html
@(message: String)
@message <br>
Hello World!!
同様にhttp://localhost:9000/にアクセスしてみよう。
すると、ブラウザに"Your new application is ready."の文字列が表示されるはずだ。
View 側では、
@(message: String)
で、コントローラ側からString 型の文字列を受け取り、message という変数に代入する。
そして、@message により代入した(コントローラから渡された)文字列を出力する。
ここで、お気づきだろうが、Play Framework ではView はScala で記載される。
@で始まる文字列はPlay Framework により、Scala 文法に従って解釈される。
※Java EE 開発におけるJSP に相当するものである。
以上が、Play Framework における処理の流れである。
Java EE開発とは少々勝手が違うが、今後より複雑なアプリを作成することでPlay Framework の開発手法に慣れて欲しい。
Strutsを読む ~6日目: initInternal() の機能(結局のところ) ~
ActionServlet#init()#initInternal() では、結局のところ、
ActionResources*.properties の内容をkey - value 形式(HashMap)で
インスタンス化することが目的。
実際に読み込んでる箇所は、
PropertyMessageResources.loadLocale() の部分になることが分かった。
Debug 仕込んでこのメソッドが呼び出されているのは確実だが、
なぜこのメソッドが呼び出されるのかが未だ不明。。。
コンストラクタの中にも含まれていないのに。。。
まさか、internal.getMessage(*)で読み込んでるのか???
Strutsを読む ~5日目: ちょっとPending ファクトリを理解する。~
いきなり、ActionServlet#init()#initInternal()でつまずいた。
ただ、このメソッドの目的がKey=Value形式のPropertiesファイルをHashMap形式(MessageResources)のクラスにインスタンス化することがわかった。
「オブジェクト脳のつくり方」のp53までを読んでファクトリとやらを
噛みしめるべし。
Strutsを読む ~ 4日目: defaultFactory.createResources("org.apache.struts.action.ActionResources") ~
掲題のメソッドは抽象クラスで下記の通り定義されている。
public abstract MessageResources createResources(String config);
これを実装しているものが、PropertyMessageResourcesFactory クラスになり、
下記の通りコーディングされている。
#####################################################
public MessageResources createResources(String config) {
PropertyMessageResources messageResources =
new PropertyMessageResources(this, config, this.returnNull);
String mode = null;
if (getConfig() != null) {
mode = getConfig().getProperty("mode");
}
messageResources.setMode(mode);
return messageResources;
}
#####################################################
Strutsを読む ~3日目: ActionServlet#init()~
テーマ: initInternal() は何をするメソッド?
<深度:1>コードとしては、下記の通りで、ActionResources.propertiesの内容をインスタンス化する。
#########################################################
protected String internalName = "org.apache.struts.action.ActionResources";
protected MessageResources internal = null;
protected void initInternal(){
internal = MessageResources.getMessageResources(internalName);
}
#########################################################
<深度:2>MessageResourcesクラスを読み解く
MessageResources.getMessageResources("org.apache.struts.action.ActionResources");
実装 ↓ ※下記2行が何をしているかを読み解く。
MessageResourcesFactory defaultFactory = MessageResourcesFactory.createFactory();
return defaultFactory.createResources("org.apache.struts.action.ActionResources");
まずは、
<深度:3>MessageResourcesFactoryはどういうクラス?
所謂ファクトリパターンにおいてオブジェクトを生成するクラス。
ファクトリパターンの利用シチュエーションとしては、
たとえば、条件によってデータファイルの読み込みに使うオブジェクトが異なる場合、
CSV形式であればCSVDataReaderオブジェクトを、XML形式であれば
XMLDataReaderオブジェクトを生成するような場合に利用する。
ファクトリクラスでは、オブジェクトの生成のみを行います。
オブジェクト生成の専門家であるファクトリが、オブジェクトの使用者から生成するオブジェクトの種類や生成手順を隠してくれます。
オブジェクトの使用者はファクトリに生成を依頼するだけで、オブジェクトの生成手順や種類を意識する必要はなく、望むオブジェクトを使用できる状態で手に入れることができる。
結局下記メソッドが何をやっているかを読み解くのが鍵。
defaultFactory.createResources("org.apache.struts.action.ActionResources");
Strutsを読む ~2日目: フレームワークの入口~
StrutsがJava EEフレームワークである以上、まずは「web.xml」となる。
############### <web.xml> ###############
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
######################################
*.doをいうURIにより、ActionServlet が必ず呼び出される。
これがフレームワークの入口。
このようにリクエストを一手に担うようなサーブレット(ActionServlet)を利用する
デザインパターンのことをFront Controller パターンと呼ぶ。
サーブレットのライフサイクルに準じて、まずは、このサーブレットのinit()メソッドを読んでいく。
Strutsを読む ~1日目: ソースコードリーディングをする環境構築~
利用するツールとしては、「Pleiades All in One」を利用するが、これは通常通りインストールすればOK。
作成する環境は、StrutsのソースコードからEclipseのプロジェクトを作成し、
そのプロジェクトの中にサンプルコードも含ませるイメージ。
こうすることで、Strutsを弄りながらサンプルの挙動を確認できる。
ビルドするStrutsのプロジェクト(パッケージ)は下記2つ。
・struts-core
・struts-taglib
手順としては下記の通り。
1. Eclipseで動的プロジェクト作成
2. struts-core を上記プロジェクトにインポート
上記で作成されたsrcフォルダを右クリックし、
[展開フォルダ]\struts-1.3.10\src\core\src\main\java(orgフォルダの一個上の階層)をインポート
3. ビルドエラー(Mock~)が出るので、クイックフィックス ⇒ 実装無しメソッド追加で解消
4. struts-taglib を同様にインポート
5. 静的コンテンツのデプロイ(tldファイル)
[展開フォルダ]\struts-1.3.10\src\taglib\src\main\resources\META-INF\tld
フォルダをプロジェクトのWEB-INF以下に置く。
6. 静的コンテンツのデプロイ(chain-config.xml)
プロジェクト内に下記XMLを配置する。
[展開フォルダ]\struts-1.3.10\src\core\src\main\resources\org\apache\struts\chain
※これが無いと"org/apache/struts/chain/chain-config.xml に対するマッピング設定がありません"というエラーが出る。Javaソースはプロジェクトにインポートしたけど、静的コンテンツ等のリソースをインポートしていないため、XMLが有りませんよという意味のエラー。
7. サンプルコードをデプロイ
下記ページのものをそのままデプロイした。
http://www.zealseeds.com/SysDevTech/Struts/Struts/introduction/helloworld/index.html
※余談だが、今回作成したプロジェクトはStrutsもサンプルコードも全て同じプロジェクト内でビルドしたが、Eclipseの外部プロジェクト読み込み機能を利用して、サンプルとStrutsのプロジェクトを分離しようとしてみたところ、ActionServletが有りませんよエラーが発報した。どうやらActionServletはプロジェクトのWEB-INF/lib以下に無いと動かないようだ。クラスローダの動きが分からないため、原因は不明。。。