Springと一緒に Wicketを使う
我が社は主に Flexと BlazeDSを用いた RIAに注力している。このプラットフォームを用いる場合、サーバ側ではほぼ純粋にビジネスロジックを提供するだけで良いため典型的なMVCタイプの Webアプリケーションよりもさらに分業が容易であるという利点がある。
しかしながら、常にユーザの環境が RIAに適しているとは限らないし、「文書を読ませる」機能に関して言えばそれを Flash Player上に実現した場合あまりユーザにとって快適とは言い難いものになる可能性が高い。
などの理由から、従来通りHTMLで表現される Webアプリケーションを実装する場合も少なからずあるため、近頃先進的な向きに人気の高い Wicketを調べてみた(むろん、同様の目的には Spring MVCや Struts2を使っても良いのだが)。
ここでは、既に Spring Frameworkが Webアプリケーションに導入されていることを前提に Wicketを動作させるために必要な最低限のセットアップを行う手順を示す。
なお、アプリケーションに BlazeDSが既に導入されている場合でも共存が可能であることを確認している。
WEB-INF/lib に設置した jarファイルは下記の通り。
wicket-1.3.4.jar
wicket-ioc-1.3.4.jar
wicket-spring-1.3.4.jar
wicket-spring-annot-1.3.4.jar
slf4j-api-1.5.0.jar
slf4j-jcl-1.5.0.jar
slf4jについては好きな実装を用いて良いと思うが、Springが前提であれば Commons Loggingが存在するはずなのでここでは slf4j-jclを用いている。
必要なライブラリを追加したら、web.xmlに Wicketの設定を追加する。Wicketはサーブレット又はサーブレットフィルタとして適用することが出来るが、後者が推奨されているようだ。
典型的な Wicketアプリケーションを構成する要素は、ひとつの WebApplicationクラスと ページ数分の WebPageクラス(とそれぞれに対応するHTMLファイル)である。
applicationFactoryClassNameに SpringWebApplicationFactoryをセットすることで、Wicketは Springの applicationContext.xml内に定義されている Beanの中から WebApplicationのインスタンスを選び出して自動的に用いるようになる。
(そのため、ことSpringを用いる場合は web.xmlにWebApplicationの実装クラス名を直接書き込む必要がない)
この設定では、Webアプリケーションに対する全てのリクエストが Wicketのフィルタに一旦渡されるが、Wicketは自身の守備範囲でない URIへのリクエストをスルーするため、画像などのリソースや他のサーブレット(BlazeDSの通信エンドポイントもそうだ)に対するリクエストを妨害されることはないようだ。
さて、最小限の WebApplicationはこのような実装になる。
Springと統合するために、initメソッドに対し addComponentInstantiationListenerの呼び出しを追加している。これによって、WebPageクラスのインスタンスが生成される際にはアノテーションに従って自動的にフィールドインジェクションが行われるようになる。例えばこのように。
上記の例ではアノテーションのパラメータとして name を渡しているが、型の合致するBeanがアプリケーションコンテキスト内にひとつしか無い場合は省略しても良い。
WebPageオブジェクトのライフサイクルは Wicketの管理下にあり Springのそれとは一致しないが、WebPageオブジェクトにフィールドインジェクションされた Beanは実際には適切に自動生成されたプロキシであり、これによりライフサイクルの差異は吸収されるらしい。
インジェクションの対象となるフィールドには初期化の記述をしないように注意すること(例えば private HelloService helloService = null; のように)。インジェクタはフィールドの初期化処理よりも前に走るため、フィールドの初期化を記述するとそれで上書きされてしまうそうだ。
あとは Wicketの作法に従って WebPageクラスと HTMLファイルを必要なだけ作ることで UIを構築していけば良いだろう。
しかしながら、常にユーザの環境が RIAに適しているとは限らないし、「文書を読ませる」機能に関して言えばそれを Flash Player上に実現した場合あまりユーザにとって快適とは言い難いものになる可能性が高い。
などの理由から、従来通りHTMLで表現される Webアプリケーションを実装する場合も少なからずあるため、近頃先進的な向きに人気の高い Wicketを調べてみた(むろん、同様の目的には Spring MVCや Struts2を使っても良いのだが)。
ここでは、既に Spring Frameworkが Webアプリケーションに導入されていることを前提に Wicketを動作させるために必要な最低限のセットアップを行う手順を示す。
なお、アプリケーションに BlazeDSが既に導入されている場合でも共存が可能であることを確認している。
WEB-INF/lib に設置した jarファイルは下記の通り。
wicket-1.3.4.jar
wicket-ioc-1.3.4.jar
wicket-spring-1.3.4.jar
wicket-spring-annot-1.3.4.jar
slf4j-api-1.5.0.jar
slf4j-jcl-1.5.0.jar
slf4jについては好きな実装を用いて良いと思うが、Springが前提であれば Commons Loggingが存在するはずなのでここでは slf4j-jclを用いている。
必要なライブラリを追加したら、web.xmlに Wicketの設定を追加する。Wicketはサーブレット又はサーブレットフィルタとして適用することが出来るが、後者が推奨されているようだ。
<filter>
<filter-name>wicket</filter-name>
<filter-class>
org.apache.wicket.protocol.http.WicketFilter
</filter-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>
org.apache.wicket.spring.SpringWebApplicationFactory
</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>wicket</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
典型的な Wicketアプリケーションを構成する要素は、ひとつの WebApplicationクラスと ページ数分の WebPageクラス(とそれぞれに対応するHTMLファイル)である。
applicationFactoryClassNameに SpringWebApplicationFactoryをセットすることで、Wicketは Springの applicationContext.xml内に定義されている Beanの中から WebApplicationのインスタンスを選び出して自動的に用いるようになる。
(そのため、ことSpringを用いる場合は web.xmlにWebApplicationの実装クラス名を直接書き込む必要がない)
この設定では、Webアプリケーションに対する全てのリクエストが Wicketのフィルタに一旦渡されるが、Wicketは自身の守備範囲でない URIへのリクエストをスルーするため、画像などのリソースや他のサーブレット(BlazeDSの通信エンドポイントもそうだ)に対するリクエストを妨害されることはないようだ。
さて、最小限の WebApplicationはこのような実装になる。
package net.stbbs.wicket;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
public class WebApplication extends
org.apache.wicket.protocol.http.WebApplication {
@Override
public void init()
{
super.init();
this.addComponentInstantiationListener(new SpringComponentInjector(this));
}
@Override
public Class getHomePage() {
return HomePage.class;
}
}
Springと統合するために、initメソッドに対し addComponentInstantiationListenerの呼び出しを追加している。これによって、WebPageクラスのインスタンスが生成される際にはアノテーションに従って自動的にフィールドインジェクションが行われるようになる。例えばこのように。
public class HomePage extends WebPage {
@SpringBean(name="helloService")
private HelloService helloService;
:
:
上記の例ではアノテーションのパラメータとして name を渡しているが、型の合致するBeanがアプリケーションコンテキスト内にひとつしか無い場合は省略しても良い。
WebPageオブジェクトのライフサイクルは Wicketの管理下にあり Springのそれとは一致しないが、WebPageオブジェクトにフィールドインジェクションされた Beanは実際には適切に自動生成されたプロキシであり、これによりライフサイクルの差異は吸収されるらしい。
インジェクションの対象となるフィールドには初期化の記述をしないように注意すること(例えば private HelloService helloService = null; のように)。インジェクタはフィールドの初期化処理よりも前に走るため、フィールドの初期化を記述するとそれで上書きされてしまうそうだ。
あとは Wicketの作法に従って WebPageクラスと HTMLファイルを必要なだけ作ることで UIを構築していけば良いだろう。

