ラベル Wicket の投稿を表示しています。 すべての投稿を表示
ラベル Wicket の投稿を表示しています。 すべての投稿を表示

2012年12月6日木曜日

WicketでWebSocketを使ってみた

Wicketの6からWebSocketに対応したらしいので使ってみた。

  • 作ったもの
  • 感想
  • 引っかかったところ
作ったもの
簡単にいうと、チャットアプリケーション。
メッセージをAjaxで受け取り、チャット参加者へWebSocketでpush通知する。
クライアント側はjQueryで受け取ったメッセージをDOMへ追加する。

引っかかったところ
IWebSocketConnectionにはComponentをaddできない。送信できるのは文字列またはbyte配列。WebSocketRequestHandlerにはaddできるので、WebSocketBehaviorのonMessageで実装すればよいが、それってAjaxとなにが違うのかな?

web.xmlで、サーブレットコンテナに対応したfilterを設定しなければならない。wikiのCustom WicketFilterを参照。

JavaScriptの依存関係を設定しなければいけない。サンプルを参照。

感想
IWebSocketConnectionで送受信できるデータが文字列かバイト配列なので、実際はJSONを送受信することになると思われる。Javaオブジェクトとの相互変換を考慮する必要があると思う。

push通知が動作するまでは、手間がかかる割に動作はAjaxと変わらないのでモチベーションが上がらなかった。が、push通知で画面が更新されるようになると一気に楽しくなった。

やや話はそれるが、JavaScriptのライブラリがjQueryになったのも大きいと思う。

2012年7月30日月曜日

DropDownChoiceでenumを使用する

突然ですが、enumって便利ですよね。
業務で使用する場面としては、"○○区分"というものを表現するのによく使います。
そしてそれを画面では<select>として表示することもよくあります。
このとき、画面に表示するテキストをenum自身から分離するための方法です。

enumを定義する

普通にenumを定義します。
public enum RockPaperScissors {
ROCK,PAPER,SCISSORS;
}

アプリケーションのプロパティファイルに表示する文字列を定義する

型名.フィールド名=文字列の形式で定義します。
# for RockPaperScissors
RockPaperScissors.ROCK=\u30b0\u30fc
RockPaperScissors.PAPER=\u30d1\u30fc
RockPaperScissors.SCISSORS=\u30c1\u30e7\u30ad

DropDownChoiceのコンストラクタにEnumChoiceRendererを渡す

public class RockPaperScissorsDropDownChoice
extends DropDownChoice<RockPaperScissors> {
public RockPaperScissorsDropDownChoice(String id) {
super(id,
Arrays.asList(RockPaperScissors.values()),
new EnumChoiceRenderer<RockPaperScissors>());
}
}

画面ごとに表示するテキストを変えたい場合、以下のようにします。

  1. 画面ごとにプロパティファイルを作成する
  2. EnumChoiceRendererのコンストラクタにPageのインスタンスを渡す



2012年3月23日金曜日

WicketTesterで独自のSessionを使用するには

アプリケーションで独自のSessionを使用するには、WebApplication.newSessionをオーバーライドします。
WicketTesterで単体テストをするときも、そのApplicationをコンストラクタに渡せば、そのSessionを使ってテストができます。
しかしこれは単体テストとしては今ひとつ。できればApplicationに依存しないテストを書きたい。Applicationのテストをしたいのではなく、Componentのテストをしたいのだ–。

MockApplicationを使う
何か適当な解決策はないものか、と考えたところで思いついたのが、MockApplicationを継承して使うという方法でした。
MockApplicationはWicketTesterのデフォルトコンストラクタが呼ばれたときに使用されるApplicationのため、もっともシンプルな解決策ではないかと考えました。
というわけで、MockApplication.newSessionをオーバーライドすれば独自のSessionが使えることを確認する試験を書きました。WicketTesterを起動した後、Sessionを取得して型を検査しています。

import org.apache.wicket.Session;
import org.apache.wicket.mock.MockApplication;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.WebSession;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
import org.apache.wicket.util.tester.WicketTester;
import org.junit.Test;
import static org.junit.Assert.*;
public class SetSessionTest {
@Test
public void testSessionCreated() {
WebApplication app = new MockApplication() {
public Session newSession(Request request, Response response) {
return new CustomizedSession(request);
}
};
WicketTester tester = new WicketTester(app);
Session session = Session.get();
assertTrue(session instanceof CustomizedSession);
}
static class CustomizedSession extends WebSession {
CustomizedSession(Request request) {
super(request);
}
}
}
これでまたTDDの道を極めたぜ。

2011年12月23日金曜日

WicketTesterでAjaxをテストする

Ajaxまわりのtestができなくて悩んでいる話にて、
お仕事で作っているwebアプリケーションはAjaxごりっごり取り入れているのですが、残念ながらWicketTesterでAjaxまわりのテストはできないのです。
と、あるのですが、WicketTesterからAjaxまわりをテストする方法はあります。Wicketのユーザーの端くれとして、誤解をといておこうと思います。

サンプルは以下3つのファイルで構成されています。

  1. MyPage.html
  2. MyPage.java
  3. MyPageTest.java
MyPage.html
<html>
<head>
<title>ajax</title>
</head>
<body>
<form wicket:id="form">
<input type="text" wicket:id="num1"/>
<span wicket:id="num2"/>
</form>
</body>
</html>
view raw MyPage.html hosted with ❤ by GitHub
引用元と同じく、TextFieldとLabelが1つずつの画面です。JavaScriptを書かずにAjaxを実現するのがWicketのいいところ。

MyPage.java
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.PropertyModel;
public class MyPage extends WebPage {
private Form<Void> form;
private Label label1;
private TextField<Integer> field;
private Integer num1;
private Integer num2;
public MyPage() {
form = new Form<Void>("form");
field = new TextField<Integer>("num1", Integer.class);
label1 = new Label("num2");
}
@Override
protected void onInitialize() {
super.onInitialize();
super.add(form);
form.add(field);
form.add(label1);
field.setModel(new PropertyModel<Integer>(this, "num1"));
label1.setDefaultModel(new PropertyModel<Integer>(this, "num2"));
label1.setOutputMarkupId(true);
field.add(new OnChangeAjaxBehavior() {
@Override
protected void onUpdate(AjaxRequestTarget target) {
if(null != num1){
num2 = num1 * num1;
}
target.add(label1);
}
private static final long serialVersionUID = 1L;
});
}
private static final long serialVersionUID = 1L;
}
view raw MyPage.java hosted with ❤ by GitHub
MyPage.htmlに対して、コンポーネントを割り当てていきます。ここでAjaxイベントも定義します。

MyPageTest.java
package ajaxtest;
import org.apache.wicket.util.tester.FormTester;
import org.apache.wicket.util.tester.WicketTester;
import org.junit.Before;
import org.junit.Test;
public class MyPageTest {
private WicketTester tester;
@Before
public void setUp() {
this.tester = new WicketTester();
this.tester.startPage(MyPage.class);
}
@Test
public void num1入力() {
FormTester ft = this.tester.newFormTester("form");
ft.setValue("num1", "12");
this.tester.executeAjaxEvent("form:num1", "onchange");
this.tester.assertLabel("form:num2", "144");
}
}
view raw MyPageTest.java hosted with ❤ by GitHub
MyPage.javaの単体テストです。Ajaxをテストするには、BaseWicketTester.executeAjaxEventを使います。
Javadoc:BaseWicketTester.executeAjaxEvent

これでAjaxもテストできます。よかったですね。