web-dev-qa-db-ja.com

二重送信防止のための純粋なJava / JSF実装

WebSpherev8.5でJSF2.0を使用しており、いくつかのコンポーネントライブラリPrimeFaces 4.0、Tomahawk 2.0、RichFacesなどがあります。

ページが更新されたとき、または送信ボタンがもう一度クリックされたときにフォームが再送信されないようにするための一般的なメカニズムを探しています。さまざまなシナリオのアプリケーションがたくさんあります。

今のところ、onclick属性のJavaScriptでボタンを無効にすることを検討しましたが、これでは満足できません。この目的のための純粋なJava実装、Struts2 <s:token>のようなものを探しています。

14
Sarz

ページが更新されたときにフォームが再送信されないようにするための一般的なメカニズムを探しています

そのために組み合わせることができない少なくとも2つの解決策があります:

  1. 同期投稿後にリダイレクトを実行します。このように、更新は、最初の要求ではなく、リダイレクトされたGET要求のみを再実行します。短所:エンドユーザーにフィードバックを提供するためにリクエストスコープを利用できなくなりました。 JSF 2.0は、新しい フラッシュスコープ を提供することでこれを解決しました。 リダイレクトされたページにfacesメッセージを表示する方法 も参照してください。

  2. POSTバックグラウンドで非同期に(ajaxを使用して)実行します。このようにすると、更新はフォームを開いた最初のGETリクエストのみを再実行します。これらのフォームが最初にあることを確認するだけで済みます。 GETリクエストによってのみ開かれます。つまり、POST(とにかくそれ自体はすでに悪いデザインです)によってページ間ナビゲーションを実行しないでください。 いつすべきか)も参照してください。 h:commandLinkの代わりにh:outputLinkを使用しますか?


または送信ボタンがもう一度クリックされたとき

そのためには、基本的に少なくとも2つのソリューションがあり、必要に応じて組み合わせることができます。

  1. 送信中および/または送信が成功した後、エンドユーザーが送信ボタンを押すことができないようにブロックするだけです。これにはさまざまな方法がありますが、すべて具体的な機能要件と設計要件によって異なります。 JavaScriptを使用して、送信中にボタンを無効にすることができます。 JSFのdisabledまたはrendered属性を使用して、送信後にボタンを無効または非表示にすることができます。 JSF 2でダブルクリック防止を行う方法 も参照してください。 ajaxリクエストの処理中にオーバーレイウィンドウを使用して、エンドユーザーの操作をブロックすることもできます。 PrimeFacesには<p:blockUI> 目的のために。

  2. サーバー側で新しく追加されたエンティティの一意性を検証します。機能的な理由ではなく技術的な理由で重複を絶対に避けたい場合、これははるかに堅牢です。非常に簡単です。問題のDB列にUNIQUE制約を設定します。この制約に違反すると、DB(およびJPAなどのDBインタラクションフレームワーク)は制約違反例外をスローします。これは、正確にその列に対してSELECTを実行し、レコードが返されないかどうかを確認することにより、入力を事前に検証するカスタムJSFバリデーターと組み合わせて実行するのが最適です。 JSFバリデーターを使用すると、問題をわかりやすい顔のメッセージのフレーバーで表示できます。とりわけ 電子メールの形式とDBに対する一意性を検証する も参照してください。

17
BalusC

トークンを手動で作成する代わりに、BalusCのソリューションを使用できます。彼は 彼のブログ でPost-Redirect-GETパターンを提案しました

代替ソリューションは、次の回答にあります。

3
Manuel
<!--Tag to show message given by bean class -->
<p:growl id="messages" />

<h:form>
  <h:inputText a:placeholder="Enter Parent Organization Id" id="parent_org_id" value="#{orgMaster.parentOrganization}" requiredMessage="Parent org-id is required" />


  <h:commandButton style="margin-bottom:8px;margin-top:5px;" class="btn btn-success btn-block " value="Save" type="submit" action="#{orgMaster.save}" onclick="resetform()" />
</h:form>
    public String save() {
    FacesContext context = FacesContext.getCurrentInstance();
    context.getExternalContext().getFlash().setKeepMessages(true); //This keeps the message even on reloading of page

FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Your submission is successful.", " ")); // To show the message on clicking of submit button


return "organizationMaster?faces-redirect=true"; // to reload the page with resetting of all fields of the form.. here my page name is organizationMaster...you can write the name of form whose firlds you want to reset on submission

}
0
Vinod Chauhan