GWTの拡張(3) - 同期処理
GWTを利用するにあたっては、同期処理が大きな課題になるが、参考情報が少ないので紹介しておく。
同期処理の課題は以下の2つにまとめることができる。
1. 二重登録の防止
ボタンを連続クリックしたり、処理をエンターキーにバインドした状態でエンターキーを押下し続けたりすると、デフォルトでは、複数のリクエストがサーバーに送信されてしまう。
このリクエストが登録処理だった場合には、同じ情報が重複して登録される可能性がある。
2. サーバーからの応答待ちの際の画面ロック
サーバーの処理結果をクライアントに確実に伝えるためには、サーバーから応答が返るまで他の操作を行えないようにする必要がある。
しかし、GWTは非同期処理を基本としているため、デフォルトではこのような動作を実現できない。
この同期処理の課題は、次のような方法で対処できる。
- イベントを受け取る(lockする)
- 入力形式チェックを行う(エラー時はunlockする)
- 確認用ダイアログを表示する(キャンセル時はunlockする)
- サーバへ送信する(
WaitingPanel
を表示する) - サーバからの応答を受け取る(
WaitingPanel
を非表示にする、unlockする)
(WaitingPanel
については、以前の記事を参照のこと。)
「二重登録」の制御は、上記の(1.イベントを受け取る)から(5. サーバからの応答を受け取る)の間で行う必要がある。
「サーバからの応答待ちの際の画面ロック」は、上記の(4. サーバへ送信する)から(5. サーバからの応答を受け取る)の間で行う必要がある。
// 複数のリクエストの発火を制御するロッククラス private Lock lock = new Lock(); // [step1. イベントを受け取る (lockする)] // ボタンクリック時に呼ばれるメソッド public void onClick(Event e) { // ロックを試みる。 if (!lock.lock()) { // 既にロックされていたら、重複リクエストなので抜ける return ; } // サーバに送信するデータ取得(省略) Model model = ((...)e.getSource())...getModel(); // 登録処理 processInsert(model); } // ロック解除メソッド protected void unlock() { lock.unlock(); } // 登録処理 protected void processInsert(Model model) { // [step2. 入力形式チェックを行う (エラー時はunlockする)] // 入力形式チェック(BeanValidation) if (validate(model)) { // エラー時の処理...ロックは解除する unlock() return ; } // [step3. 確認用ダイアログを表示する (キャンセル時はunlockする)] // 確認ダイアログを表示 if (!confirm("登録しますか?")) { // キャンセルの処理...ロックは解除する unlock() return ; } // [step4. サーバへ送信する (WaitingPanelを表示する)] // ウェイティングパネルを表示し、画面操作をロックする final WaitingPanel waiting = new WaitingPanel(); waiting.show(); // サーバ通信処理 MyRemoteServiceAsync service = GWT.create(MyRemoteService.class); // 第1引数:登録するデータのオブジェクト // 第2引数:サーバからの応答を待つ非同期コールバック service.insert(model, new AsyncCallback<String>() { @Override public void onSuccess(final String result) { // [step5. サーバからの応答を受け取る (WaitingPanel非表示にする、unlockする)] // 成功時 // implements ... waiting.hide(); unlock() } @Override public void onFailure(Throwable caught) { // step[5. サーバからの応答を受け取る (WaitingPanel非表示、unlock)] // サーバからのエラー時 waiting.hide(); unlock() // Error handling ... } }); } // 複数のリクエストの発火を制御するロッククラス class Lock{ private boolean isLocked = false; // ロックを試みる。ロックできたらtrue, 既にロックされてい // たらfalse public synchronized boolean lock() { if(isLocked){ return false; } isLocked = true; return true; } // ロックの解除 public synchronized void unlock(){ isLocked = false; } }
[高橋 友樹]