- PR -

Strutsで複数のウィンドウ間のデータのやり取りについて

投稿者投稿内容
sumin
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 93
投稿日時: 2003-12-24 15:36
いつも勉強させて頂いてます。
Strutsで一つの処理が複数の画面にまたがっている場合、各画面ごとのデータのやり取りはどうしますか?例えば、
 @画面1で一部情報を入力。
 A画面2で追加情報を入力。
 B画面3で画面1と2の入力情報を表示(確認のため)
 C画面3でサブミットすると全ての情報をDBMSに登録。
勿論、各画面の遷移間バリデーションを実施し、問題があった場合は元の画面に戻し、エラー内容を表示します。

今、考えている方法は
 ・画面1から3までを全部カバー出来る一つのアクションフォームを作成し、
 ・各画面ではその画面の入力データをアクションフォームに格納及びバリデーションを実施
 ・画面1で入力されたデータは画面2ではHidden項目として保持して画面2のサブミット時に共に転送される。
 
という方法です。ここでHidden項目として持つ場合問題になり得る可能性(セキュリティ上?)はないでしょうか?セッションに保持した方がいいでしょうかね?

忠告とかよりいいアイディアとかございましたらお願いします。
さやべえ
常連さん
会議室デビュー日: 2003/03/13
投稿数: 33
投稿日時: 2003-12-24 18:25
メリークリスマス!さやべえです。
私も今同じようなことをやっています。
私は、現在どの画面にいるかに応じてAction内で切り分けを行っています。

struts-config.xml
コード:
<action
  attribute="CreateMemberForm"
  input="/visitor/CreateMember.jsp"
  name="CreateMemberForm"
  path="/CreateMemberAction"
  scope="session"
  type="com.hogehoge.CreateMemberAction"
  validate="false">
    <forward name="BackFirst" path="/visitor/CreateMember.jsp" />
    <forward name="BackSecond" path="/WEB-INF/jsp/visitor/CreateMemberDetail.jsp" />
    <forward name="Confirmation" path="/WEB-INF/jsp/visitor/CreateMemberConfirmation.jsp" />
    <forward name="GoSecond" path="/WEB-INF/jsp/visitor/CreateMemberDetail.jsp" />
    <forward name="Sucess" path="/visitor/CreateMemberSuccess.jsp" redirect="true" />
</action>



該当するAction
コード:
public ActionForward execute(
  ActionMapping mapping,
  ActionForm form,
  HttpServletRequest request,
  HttpServletResponse response)
  throws Exception {

  //完了時に返されるAcitonForward
  ActionForward forward = null;

  //Validation用ActionErrors
  ActionErrors errors = new ActionErrors();

  //Formからデータを取得する
  CreateMemberForm theForm = (CreateMemberForm) form;

  //HttpSession
  HttpSession session = request.getSession();

  //ステータスに応じての処理
  switch (Integer.parseInt(theForm.getStatus())) {
    case 0 : //詳細情報入力画面へ
      //Validateを行う
      errors = theForm.validate(mapping, request);
      if (errors.isEmpty()) {
        theForm.setStatus("1");
        //Formのreset()で初期化をしていないので、requestがnullだった場合に値をfalseにする
        if (request.getParameter("hogehoge") == null) {
          theForm.setHogehoge(null);
        }
        forward = mapping.findForward("GoSecond");
      } else {
        saveErrors(request, errors);
        forward = mapping.findForward("BackFirst");
      }
      break;
    case 1 : //確認画面へ
      //Validateを行う
      errors = theForm.validate(mapping, request);
      if (errors.isEmpty()) {
        theForm.setStatus("2");
        //Formのreset()で初期化をしていないので、requestがnullだった場合に値をfalseにする
        if (request.getParameter("hogehoge2") == null) {
          theForm.setHogehoge2(null);
        }
        forward = mapping.findForward("Confirmation");
      } else {
        saveErrors(request, errors);
        forward = mapping.findForward("BackSecond");
      }
      break;
    case 2 : //完了画面へ
      if (request.getParameter("submit") != null) {
        //Validateを行う
        errors = theForm.validate(mapping, request);
        if (errors.isEmpty()) {
          //処理を実行
          if (!doSave(theForm, request)) {
            SendMail.sendMail(theForm);
            session.removeAttribute(mapping.getAttribute());
            forward = mapping.findForward("Sucess");
          } else {
            forward = mapping.findForward("SystemError");
          }
        } else {
          saveErrors(request, errors);
          forward = mapping.findForward("BackFirst");
        }
      } else {
        //最初に戻る
        forward = mapping.findForward("BackFirst");
      }
      break;
  }

  return forward;
}

masaka
常連さん
会議室デビュー日: 2003/08/04
投稿数: 27
お住まい・勤務地: 東京
投稿日時: 2003-12-24 20:37
引用:

