StrutsのTokenメカニズムを使用してフォームの重複コミットを解決

6593 ワード

StrutsのToken(トークン)メカニズムは、サーバ側が到着したリクエストを処理する前に、リクエストに含まれるトークン値を現在のユーザセッションに保存されているトークン値と比較し、一致するかどうかを確認することによって、フォームの重複コミットの問題をうまく解決することができる.要求の処理が完了し、応答がクライアントに送信される前に、クライアントに渡されるほか、ユーザセッションに保存されている古いトークンを置き換える新しいトークンが生成される.これにより,ユーザが先ほどのコミットページに戻って再度コミットすると,クライアントから送信されたトークンがサーバ側のトークンと一致せず,重複コミットの発生を効果的に防止できる.
 
この場合、実は2つ目です.1つ目は、リクエストにこのトークン値が必要です.リクエストのトークン値をどのように保存するかということです.実は、私たちが普段ページに保存している情報と同じです.フィールドを隠すことで保存します.保存形式は、〈input type=“hidden”name=“org.apache.struts.taglib.html.TOKEN”value=“6 aa 35341 f 2584 fd 996 c 4 c 918255 c 3 ae”、このvalueはTokenProcessorクラスのgenerateToken()で得られ,現在のユーザのセッションidと現在の時間のlong値に基づいて計算される.第二に、クライアントがコミットした後、要求に含まれる値がサーバのトークンと一致するかどうかを判断します.サーバはコミットするたびに新しいTokenを生成するので、重複コミットであればクライアントのToken値とサーバ側のToken値が一致しません.次に、重複コミットを防止する方法について、データベースにデータを挿入します.
 
Actionのaddメソッドでは、Token値の明確な要求をページに保存する必要があります.文を1つ追加するだけです.saveToken(request);以下にpublic ActionForward add(ActionMapping mapping,ActionForm,HttpServertRequest request,HttpServertResponse response)/前の処理はsaveToken(request)を省略する.return mapping.findForward("add");}Actionのinsertメソッドでは、フォームのToken値とサーバ側のToken値とを比較します.以下に示します.
public ActionForward insert(ActionMapping mapping, ActionForm form, 
HttpServletRequest request, HttpServletResponse response)
if (isTokenValid(request, true)) {
//         
//          
} else {
//      
saveToken(request);
//       
}
}

 
 
1.重複コミット、重複リフレッシュのシーン重複コミット、重複リフレッシュは、システム重複レコードの問題を解決するために使用されます.つまり、ある人が何度も記録を提出している(なぜ?暇かもしれないし、やることがないかもしれない.最も可能性のあるのは、ユーザーが自分の提出結果が実行されたかどうか分からないこと?!).
しかし、このような問題が発生したら、処理しなければならないわけではありません.あなたが開発したシステムのカテゴリによって異なります.例えば、あなたが引き継いだのはある資源管理システムで、システム自体は需要の角度からまったく“繰り返し”の記録が現れることを許さないで、このような需要の制約の条件の下で、繰り返しの提出の動作を実行して“業務レベルの異常”の発生を引き起こすだけで、根本的に実行することができなくて成功して避けられない問題を避けることはできません.
 
2.後退を防止するシーン重複リフレッシュ、重複コミットのシーンを理解し、「後退防止」操作の原因を理解してみましょう.例えば、投票システムを開発していると、多くのステップがあり、これらのステップの間にはつながりがあります.例えば、最初のステップはいくつかの情報を第2のステップに送信し、第2のステップはこれらの情報をキャッシュし、同時に自分の情報を第3のステップに送信します...など、もしこの時ユーザーが第3のステップの下にいたら、あるいたずらユーザーのユーザーが後退ボタンをクリックしたことを想像してみましょう.この時、画面に第2のステップのページが表示され、彼は再び修正したり、再び提出したりして、次のステップ(つまり第3のステップ)に入ると、エラーが発生します?!どんな間違いですか.最も典型的なのは、このような操作が最初のステップ情報の損失を直接招くことです.(このような情報がRequestに依存して格納されている場合は、もちろんSession以上のコンテキスト環境に格納できますが、これは良いアイデアではありません!情報格納の問題については、次回この問題について詳しく議論します)
三.どのように処理するかという問題はもちろん多くのシステム(例えば、チケット予約システムは需要的に個人がチケットを繰り返すことを許可している)は、重複リフレッシュ、重複提出、および後退防止の問題を避けなければならないが、このような問題であっても、どのように処理するかとどこで処理するかを区別しなければならない(ネット上ではどのように処理するかを教えているだけだが、どこで処理するかを区別することは少ない).明らかに処理の仕方はクライアントとサーバーの2つにほかならないが、異なる位置で処理する方法も異なるが、事前に宣言しなければならないことがある.どのクライアント(特にB/S端)の処理も信頼できない.最良で最も当然なのはサーバ側の処理方法である.
クライアント処理:クライアントに対してJavascriptスクリプトを使用して、次のように解決できます.
1.繰り返しリフレッシュ、繰り返しコミットWays One:一度だけコミットできる変数を設定します.
 
