Strutsメモ5

2002/1/25 作成

Struts Testcase

アプリケーションの単体テストを書くときに、よく使われるのがJUnitです。 JUnit単体では、Javaアプリケーションのテストはできますが、 サーバーサイドのテストはできません(Web上でコンテナから呼ばれるので)。

Struts Testcase はJUnitを拡張し、 Struts上でテストすることを可能にしています。 Struts Testcaseでテストを行う方法には、モックテストコンテナテストの2つあります。 モックの方はダミーのサーブレットコンテナ、ダミーのサーブレットリクエストを使って、 テストする方法。コンテナテストの方は実際にコンテナを起動して、テストをする方法です。 とりあえず、早くて簡単(な気がする)モックテストを試してみました。

少しさわってみまた感想としては、比較的簡単です。 注意点としては、

ぐらいで、JUnitのテストを書くのとほとんど変わりません。 サンプルなどは、参考のページが詳しいのでそちらをご覧ください。

参考

2度押し防止(同期トークン)

Webアプリ開発時によくある問題として、 「2度押し」があります。 例えばショッピングサイトで注文決定ボタンを押して、 画面が切り替わる前に、もう1度注文決定を押してしまったら。。。 2重注文はしたくないですね。

Strutsでは、画面をまたぐトランザクションの仕組みとして、 同期トークンの仕組みを提供しています。Actionクラスの以下のメソッドを使います。
メソッド 説明
Action#saveToken(HttpServletRequest) トークンを作成し保存する
Action#isTokenValid(HttpServletRequest) トークンを検証する
Action#resetTokan(HttpServletRequest) トークンをクリアする
この同期トークンを使って、 2度押しに対処することができます。

以下は同期トークンを使った簡単なシナリオです。 注文決定前の確認画面を表示するActionを想像してください。

  1. ユーザーは必要項目を入力し、注文ボタンを押す。
  2. システムはユニークな文字列(同期トークン)を作成し、セッションに埋める
  3. システムは注文確認画面を表示する。
    この画面のHTMLソースにはhiddenで同期トークンが記述されている。
  4. ユーザーは注文決定ボタンを押す
  5. システムは受け取ったリクエストの同期トークンとセッションに保存されている同期トークンを比較し、 同じであれば、処理を継続する。
    同期トークンが異なる場合(例えば2度押しされた場合)、 このリクエストに対する処理は行わず、エラー画面に遷移する。
  6. システムは注文受付終了画面を表示する。

上記の太字の部分をActionに実装するとこんな感じになります。

アクションの例:ユニークな文字列(同期トークン)を作成し、セッションに埋める

  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws Exception {
    
    //....

    //同期トークンを保存
    saveToken(request);

    //...

    return mapping.findForward("success");
  }

JSPの例:同期トークン付のformを生成する

<html:form action="/order">
  <input type="submit" value="注文決定"/>
</html:form>

<!--↓確認用-->
<p>token=<%=session.getAttribute(org.apache.struts.action.Action.TRANSACTION_TOKEN_KEY)%>

同期トークンは、 存在すれば自動的にform内にhiddenで埋め込まれるので、特に何か指定する必要はありません。 Action.TRANSACTION_TOKEN_KEYは同期トークンをセッションに埋める定数で、 確認(デバッグ)用の記述です。

アクションの例:リクエストの同期トークンとセッションに保存されている同期トークンを比較する

  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws Exception {

    //...

    boolean valid  = isTokenValid(request, true);
    
    System.out.println("Is Token Valid? " + valid);    

    if(valid){
      //正常系
    }else{
      //異常系
    }

    //...
  }

上の例だと、 重要な処理を2度行わないことは保証されていますが、 例えば2度押しされた場合、何を画面に表示するかが問題になります。 「エラーです」と画面に表示しても、 処理が実行されたのかどうかをユーザーが確認できません。 1回目の正しいリクエストの結果を返すのが一番ですが、 けっこうややこしいことをしないといけない気がします。 (というかいい方法あったら教えてください)

JavaScriptの利用が可能ならば、クライアントでの2度押し防止処理と あわせて利用すれば、大体は大丈夫だと思いますが。。。

次のページへ



もどる