ここでHidden項目として持つ場合問題になり得る可能性(セキュリティ上?)はないでしょうか?セッションに保持した方がいいでしょうかね?


私はいつもFormビーンのスコープをsessionにしています。
理由は以下の二点です。
1.Hiddenに入れる値を書き換えて送信される可能性がある。
(一度バリデートした値を次の画面で再度編集される可能性もでてくる)
2.Hiddenに入れたり取り出したりするのが面倒。

引用:

私は、現在どの画面にいるかに応じてAction内で切り分けを行っています。


一つのActionで複数の画面からSubmitされる場合の処理を書くと煩雑になるので、私の場合は、それぞれの画面ごとにActionを用意することにしています。
もし、Actionの数が多くなるのがイヤなのであれば、org.apache.struts.actions.DispatchActionを使用することをお勧めします。
sumin
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 93
投稿日時: 2003-12-25 08:39
引用:

私はいつもFormビーンのスコープをsessionにしています。
理由は以下の二点です。
1.Hiddenに入れる値を書き換えて送信される可能性がある。
(一度バリデートした値を次の画面で再度編集される可能性もでてくる)
2.Hiddenに入れたり取り出したりするのが面倒。




ご返事ありがとうございます。
セッションに入れるのは確かに簡単ではありますが、セッションに入れた情報を削除しないとリソース的に問題になると思います。その削除のタイミングとか方法はどうしているんでしょうか?



[ メッセージ編集済み 編集者: sumin 編集日時 2003-12-25 08:42 ]
でくのぼう
大ベテラン
会議室デビュー日: 2003/10/06
投稿数: 162
投稿日時: 2003-12-25 12:00
私は滅多に session スコープは使用しません。
理由としては下の二つが主なものです。

・リソース回収が面倒
・インスタンス再利用時の情報漏洩が怖い (初期化漏れがあると発生します)

hidden 書き換えが問題にならないよう、かなりしつこく validate します。
また、Action の数が増えないようにパスによって parameter を設定したり、
Token を用いることで、なんとかやりくりしています。
sumin
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 93
投稿日時: 2003-12-25 14:54
確かにセッションに入れるのは私としても怖いですが、それでもしょうがなくセッションに入れる場合、これをちゃんと掃除したいと思います。何かいい方法はありますでしょうか?
また、リクエストごとに渡されるデータをHiddenでもいいので出来るだけ簡単に渡す方法は無いでしょうか?データの数だけセット・ゲットするのは避けたいですね。
masaka
常連さん
会議室デビュー日: 2003/08/04
投稿数: 27
お住まい・勤務地: 東京
投稿日時: 2003-12-25 18:04
sessionの中身を確実に掃除する方法はないと思います。(画面遷移の途中でブラウザを閉じられてしまえば、掃除されないで残ってしまうので)

ただ、そんなにsessionを恐れる必要はないのではないか、というのが正直な感想です。
sessionの中身を掃除するのが面倒というのは確かにそのとおりですが、例え掃除されなかったとしても、最近のJavaVMは賢いので、sessionがタイムアウトした後に適当なタイミングでガーベジコレクションが走って、メモリは開放されると思います。少なくとも私がいままでかかわったプロジェクトではsessionに入れすぎたためにメモリが足りなくなったということはありません。

私としてはそれよりもHiddenを使うことによるセキュリティ上の心配の方が大きいです。
でくのぼう
大ベテラン
会議室デビュー日: 2003/10/06
投稿数: 162
投稿日時: 2003-12-25 19:58
ええと、すいません、誤解でした。

実はですね、以前の Struts は ActionForm クラスのインスタンスを
データのリセット無しに再利用してしまうという、とんでもない仕様だったのです。

つまり、ある人が初めて入力フォーム画面を開いてみると
以前誰かが入力した項目がそのままフォームの項目を埋めている
空恐ろしい状況が発生しえたのです。

この仕様が今の今まで、残っているものだと勘違いしてしまいました。

ついさっき Struts の CVS リポジトリにあるソースを確認して
この仕様は、かなり昔に取り除かれた事が判明しました。
私もこれから安心して使えます・・・。

問題のソースは RequestProcessor.java の processActionForm メソッドです。

http://cvs.apache.org/viewcvs.cgi/jakarta-struts/src/share/org/apache/struts/action/RequestProcessor.java
興味のある方はこちらから見ることができますので、どうぞ。

一番古い 1.1 だけがこの実装になっています。
どうやら私はとてもタイミング悪い時期に使い始めてしまったようですね・・・。

// 開発中にこの現象がブラウザ上で発生した時は背筋が凍りつきました。

スキルアップ/キャリアアップ(JOB@IT)