<script language="javascript"> 
    var checkSubmit*** = false; 
    function checkSubmit() { 
      if (checkSubmit*** == true) { 
         return false; 
      } 
      checkSubmit*** = true; 
      return true; 
   } 
   document.ondblclick = function docondblclick() { 
    window.event.returnValue = false; 
   } 
   document.onclick = function doconclick() { 
       if (checkSubmit***) { 
         window.event.returnValue = false; 
       } 
   } 
</script> 



 
 
 
Way Two:コミットボタンまたはimageをdisable        
2.ユーザーの後退を防ぐ方法は様々で、ブラウザの履歴を変更する方法もあります.例えばwindowを使用します.history.forward()メソッド;「現在の履歴を新しいページのURLで置き換えると、履歴をブラウズするページが1つしかなく、後退ボタンが使用可能にならない」というものもあります.例えばjavascript:location.replace(this.href); event.returnValue=false;
2.サーバ側の処理(ここではStrutsフレームワークの処理のみ)は、同期トークン(Token)メカニズムを用いてWebアプリケーションにおける重複コミットの問題を解決し、Strutsも参照実装を与える.
基本原理:サーバ側は、到着したリクエストを処理する前に、リクエストに含まれるトークン値を現在のユーザセッションに保存されているトークン値と比較し、一致するかどうかを確認します.要求の処理が完了し、応答がクライアントに送信される前に、クライアントに渡されるほか、ユーザセッションに保存されている古いトークンを置き換える新しいトークンが生成される.これにより,ユーザが先ほどのコミットページに戻って再度コミットすると,クライアントから送信されたトークンがサーバ側のトークンと一致せず,重複コミットの発生を効果的に防止できる.
if (isTokenValid(request, true)) { 
    // your code here 
    return mapping.findForward("success"); 
} else { 
    saveToken(request); 
    return mapping.findForward("submitagain"); 
}

 
 
Strutsは、ユーザセッションIDおよび現在のシステム時間に基づいて一意の(各セッションについて)トークンを生成し、具体的なインプリメンテーションは、TokenProcessorクラスのgenerateToken()メソッドを参照することができる.
1.//トランザクション制御トークンを検証し、はセッションのIDに基づいて自動的に暗黙のinput代表トークンを生成し、2回のコミットを防止する.アクション:
 //<input type="hidden" name="org.apache.struts.taglib.html.TOKEN"  
       //  value="6aa35341f25184fd996c4c918255c3ae"> 
       if (!isTokenValid(request)) 
           errors.add(ActionErrors.GLOBAL_ERROR, 
                      new ActionError("error.transaction.token")); 
       resetToken(request); //  session     

 
 3. Actionではトークンを生成する方法があります
 
   protected String generateToken(HttpServletRequest request) { 
       HttpSession session = request.getSession(); 
       try { 
           byte id[] = session.getId().getBytes(); 
           byte now[] = 
               new Long(System.currentTimeMillis()).toString().getBytes(); 
           MessageDigest md = MessageDigest.getInstance("MD5"); 
           md.update(id); 
           md.update(now); 
           return (toHex(md.digest())); 
       } catch (IllegalStateException e) { 
           return (null); 
       } catch (NoSuchAlgorithmException e) { 
           return (null); 
       } 
   }  

 
重複コミット、重複リフレッシュ、後退防止などは、システムが重複記録を回避するために解決しなければならない問題であり、クライアントで処理するには、それぞれの可能性に対応した解決策を提案する必要があるが、サーバ側から見れば、データの真実性の検証問題にすぎず、トークンベースの処理は永遠の方法である.
同時に、異なる角度から問題を見ると、その解決方法も異なることも見られます.クライアントはユーザーの操作を追求しているが、サービス側はデータの処理に集中しているので、サーバ側にとって容易に見える問題では、クライアントで解決するのは面倒だ.逆は相変わらず.だから、いくつかの問題の処理では、クライアントで解決するために総合的な考慮とバランスが必要ですか?それともサーバー側で処理しますか?