Browse Source

Improve @SessionAttributes support during redirect

Before this change attributes listed with @SessionAttributes would not
be saved in the session when there was a redirect and the controller
method declared a parameter of type RedirectAttributes.

This change ensures it's the "default" model that is always the one
checked for @SessionAttributes under all circumstances since
RedirectAttributes is really only meant to provide String values to
insert into or append to the the redirect URL.

Issue: SPR-12542
pull/712/head
Rossen Stoyanchev 11 years ago
parent
commit
ea05e0b1ad
  1. 7
      spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
  2. 13
      spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
  3. 26
      spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java

7
spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java

@ -224,14 +224,15 @@ public final class ModelFactory { @@ -224,14 +224,15 @@ public final class ModelFactory {
* @throws Exception if creating BindingResult attributes fails
*/
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
ModelMap defaultModel = mavContainer.getDefaultModel();
if (mavContainer.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
this.sessionAttributesHandler.storeAttributes(request, defaultModel);
}
if (!mavContainer.isRequestHandled()) {
updateBindingResult(request, mavContainer.getModel());
if (!mavContainer.isRequestHandled() && mavContainer.getModel() == defaultModel) {
updateBindingResult(request, defaultModel);
}
}

13
spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java

@ -137,6 +137,19 @@ public class ModelAndViewContainer { @@ -137,6 +137,19 @@ public class ModelAndViewContainer {
return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
}
/**
* Return the "default" model created at instantiation.
* <p>In general it is recommended to use {@link #getModel()} instead which
* returns either the "default" model (template rendering) or the "redirect"
* model (redirect URL preparation). Use of this method may be needed for
* advanced cases when access to the "default" model is needed regardless,
* e.g. to save model attributes specified via {@code @SessionAttributes}.
* @return the default model, never {@code null}
*/
public ModelMap getDefaultModel() {
return this.defaultModel;
}
/**
* Provide a separate model instance to use in a redirect scenario.
* The provided additional model however is not used used unless

26
spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java

@ -215,6 +215,32 @@ public class ModelFactoryTests { @@ -215,6 +215,32 @@ public class ModelFactoryTests {
assertNull(this.sessionAttributeStore.retrieveAttribute(this.webRequest, attributeName));
}
// SPR-12542
@Test
public void updateModelWhenRedirecting() throws Exception {
String attributeName = "sessionAttr";
String attribute = "value";
ModelAndViewContainer container = new ModelAndViewContainer();
container.addAttribute(attributeName, attribute);
String queryParam = "123";
String queryParamName = "q";
container.setRedirectModel(new ModelMap(queryParamName, queryParam));
container.setRedirectModelScenario(true);
WebDataBinder dataBinder = new WebDataBinder(attribute, attributeName);
WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
given(binderFactory.createBinder(this.webRequest, attribute, attributeName)).willReturn(dataBinder);
ModelFactory modelFactory = new ModelFactory(null, binderFactory, this.sessionAttrsHandler);
modelFactory.updateModel(this.webRequest, container);
assertEquals(queryParam, container.getModel().get(queryParamName));
assertEquals(1, container.getModel().size());
assertEquals(attribute, this.sessionAttributeStore.retrieveAttribute(this.webRequest, attributeName));
}
private String bindingResultKey(String key) {
return BindingResult.MODEL_KEY_PREFIX + key;

Loading…
Cancel
Save