フォームの2度押し防止

フォームの送信ボタンを1度押した後に、ブラウザの戻るボタンでフォームページに戻ってまた送信を押す、2重送信(と言うんだろうか…)はウェブアプリケーションではよくある問題だ。 Strutsではsynchronizing tokenを使って二重送信を防止する。
簡単な例で説明しよう。 まずアクションマッピングは次のようになる。


<action path="/contact"
type="app.actions.SetupContactAction"
scope="request">
<forward name="success" path="/contactForm.jsp" />
</action>
<action path="/contact/submit"
type="app.actions.ContactSubmitAction"
name="contactForm"
validate="true"
input="/contactForm.jsp"
scope="request">
<forward name="success" path="/contactConfirm.jsp" />
</action>

contactForm.jspを呼び出す前にSetupContactFormActionを呼び出し、セッションにTokenをおく。

public class SetupContactFormAction extends Action {
public ActionForward execute (...) {
saveToken(request);
return mapping.findForward("success");
}
}
contactForm.jspで送信ボタンを押すと、htmlタグが自動的にセッションからTokenを見つけ、hiddenフィールドとして埋め込まれる。 便利にできてるもんだ。
そしてContactSubmitActionではTokenが有効かどうかをチェックし、結果に応じて処理する。

public class ContactSubmitAction extends Action {
public ActionForward execute (...) {
//Tokenが有効=フォームを送信
if(isTokenValid(request)) {
resetToken(request);
//ここでフォームの処理。
}
//2度押しの場合
else {
saveToken(request);
ActionMessages message = new ActionMessages();
message.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("message.contact.resubmit"));
saveMessages(request, message);
}
return mapping.findForward("success");
}
}
上の例では、2度押しの場合でもcontactConfirm.jspフォワードし、メッセージを表示するようにしている。 contactConfirm.jspでは<html:messages>タグを使う。

<logic:messagesPresent message="true">
<html:messages id="message" message="true">
<bean:write name="message" />
</html:messages>
</logic:messagesPresent>
もちろん、Tokenが有効でない場合は別のページにフォワードすることもできる。 このあたりはアプリケーションの流れによって変わってくる。