Tagbangers Blog

Spring MVC で Post-Redirect-Get パターンをやってみる

Spring MVC で Post-Redirect-Get パターンを実装するときのやり方をメモ。

コードは GitHub にもあります。
https://github.com/tagbangers/spring-best-practice...

パターン1:セッションを使わない

package practice.post_redirect_get;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
@RequestMapping("/basic")
public class BasicExampleController {

   public static final String FORM_MODEL_KEY = "form";
   public static final String ERRORS_MODEL_KEY = BindingResult.MODEL_KEY_PREFIX + FORM_MODEL_KEY;

   @RequestMapping
   public String get(Model model) {
      BasicExampleForm form = (BasicExampleForm) model.asMap().get(FORM_MODEL_KEY);
      if (form == null) {
         form = new BasicExampleForm();
      }
      model.addAttribute(FORM_MODEL_KEY, form);
      return "basic";
   }

   @RequestMapping(method = RequestMethod.POST)
   public String post(
         @Validated BasicExampleForm form,
         BindingResult result,
         RedirectAttributes redirectAttributes) {
      redirectAttributes.addFlashAttribute(FORM_MODEL_KEY, form);
      redirectAttributes.addFlashAttribute(ERRORS_MODEL_KEY, result);

      if (result.hasErrors()) {
         return "redirect:/basic";
      }

      // Do something. For example, call a method of a service class.

      redirectAttributes.getFlashAttributes().clear();
      redirectAttributes.addFlashAttribute("message", "Success!");
      return "redirect:/basic";
   }
}

パターン2:セッションを使う

入力ページが複数に渡るウィザードのようなページを作りたい時など。

package practice.post_redirect_get;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.HttpSessionRequiredException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
@RequestMapping("/session")
@SessionAttributes(types = SessionExampleForm.class)
public class SessionExampleController {

   public static final String FORM_MODEL_KEY = "form";
   public static final String ERRORS_MODEL_KEY = BindingResult.MODEL_KEY_PREFIX + FORM_MODEL_KEY;

   @ExceptionHandler(HttpSessionRequiredException.class)
   public String handleHttpSessionRequiredException(HttpSessionRequiredException exception) {
      return "redirect:/session?expired";
   }

   @RequestMapping
   public String init(Model model) {
      SessionExampleForm form = new SessionExampleForm();
      model.addAttribute(FORM_MODEL_KEY, form);
      return "session-step1";
   }

   @RequestMapping(params = "step1")
   public String step1(Model model) {
      SessionExampleForm form = (SessionExampleForm) model.asMap().get(FORM_MODEL_KEY);
      if (form == null) {
         form = new SessionExampleForm();
      }
      model.addAttribute(FORM_MODEL_KEY, form);
      return "session-step1";
   }

   @RequestMapping(params = "step1", method = RequestMethod.POST)
   public String step1(
         @Validated SessionExampleForm form,
         BindingResult result,
         RedirectAttributes redirectAttributes) {
      redirectAttributes.addFlashAttribute(FORM_MODEL_KEY, form);
      redirectAttributes.addFlashAttribute(ERRORS_MODEL_KEY, result);

      if (result.hasFieldErrors("email")) {
         return "redirect:/session?step1";
      }

      redirectAttributes.getFlashAttributes().clear();
      return "redirect:/session?step2";
   }

   @RequestMapping(params = "step2")
   public String step2(Model model) throws HttpSessionRequiredException {
      SessionExampleForm form = (SessionExampleForm) model.asMap().get(FORM_MODEL_KEY);
      if (form == null) {
         throw new HttpSessionRequiredException("Expected session attribute '" + FORM_MODEL_KEY + "'");
      }
      model.addAttribute(FORM_MODEL_KEY, form);
      return "session-step2";
   }

   @RequestMapping(params = "step2", method = RequestMethod.POST)
   public String step2(
         @Validated SessionExampleForm form,
         BindingResult result,
         RedirectAttributes redirectAttributes) {
      redirectAttributes.addFlashAttribute(FORM_MODEL_KEY, form);
      redirectAttributes.addFlashAttribute(ERRORS_MODEL_KEY, result);

      if (result.hasErrors()) {
         return "redirect:/session?step2";
      }

      // Do something. For example, call a method of a service class.

      redirectAttributes.getFlashAttributes().clear();
      redirectAttributes.addFlashAttribute("message", "Success!");
      return "redirect:/session";
   }
}