Skip to content
This repository was archived by the owner on Feb 5, 2022. It is now read-only.

@MVC Flash Attribute Support

cbeams edited this page Aug 15, 2011 · 3 revisions

Option 1: @FlashAttributes

Description:

Attributes present in the model that match the @FlashAttributes annotation are automatically saved in flash storage only if the controller redirects.

Example:

@Controller
@FlashAttributes("successMessage")
public class MessageController {

	@RequestMapping(value = "/messages", method = RequestMethod.POST)
	public String sendMessage(TestBean testBean, BindingResult result, Model model) {
		if (result.hasErrors()) {
			return "messages/new";
		}
		else {
			model.addAttribute("id", "1").addAttribute("name", "value").addAttribute("successMessage", "yay!");
			return "redirect:/messages/{id}";
		}
	}
}

Advantages:

  • Consistent with @SessionAttributes
  • Does not require additional method arguments
  • Syncs the model transparently

Things to Consider:

  • While @SessionAttributes targets command objects applicable to several methods, @FlashAttributes targets redirect-specific data and may be unique to a method. Hence a type-level annotation may be an assortment of attribute names each applicable to a different redirect.
  • Flash attributes are added conditionally (e.g. success message on redirect after post); you are likely to reference them twice -- in the annotation and in the controller method.
  • What is the meaning of @FlashAttributes when one controller redirects to another? Should the recipient controller list the flash attributes it expects? In which case it would not be clear what it accepts vs what it stores, unless the annotation makes it explicit.

Option 2: ResponseContext Method Argument

Description:

ResponseContext method argument provides convenience methods for selecting between a view for rendering vs a view for redirecting. On a redirect we start with an empty model and distinguish among URI variables, query params, and flash attributes. For rendering we use the implicit model and expect a view name.

Example:

@Controller
public class MessageController {

	@RequestMapping(value = "/messages", method = RequestMethod.POST)
	public void sendMessage(TestBean testBean, BindingResult result, ResponseContext responseContext) {
		if (result.hasErrors()) {
			responseContext.view("messages/new");
		}
		else {
			responseContext.redirect("redirect:/messages/{id}").uriVariable("id", "1").queryParam("name", "value")
					.flashAttribute("successMessage", "yay!");
		}
	}
}

Advantages:

  • Flash attributes are specified once and in the place they are needed.
  • Addresses a long standing, related concern to provide better control over the model when redirecting (SPR-1068, SPR-1294, SPR-6796)

Things to Consider:

  • Use of ResponseContext assumes a void return value, which prevents the use of pluggable HandlerMethodReturnValueHandlers or custom ModelAndViewResolvers. Hence there is no way of customizing the response handling.
  • If the user does return a value (by mistake) we can only flag that as an error at runtime. Even then some ambiguity remains - i.e. what is the meaning of combining a ResponseContext argument with annotations like @ResponseStatus, @ModelAttribute, @ResponseBody.
  • How does one return a RedirectView or a RedirectView sub-type?
  • No control over what flash attributes a controller method accepts.

Option 3: ResponseInstruction Return Value

Description:

The method sets up and returns ResponseInstruction selecting between a view for rendering vs redirecting. Similar to a ResponseContext method argument but using a return value instead.

Example:

@Controller
public class MessageController {

	@RequestMapping(value = "/messages", method = RequestMethod.POST)
	public ResponseInstruction sendMessage(TestBean testBean, BindingResult result) {
		if (result.hasErrors()) {
			return new ViewInstruction("messages/new");
		}
		else {
			return new RedirectInstruction("redirect:/messages/{id}").uriVariable("id", "1")
					.queryParam("name", "value").flashAttribute("successMessage", "yay!");
		}
	}
}

Advantages:

  • Same as for RedirectContext

Things to Consider:

  • Slightly more verbose than returning a String view name
  • How does one return a RedirectView or a RedirectView sub-type?
  • No control over what flash attributes a controller method accepts.

Option 4: RedirectModel Method Argument

Description:

Controller method declares a RedirectModel method argument. This model is used only if the controller decides to redirect. Initially the RedirectModel is empty. However, it wraps the implicit model making it easy to copy attributes by name. Attributes stored in the RedirectModel are immediately formatted as strings (via DataBinder) in preparation for inclusion in the URL.

Example:

@Controller
public class MessageController {

	@RequestMapping(value = "/messages", method = RequestMethod.POST)
	public String sendMessage(TestBean testBean, BindingResult result, RedirectModel redirectModel) {
		if (result.hasErrors()) {
			return "messages/new";
		}
		else {
			redirectModel.addAttribute("id", "1").addAttribute("name", "value")
					.addFlashAttribute("successMessage", "yay!");
			return "redirect:/messages/{id}";
		}
	}
}

Advantages:

  • Flash attributes are specified once and in the place they are needed.
  • Addresses a long standing, related concern to provide precise control over the model when redirecting (SPR-1068, SPR-1294, SPR-6796)
  • Makes it easy to copy attributes from the implicit model
  • Formats attributes as Strings using @MVC registered type conversion

Things to Consider:

  • Using the implicit model on a redirect is less than ideal but does that justify the need for a different kind of model?
  • No control over what flash attributes a controller method accepts.
Clone this wiki locally