答えは質問にあります-「フォームの送信が重複しています」、サーバーに2つのリクエストが送信されているため、両方に対処する必要があります。
したがって、2 つの同一の要求がブラウザーからサーバーに送信されるため、アクションは 2 回呼び出されます。
最初のリクエストは成功し、「withForm」ブロックのコードを使用して、トークンがインクリメントされます。
2 番目のリクエストには最初のリクエストと同じトークンがまだ含まれていますが、サーバーはそのトークンを破棄したため、2 番目のリクエストは「invalidToken」ブロックのコードを使用するか、「invalidToken」ブロックを省略した場合はデフォルト ブロックを使用します。 .
重要な点の 1 つは、ブラウザーに表示される内容を決定するのは 2 番目の (悪い) 要求です。最初の要求の後に到着するため、悪い要求を処理する際に、ユーザーをインデックスにリダイレクトすることにしました。 、最初の要求によって作成および保存されたレコードを表示できるはずです。すなわち
}.invalidToken
{
println "myController: swallowing request with invalidToken (probably a double-click or due to using back button in browser.)"
flash.invalidToken = " " // just enough to trigger the g:if in the index.gsp
redirect action:"index", method:"GET"
}
次に、index.gsp に次のメッセージを表示します。
<g:if test="${flash.invalidToken}">
<ul class="errors" role="alert">
<li>
<g:message code="error.doubleclick"
default="oops, the item you are creating exists already (maybe you double-clicked on the 'Save' button ?). Click on the item in the list below to continue working with that item."
/>
</li>
</ul>
これは問題なく動作し、カスタマイズする必要なく、任意のコントローラーと index.gsp に切り貼りできるほど一般的です。