Contents
PRGパターンとは?
PRGパターンとは、Post>Redirect>Get により画面遷移させることです。
Postしたあと、ただ単にHTMLをレスポンスするのではなくて、次の画面にリダイレクト遷移させます。
PRGパターンは、Webアプリで登録・更新・削除を行なった次の画面を表示するときに使用します。
リダイレクトとは?
PRGパターンを理解するには、リダイレクトを理解する必要があります。
リダイレクトとは、ユーザーに対して「指定したURLにGETしてくださいね」というレスポンスの一種です。
図の②の302リダイレクトというとレスポンスをクライアント(ブラウザ)が受けとると、即座に次のURLに対して③のGetリクエストが実行されます。
その結果、クライアントには④のレスポンスが返却されて、ブラウザには遷移先画面が表示されます。
PRGパターンのメリット(必要性)
なぜ、PRGパターンで実装しないといけないかというと、二重送信(二重登録、二重更新、二重削除)を防ぐためです。
PRGパターンのデメリット
ユーザーにとっては、1度のリクエストで2度リクエストが発生することになるので回線速度によっては少し遅く感じることがあるかもしれません。
(2度目のリクエストはブラウザが自動でやってくれるので、手を煩わせることはありません)
物理的に2回リクエストが発生するという性質上、単純な1回のリクエストで済ませるよりは遅くなります。
が、体感的に遅く感じるほどのことにはならないため、現場ではPRGパターンをやめるという話にはなりません。
SpringBootでPRGパターンの実装サンプルコード
サンプルコード
登録完了のコントローラー
...
@PostMapping("/children/registerFinish")
public String registerFinish(@Validated ChildRegisterForm childRegisterForm, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes) {
// 入力チェック
if (bindingResult.hasErrors()) {
return "children/register";
}
// 登録可否チェック
boolean canRegister = childrenService.canRegister(childRegisterForm.getName());
if (!canRegister) {
model.addAttribute("message", "既に同じ名前が登録されています。");
return "children/register";
}
// 登録実行
var child = ChildrenControllerHelper.toChild(childRegisterForm);
childrenService.register(child);
// 画面遷移
redirectAttributes.addFlashAttribute("message", child.getName() + "を登録しました。");
return "redirect:/children";
}
...
・23行目 SpringBootでは、return文字列に"redirect:パス"と書くことで、302リダイレクトになります。
・22行目 RedirectAttributes#addFlashAttributeを使うことで、リダイレクト先に何らかの値を渡すことができます。
ここでは、登録成功メッセージを渡しています。
リダイレクト先(画面遷移先)の一覧表示画面のコントローラー
...
@RequestMapping("/children")
public String index(Model model) {
// 子どもリストを取得
List<Child> children = childrenService.getAll();
// 画面表示
Object message = model.getAttribute("message");
if (message != null) {
model.addAttribute("message", String.valueOf(message));
}
model.addAttribute("children", children);
return "children/index";
}
...
PRGパターンでパラメータを渡すには?
方法1 フラッシュスコープで渡す
上記の例では、"message"を渡していますが、渡せるものに制限は特にありません。
渡す側
@PostMapping("/children/registerFinish")
public String registerFinish(RedirectAttributes redirectAttributes) {
...
redirectAttributes.addFlashAttribute("パラメータ名", パラメータ);
...
}
・4行目 SpringBootでは、上記のようにRedirectAttributes#addFlashAttributeを使用することで、リダイレクト先にパラメータを渡すことができます。
・2行目 実行メソッドの引数にRedirectAttributesクラスの変数を書きます。
受け取る側(遷移先)
@RequestMapping("/children")
public String index(Model model) {
...
Object hoge = model.getAttribute("パラメータ名");
...
}
・2行目 渡す側でaddFlashAttributeで指定した値を受け取るには、実行メソッドの引数にModelクラスの変数を書きます。
・4行目 Model#getAttributeにより値を受け取ることができます。戻り値はObject型なので、値を使う場合は適宜キャストして使ってください。
方法2 URLパラメータとして渡す
フラッシュスコープを使わずとも、URLパラメータとして渡すこともできます。
渡す側
@PostMapping("/children/registerFinish")
public String registerFinish(...) {
...
return "redirect:/children?id=" + xxx.getId();
}
・4行目 上記のようにすることで、"/children?id=123"のようなURLにGetリクエストすることになります。
受け取る側(遷移先)
@RequestMapping("/children")
public String index(String id, Model model) {
...
something to do
...
}
・2行目 Getパラメータを受け取る要領で、リダイレクト元からのパラメータを受け取ることができます。