StrutsからWicketに移行する際にとまどった部分とその解決方法

Strutsでこういう実装をしたのを、Wicketではどうやればいいんだろう?と私が思った内容をつらつら書きます。もうだいぶ前に実装完了しちゃったから、思い出せるものも多くないかも知れませんが、少しでも役に立つと幸い。
私が当時使っていたStrutsWicketのバージョンはそれぞれ以下の通りです。

RequestProcessor#preprocess()*1でアクション実行前の前処理実施

WebApplication#newRequestCycle()をオーバーライドし、WebRequestCycleのサブクラスのインスタンスを逐一返すようにする。肝心のWebRequestCycleのサブクラスはonBeginRequest()をオーバーライドすればOK。

ただしこの方法だと、Strutsの場合はアクションのみ前処理を行い、JSP直アクセスの場合は前処理を行いませんでしたが、Wicketの場合はWicketのFilterに引っかかるすべてのリクエストに対して前処理を行うはず。

PlugInの替わりの機構

何がそれに該当するか分かりませんが、Webアプリケーションの初期化を行うのは、WebApplication#init()で実装するので、同じ風に実装すればいいんじゃないでしょうか。
DIを使いたい場合も、この辺で行いますし。

認証の仕組みを入れる

WebApplicationではなく、Wicket-auth-rolesで提供されている、AuthenticatedWebApplicationのサブクラスを実装しましょう。また、セッションはSessionではなく、AuthenticatedWebSessionのサブクラスを実装することになります。

public class SampleApplication extends AuthenticatedWebApplication {
	@Override
	protected Class<? extends AuthenticatedWebSession> getWebSessionClass() {
		//AuthenticatedWebSessionのサブクラス
		return SampleAuthenticatedWebSession.class;
	}

	@Override
	protected Class<? extends WebPage> getSignInPageClass() {
		//未認証時に遷移するログイン画面
		return LoginPage.class;
	}
}

public class SampleAuthenticatedWebSession extends AuthenticatedWebSession {
	@Override
	public boolean authenticate(String username, String password) {
		//認証の実装を行う。
	}

	@Override
	public Roles getRoles() {
		//認証成功時のロールを返す。ここではUSERとする。
		return new Role("USER");
	}
}

で、最後に認可を行いたい各画面に対しては、アノテーション@AuthorizeInstantiationを、ロール名付きで付与すればOK。該当ロールを持っているセッションの場合は、表示されるべき画面が表示されます。ロールを持っていない場合は、SampleApplicationで指定しているログイン画面に遷移します。
何より嬉しいのが、ログイン後に以前の処理をそのまま継続するかしないかまで簡単に制御可能なところ。素晴らしいねWicketさん。

@AuthorizeInstantiation("USER")
public class SamplePage extends WebPage {
}

動的フォームの作成

例えばStrutsでList型のフォームを使う場合、ActionFormのインスタンス変数にListを用意、それらのgetter/setterも用意して、JSP側ではそのListに対してiteratorを回してフォームを生成する。フォームに入力された値は、直接Listに格納される、みたいなことができました。

Wicketの場合、私の場合ですが、直接値を格納できるListの変数を用意せず、Listを用意しました。以下のようなイメージです。多少、記憶頼りのコードですので、参考程度に。

public class HogeHogePanel extends Panel {
	//動的フォームの各要素を格納するモデルのリスト
	private List<IModel> models = null;
	//動的フォームを表現するフォームコンポーネントを格納するリスト
	private List<FormComponent> formComponents = null;
	public HogeHogePanel(String id) {
		//...
		for () {
			//動的フォームの各要素に紐付くモデルを作り、リストに入れておく
			Model model = new Model("");
			models.add(model);
			//フォームコンポーネントにも紐付けておく
			FormComponent component = new 何がし();
			component.setModel(model);
			formComponents.add(component);
		}

		//フォームコンポーネントの配置
		ListView listView = new ListView("nanigashi", formComponents) {

			@Override
			protected void populateItem(ListItem item) {
				FormComponent component = (FormComponent) item.getModelObject();
				item.add(component);
			}
		};
		listView.setReuseItems(true); //入力した値を再利用可能に。
		form.add(listView);

	}
}

CompoundPropertyModelやその他の方法で直接インスタンス変数に値を格納する方法が分からなかったので、モデルのリストを用意しておいて、そこに値を格納する、という形を取りました。

ちょいと時間がなくなったので、思い出したらどんどん書いていきます。

*1:Struts1.2以前の場合。Struts1.3はRequestProcessorのサブクラスの実装、ではなく、Chains of Responsibilityパターンを使っているので、ActionCommandBase#execute()の実装になりますね。