Spring <form:errors>
タグを介して後続のGETで使用できるように、BindingResultを「保持」する方法を見つけようとしています。これを行う理由は、Google App EngineのSSL制限のためです。 HTTP経由で表示されるフォームがあり、投稿はHTTPS URLに対して行われます。リダイレクトではなく転送のみを行うと、ユーザーには https://whatever.appspot.com/my/form URLが表示されます。これを避けようとしています。これにアプローチする方法はありますか?
以下は私がやりたいことですが、return "create"
を使用したときにのみ検証エラーが表示されます。
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(
@ModelAttribute("register") @Valid final Register register,
final BindingResult binding) {
if (binding.hasErrors()) {
return "redirect:/register/create";
}
return "redirect:/register/success";
}
Spring 3.1以降では、RedirectAttributesを使用できます。リダイレクトを行う前に、使用可能にする属性を追加します。 BindingResultと、検証に使用しているオブジェクト(この場合はRegister)の両方を追加します。
BindingResultには、「org.springframework.validation.BindingResult。[ModelAttributeの名前]」という名前を使用します。
検証に使用しているオブジェクトには、ModelAttributeの名前を使用します。
RedirectAttributesを使用するには、設定ファイルにこれを追加する必要があります。特に、いくつかの新しいクラスを使用するようSpringに指示しています。
<mvc:annotation-driven />
これで、リダイレクト先にエラーが表示されます
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(@ModelAttribute("register") @Valid final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) {
if (binding.hasErrors()) {
attr.addFlashAttribute("org.springframework.validation.BindingResult.register", binding);
attr.addFlashAttribute("register", register);
return "redirect:/register/create";
}
return "redirect:/register/success";
}
オスカーの素敵な答えに加えて、そのRedirectAttributes
アプローチに従っている場合、リダイレクトされたページに実際にmodelAttribute
を渡していることを忘れないでください。これは、リダイレクトされたページ(コントローラー内)のそのmodelAttributeの新しいインスタンスを作成すると、検証エラーが失われることを意味します。したがって、[〜#〜] post [〜#〜]コントローラーメソッドが次のようなものである場合:
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(@ModelAttribute("register") @Valid final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) {
if (binding.hasErrors()) {
attr.addFlashAttribute("org.springframework.validation.BindingResult.register", binding);
attr.addFlashAttribute("register", register);
return "redirect:/register/create";
}
return "redirect:/register/success";
}
その後、おそらくレジスタ作成ページ[〜#〜] get [〜#〜]コントローラーで変更を行う必要があります。これから:
@RequestMapping(value = "/register/create", method = RequestMethod.GET)
public String registerCreatePage(Model model) {
// some stuff
model.addAttribute("register", new Register());
// some more stuff
}
に
@RequestMapping(value = "/register/create", method = RequestMethod.GET)
public String registerCreatePage(Model model) {
// some stuff
if (!model.containsAttribute("register")) {
model.addAttribute("register", new Register());
}
// some more stuff
}
なぜリダイレクトが必要なのか疑問に思うでしょう。同じURLに送信するだけで、POSTに対して異なる応答をするのはなぜですか?それにもかかわらず、本当にこれをしたい場合:
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(
@ModelAttribute("register") @Valid final Register register,
final BindingResult binding,
HttpSession session) {
if (binding.hasErrors()) {
session.setAttribute("register",register);
session.setAttribute("binding",binding);
return "redirect:/register/create";
}
return "redirect:/register/success";
}
次に、「作成」メソッドで:
model.put("register",session.getAttribute("register"));
model.put("org.springframework.validation.BindingResult.register",session.getAttribute("register"));
リクエスト間でオブジェクトを永続化する唯一の方法(リダイレクトなど)は、セッション属性にオブジェクトを保存することです。そのため、両方のメソッド(getおよびpost)のメソッドパラメーターに「HttpServletRequest request」を含め、request.getAttribute( "binding")を介してオブジェクトを取得します。そうは言っても、自分で試していないので、新しいリクエストでオブジェクトへのバインディングを再バインドする方法を理解する必要があるかもしれません。
もう1つの「より良い」方法は、javascriptを使用してブラウザのURLを変更することです
問題は、ビューをレンダリングして処理済みのフォームページを返すのではなく、新しいコントローラーにリダイレクトしていることです。次の行に沿って何かをする必要があります。
String FORM_VIEW = wherever_your_form_page_resides
...
if (binding.hasErrors())
return FORM_VIEW;
文字列のコードの重複により、メソッドの外部のパスを保持します。
Google App Engineの正確な問題はわかりませんが、 ForwardedHeaderFilter を使用すると、クライアントが使用した元のスキームを保持するのに役立つ場合があります。このフィルターはSpring Framework 4.3で追加されましたが、一部のサーブレットコンテナーは同様のフィルターを提供します。フィルターは自給式なので、必要に応じてソースを取得することもできます。