SPR-6464 Polish FlashMap changes.
This commit is contained in:
parent
f0ed37c233
commit
671744aa62
|
|
@ -671,7 +671,8 @@ public class DispatcherServlet extends FrameworkServlet {
|
|||
|
||||
/**
|
||||
* Initialize the {@link FlashMapManager} used by this servlet instance.
|
||||
* <p>If no implementation is configured then we default to DefaultFlashMapManager.
|
||||
* <p>If no implementation is configured then we default to
|
||||
* {@code org.springframework.web.servlet.support.DefaultFlashMapManager}.
|
||||
*/
|
||||
private void initFlashMapManager(ApplicationContext context) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import java.util.LinkedHashMap;
|
|||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A FlashMap provides a way for one request to store attributes intended for
|
||||
|
|
@ -33,11 +32,14 @@ import org.springframework.util.Assert;
|
|||
* <p>A FlashMap can be set up with a request path and request parameters to
|
||||
* help identify the target request. Without this information, a FlashMap is
|
||||
* made available to the next request, which may or may not be the intended
|
||||
* result. Before a redirect, the target URL is known and when using the
|
||||
* {@code org.springframework.web.servlet.view.RedirectView}, FlashMap
|
||||
* instances are automatically updated with redirect URL information.
|
||||
* recipient. On a redirect, the target URL is known and for example
|
||||
* {@code org.springframework.web.servlet.view.RedirectView} has the
|
||||
* opportunity to automatically update the current FlashMap with target
|
||||
* URL information .
|
||||
*
|
||||
* <p>Annotated controllers will usually not access a FlashMap directly.. TODO
|
||||
* <p>Annotated controllers will usually not use this type directly.
|
||||
* See {@code org.springframework.web.servlet.mvc.support.RedirectAttributes}
|
||||
* for an overview of using flash attributes in annotated controllers.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
|
@ -58,13 +60,6 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
|||
|
||||
private final int createdBy;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*/
|
||||
public FlashMap() {
|
||||
this.createdBy = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance with an id uniquely identifying the creator of
|
||||
* this FlashMap.
|
||||
|
|
@ -73,19 +68,25 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
|||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*/
|
||||
public FlashMap() {
|
||||
this.createdBy = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a URL path to help identify the target request for this FlashMap.
|
||||
* The path may be absolute (e.g. /application/resource) or relative to the
|
||||
* current request (e.g. ../resource).
|
||||
* @param path the URI path, never {@code null}
|
||||
* @param path the URI path
|
||||
*/
|
||||
public void setTargetRequestPath(String path) {
|
||||
Assert.notNull(path, "Expected path must not be null");
|
||||
this.targetRequestPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL path of the target request, or {@code null} if none.
|
||||
* Return the target URL path or {@code null}.
|
||||
*/
|
||||
public String getTargetRequestPath() {
|
||||
return targetRequestPath;
|
||||
|
|
@ -93,10 +94,9 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
|||
|
||||
/**
|
||||
* Provide request parameter pairs to identify the request for this FlashMap.
|
||||
* If not set, the FlashMap will match to requests with any parameters.
|
||||
* Only simple value types, as defined in {@link BeanUtils#isSimpleValueType},
|
||||
* are used.
|
||||
* Only simple type, non-null parameter values are used.
|
||||
* @param params a Map with the names and values of expected parameters.
|
||||
* @see BeanUtils#isSimpleValueType(Class)
|
||||
*/
|
||||
public FlashMap addTargetRequestParams(Map<String, ?> params) {
|
||||
if (params != null) {
|
||||
|
|
@ -112,10 +112,8 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
|||
|
||||
/**
|
||||
* Provide a request parameter to identify the request for this FlashMap.
|
||||
* If not set, the FlashMap will match to requests with any parameters.
|
||||
*
|
||||
* @param name the name of the expected parameter (never {@code null})
|
||||
* @param value the value for the expected parameter (never {@code null})
|
||||
* @param name the name of the expected parameter, never {@code null}
|
||||
* @param value the value for the expected parameter, never {@code null}
|
||||
*/
|
||||
public FlashMap addTargetRequestParam(String name, String value) {
|
||||
this.targetRequestParams.put(name, value.toString());
|
||||
|
|
@ -130,9 +128,8 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
|||
}
|
||||
|
||||
/**
|
||||
* Start the expiration period for this instance. After the given number of
|
||||
* seconds calls to {@link #isExpired()} will return "true".
|
||||
* @param timeToLive the number of seconds before flash map expires
|
||||
* Start the expiration period for this instance.
|
||||
* @param timeToLive the number of seconds before expiration
|
||||
*/
|
||||
public void startExpirationPeriod(int timeToLive) {
|
||||
this.expirationStartTime = System.currentTimeMillis();
|
||||
|
|
@ -140,8 +137,8 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
|||
}
|
||||
|
||||
/**
|
||||
* Whether the flash map has expired depending on the number of seconds
|
||||
* elapsed since the call to {@link #startExpirationPeriod}.
|
||||
* Whether this instance has expired depending on the amount of elapsed
|
||||
* time since the call to {@link #startExpirationPeriod}.
|
||||
*/
|
||||
public boolean isExpired() {
|
||||
if (this.expirationStartTime != 0) {
|
||||
|
|
@ -160,8 +157,9 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
|||
}
|
||||
|
||||
/**
|
||||
* Compare two FlashMaps and select the one that has a target URL path or
|
||||
* has more target request parameters.
|
||||
* Compare two FlashMaps and prefer the one that specifies a target URL
|
||||
* path or has more target URL parameters. Before comparing FlashMap
|
||||
* instances ensure that they match a given request.
|
||||
*/
|
||||
public int compareTo(FlashMap other) {
|
||||
int thisUrlPath = (this.targetRequestPath != null) ? 1 : 0;
|
||||
|
|
@ -178,8 +176,8 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
|||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("[Attributes=").append(super.toString());
|
||||
result.append(", expecteRequestUri=").append(this.targetRequestPath);
|
||||
result.append(", expectedRequestParameters=" + this.targetRequestParams.toString()).append("]");
|
||||
result.append(", targetRequestPath=").append(this.targetRequestPath);
|
||||
result.append(", targetRequestParams=" + this.targetRequestParams.toString()).append("]");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,20 +16,22 @@
|
|||
|
||||
package org.springframework.web.servlet;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* A strategy interface for storing and retrieving {@code FlashMap} instances.
|
||||
* See {@link FlashMap} for a general overview of using flash attributes.
|
||||
* A strategy interface for storing, retrieving, and managing {@code FlashMap}
|
||||
* instances. See {@link FlashMap} for a general overview of flash attributes.
|
||||
*
|
||||
* <p>A FlashMapManager is invoked at the beginning and at the end of a request.
|
||||
* For each request, it exposes an "input" FlashMap with attributes passed from
|
||||
* a previous request (if any) and an "output" FlashMap with attributes to pass
|
||||
* to a subsequent request. Both FlashMap instances are exposed via request
|
||||
* attributes and can be accessed through methods in
|
||||
* {@code org.springframework.web.servlet.support.RequestContextUtils}.
|
||||
* <p>A FlashMapManager is invoked at the beginning and at the end of requests.
|
||||
* For each request it retrieves an "input" FlashMap with attributes passed
|
||||
* from a previous request (if any) and creates an "output" FlashMap with
|
||||
* attributes to pass to a subsequent request. "Input" and "output" FlashMap
|
||||
* instances are exposed as request attributes and are accessible via methods
|
||||
* in {@code org.springframework.web.servlet.support.RequestContextUtils}.
|
||||
*
|
||||
* <p>Annotated controllers are most likely to store and access flash attributes
|
||||
* through their model.
|
||||
* See {@code org.springframework.web.servlet.mvc.support.RedirectAttributes}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
|
@ -39,42 +41,39 @@ import javax.servlet.http.HttpServletRequest;
|
|||
public interface FlashMapManager {
|
||||
|
||||
/**
|
||||
* Name of request attribute that holds a read-only {@link Map} with
|
||||
* "input" flash attributes from a previous request (if any).
|
||||
* Name of request attribute that holds a read-only
|
||||
* {@code Map<String, Object>} with "input" flash attributes if any.
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getInputFlashMap(HttpServletRequest)
|
||||
*/
|
||||
public static final String INPUT_FLASH_MAP_ATTRIBUTE = FlashMapManager.class.getName() + ".INPUT_FLASH_MAP";
|
||||
|
||||
/**
|
||||
* Name of request attribute that holds the "output" {@link FlashMap} with
|
||||
* attributes to pass to a subsequent request.
|
||||
* attributes to save for a subsequent request.
|
||||
* @see org.springframework.web.servlet.support.RequestContextUtils#getOutputFlashMap(HttpServletRequest)
|
||||
*/
|
||||
public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = FlashMapManager.class.getName() + ".OUTPUT_FLASH_MAP";
|
||||
|
||||
/**
|
||||
* Performs the following tasks unless the {@link #OUTPUT_FLASH_MAP_ATTRIBUTE}
|
||||
* Perform the following tasks unless the {@link #OUTPUT_FLASH_MAP_ATTRIBUTE}
|
||||
* request attribute exists:
|
||||
* <ol>
|
||||
* <li>Find the "input" FlashMap from a previous request (if any), expose it
|
||||
* under the request attribute {@link #INPUT_FLASH_MAP_ATTRIBUTE}, and
|
||||
* remove it from underlying storage.
|
||||
* <li>Create the "output" FlashMap where the current request can save
|
||||
* flash attributes and expose it under the request attribute
|
||||
* {@link #OUTPUT_FLASH_MAP_ATTRIBUTE}.
|
||||
* <li>Remove expired FlashMap instances.
|
||||
* <li>Find the "input" FlashMap, expose it under the request attribute
|
||||
* {@link #INPUT_FLASH_MAP_ATTRIBUTE}, and remove it from underlying storage.
|
||||
* <li>Create the "output" FlashMap and expose it under the request
|
||||
* attribute {@link #OUTPUT_FLASH_MAP_ATTRIBUTE}.
|
||||
* <li>Clean expired FlashMap instances.
|
||||
* </ol>
|
||||
*
|
||||
* @param request the current request
|
||||
*/
|
||||
void requestStarted(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Save the "output" FlashMap in underlying storage, start its expiration
|
||||
* period, and decode/normalize its target request path.
|
||||
*
|
||||
* <p>The "output" FlashMap is not saved if it is empty or if it was not
|
||||
* created by this FlashMapManager.
|
||||
* Start the expiration period of the "output" FlashMap save it in the
|
||||
* underlying storage.
|
||||
* <p>The "output" FlashMap should not be saved if it is empty or if it was
|
||||
* not created by the current FlashMapManager instance.
|
||||
* @param request the current request
|
||||
*/
|
||||
void requestCompleted(HttpServletRequest request);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
package org.springframework.web.servlet;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by Views that perform a redirect.
|
||||
* Provides additional information about a View such as whether it
|
||||
* performs redirects.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|||
import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap;
|
||||
|
||||
/**
|
||||
* Resolves {@link RedirectAttributesModelMap} method arguments.
|
||||
* Resolves method arguments of type {@link RedirectAttributes}.
|
||||
*
|
||||
* <p>This resolver must be listed ahead of the {@link ModelMethodProcessor},
|
||||
* which also resolves arguments of type {@link Map} and {@link Model}.
|
||||
* <p>This resolver must be listed before the {@link ModelMethodProcessor},
|
||||
* which resolves {@link Map} and {@link Model} arguments.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
|
|
|||
|
|
@ -20,70 +20,66 @@ import java.util.Collection;
|
|||
import java.util.Map;
|
||||
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
|
||||
/**
|
||||
* A {@link Model} that can also store attributes candidate for flash storage.
|
||||
* A specialization of the {@link Model} interface that controllers can use to
|
||||
* select attributes for a redirect scenario. Since the intent of adding
|
||||
* redirect attributes is very explicit -- i.e. to be used for a redirect URL,
|
||||
* attribute values may be formatted as Strings and stored that way to make
|
||||
* them eligible to be appended to the query string or expanded as URI
|
||||
* variables in {@code org.springframework.web.servlet.view.RedirectView}.
|
||||
*
|
||||
* <p>This interface also provides a way to add flash attributes. For a
|
||||
* general overview of flash attributes see {@link FlashMap}. You can use
|
||||
* {@link RedirectAttributes} to store flash attributes and they will be
|
||||
* automatically propagated to the "output" FlashMap of the current request.
|
||||
*
|
||||
* <p>Example usage in an {@code @Controller}:
|
||||
* <pre>
|
||||
* @RequestMapping(value = "/accounts", method = RequestMethod.POST)
|
||||
* public String handle(Account account, BindingResult result, RedirectAttributes redirectAttrs) {
|
||||
* if (result.hasErrors()) {
|
||||
* return "accounts/new";
|
||||
* }
|
||||
* // Save account ...
|
||||
* redirectAttrs.addAttribute("id", account.getId()).addFlashAttribute("message", "Account created!");
|
||||
* return "redirect:/accounts/{id}";
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>After the redirect, flash attributes are automatically added to the model
|
||||
* of the controller serving the redirect URL.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface RedirectAttributes extends Model {
|
||||
|
||||
/**
|
||||
* Add the supplied attribute under the supplied name.
|
||||
* @param attributeName the name of the model attribute (never <code>null</code>)
|
||||
* @param attributeValue the model attribute value (can be <code>null</code>)
|
||||
*/
|
||||
RedirectAttributes addAttribute(String attributeName, Object attributeValue);
|
||||
|
||||
/**
|
||||
* Add the supplied attribute to this <code>Map</code> using a
|
||||
* {@link org.springframework.core.Conventions#getVariableName generated name}.
|
||||
* <p><emphasis>Note: Empty {@link java.util.Collection Collections} are not added to
|
||||
* the model when using this method because we cannot correctly determine
|
||||
* the true convention name. View code should check for <code>null</code> rather
|
||||
* than for empty collections as is already done by JSTL tags.</emphasis>
|
||||
* @param attributeValue the model attribute value (never <code>null</code>)
|
||||
*/
|
||||
RedirectAttributes addAttribute(Object attributeValue);
|
||||
|
||||
/**
|
||||
* Copy all attributes in the supplied <code>Collection</code> into this
|
||||
* <code>Map</code>, using attribute name generation for each element.
|
||||
* @see #addAttribute(Object)
|
||||
*/
|
||||
RedirectAttributes addAllAttributes(Collection<?> attributeValues);
|
||||
|
||||
/**
|
||||
* Copy all attributes in the supplied <code>Map</code> into this <code>Map</code>.
|
||||
* @see #addAttribute(String, Object)
|
||||
*/
|
||||
Model addAllAttributes(Map<String, ?> attributes);
|
||||
|
||||
/**
|
||||
* Copy all attributes in the supplied <code>Map</code> into this <code>Map</code>,
|
||||
* with existing objects of the same name taking precedence (i.e. not getting
|
||||
* replaced).
|
||||
*/
|
||||
RedirectAttributes mergeAttributes(Map<String, ?> attributes);
|
||||
|
||||
/**
|
||||
* Add the given attribute as a candidate for flash storage.
|
||||
* @param attributeName the flash attribute name; never null
|
||||
* @param attributeValue the flash attribute value; may be null
|
||||
* Add the given flash attribute.
|
||||
* @param attributeName the attribute name; never {@code null}
|
||||
* @param attributeValue the attribute value; may be {@code null}
|
||||
*/
|
||||
RedirectAttributes addFlashAttribute(String attributeName, Object attributeValue);
|
||||
|
||||
/**
|
||||
* Add the given attribute value as a candidate for flash storage using a
|
||||
* Add the given flash storage using a
|
||||
* {@link org.springframework.core.Conventions#getVariableName generated name}.
|
||||
* @param attributeValue the flash attribute value; never null
|
||||
* @param attributeValue the flash attribute value; never {@code null}
|
||||
*/
|
||||
RedirectAttributes addFlashAttribute(Object attributeValue);
|
||||
|
||||
/**
|
||||
* Return the attributes candidate for flash storage.
|
||||
* Return the attributes candidate for flash storage or an empty Map.
|
||||
*/
|
||||
Map<String, ?> getFlashAttributes();
|
||||
|
||||
}
|
||||
|
|
@ -23,12 +23,10 @@ import org.springframework.ui.ModelMap;
|
|||
import org.springframework.validation.DataBinder;
|
||||
|
||||
/**
|
||||
* A {@link ModelMap} that implements the {@link RedirectAttributes} interface.
|
||||
*
|
||||
* <p>Attributes are formatted and stored as Strings so they can be used as URI
|
||||
* variables or as query parameters in the redirect URL. Alternatively,
|
||||
* attributes may also be added as flash attributes in order to request storing
|
||||
* them until the next request without affecting the redirect URL.
|
||||
* A {@link ModelMap} implementation of {@link RedirectAttributes} that formats
|
||||
* values as Strings using a {@link DataBinder}. Also provides a place to store
|
||||
* flash attributes so they can survive a redirect without the need to be
|
||||
* embedded in the redirect URL.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
|
@ -41,33 +39,31 @@ public class RedirectAttributesModelMap extends ModelMap implements RedirectAttr
|
|||
private final ModelMap flashAttributes = new ModelMap();
|
||||
|
||||
/**
|
||||
* Default constructor without a DataBinder.
|
||||
* Redirect attribute values will be formatted via {@link #toString()}.
|
||||
*/
|
||||
public RedirectAttributesModelMap() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a DataBinder to use to format redirect attribute values.
|
||||
* @param dataBinder a DataBinder for converting attribute values to String.
|
||||
* Class constructor.
|
||||
* @param dataBinder used to format attribute values as Strings.
|
||||
*/
|
||||
public RedirectAttributesModelMap(DataBinder dataBinder) {
|
||||
this.dataBinder = dataBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attributes candidate for flash storage.
|
||||
* Default constructor without a DataBinder.
|
||||
* Attribute values are converted to String via {@link #toString()}.
|
||||
*/
|
||||
public Map<String, ?> getFlashAttributes() {
|
||||
return flashAttributes;
|
||||
public RedirectAttributesModelMap() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the attribute value as a String and add it. If the value is
|
||||
* {@code null} it is not be added.
|
||||
* @param attributeName the attribute name; never null
|
||||
* @param attributeValue the attribute value; skipped if null
|
||||
* Return the attributes candidate for flash storage or an empty Map.
|
||||
*/
|
||||
public Map<String, ?> getFlashAttributes() {
|
||||
return this.flashAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Formats the attribute value as a String before adding it.
|
||||
*/
|
||||
public RedirectAttributesModelMap addAttribute(String attributeName, Object attributeValue) {
|
||||
if (attributeValue != null) {
|
||||
|
|
@ -81,10 +77,8 @@ public class RedirectAttributesModelMap extends ModelMap implements RedirectAttr
|
|||
}
|
||||
|
||||
/**
|
||||
* Add an attribute using a
|
||||
* {@link org.springframework.core.Conventions#getVariableName generated name}.
|
||||
* Before being added the attribute value is formatted as a String.
|
||||
* @param attributeValue the attribute value; never null
|
||||
* {@inheritDoc}
|
||||
* <p>Formats the attribute value as a String before adding it.
|
||||
*/
|
||||
public RedirectAttributesModelMap addAttribute(Object attributeValue) {
|
||||
super.addAttribute(attributeValue);
|
||||
|
|
@ -92,9 +86,8 @@ public class RedirectAttributesModelMap extends ModelMap implements RedirectAttr
|
|||
}
|
||||
|
||||
/**
|
||||
* Copy all attributes in the supplied <code>Collection</code> into this
|
||||
* Model using attribute name generation for each element.
|
||||
* @see #addAttribute(Object)
|
||||
* {@inheritDoc}
|
||||
* <p>Each attribute value is formatted as a String before being added.
|
||||
*/
|
||||
public RedirectAttributesModelMap addAllAttributes(Collection<?> attributeValues) {
|
||||
super.addAllAttributes(attributeValues);
|
||||
|
|
@ -102,8 +95,8 @@ public class RedirectAttributesModelMap extends ModelMap implements RedirectAttr
|
|||
}
|
||||
|
||||
/**
|
||||
* Copy all supplied attributes into this model.
|
||||
* @see #addAttribute(String, Object)
|
||||
* {@inheritDoc}
|
||||
* <p>Each attribute value is formatted as a String before being added.
|
||||
*/
|
||||
public RedirectAttributesModelMap addAllAttributes(Map<String, ?> attributes) {
|
||||
if (attributes != null) {
|
||||
|
|
@ -115,9 +108,8 @@ public class RedirectAttributesModelMap extends ModelMap implements RedirectAttr
|
|||
}
|
||||
|
||||
/**
|
||||
* Copy all supplied attributes into this model with with existing
|
||||
* attributes of the same name taking precedence (i.e. not getting replaced).
|
||||
* @see #addAttribute(String, Object)
|
||||
* {@inheritDoc}
|
||||
* <p>Each attribute value is formatted as a String before being merged.
|
||||
*/
|
||||
public RedirectAttributesModelMap mergeAttributes(Map<String, ?> attributes) {
|
||||
if (attributes != null) {
|
||||
|
|
@ -134,21 +126,11 @@ public class RedirectAttributesModelMap extends ModelMap implements RedirectAttr
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given attribute as a candidate for flash storage.
|
||||
* @param attributeName the flash attribute name; never null
|
||||
* @param attributeValue the flash attribute value; may be null
|
||||
*/
|
||||
public RedirectAttributes addFlashAttribute(String attributeName, Object attributeValue) {
|
||||
this.flashAttributes.addAttribute(attributeName, attributeValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given attribute value as a candidate for flash storage using a
|
||||
* {@link org.springframework.core.Conventions#getVariableName generated name}.
|
||||
* @param attributeValue the flash attribute value; never null
|
||||
*/
|
||||
public RedirectAttributes addFlashAttribute(Object attributeValue) {
|
||||
this.flashAttributes.addAttribute(attributeValue);
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.springframework.web.servlet.support;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
|
@ -34,7 +33,8 @@ import org.springframework.web.servlet.FlashMapManager;
|
|||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
/**
|
||||
* A {@link FlashMapManager} that stores FlashMap instances in the HTTP session.
|
||||
* A default {@link FlashMapManager} implementation keeps {@link FlashMap}
|
||||
* instances in the HTTP session.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
|
@ -50,8 +50,9 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
private final UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
|
||||
/**
|
||||
* The amount of time in seconds after a FlashMap is saved (after request
|
||||
* completion) before it is considered expired. The default value is 180.
|
||||
* Set the amount of time in seconds after a {@link FlashMap} is saved
|
||||
* (at request completion) and before it expires.
|
||||
* <p>The default value is 180 seconds.
|
||||
*/
|
||||
public void setFlashMapTimeout(int flashTimeout) {
|
||||
this.flashTimeout = flashTimeout;
|
||||
|
|
@ -59,16 +60,16 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This method never causes the HTTP session to be created.
|
||||
* <p>An HTTP session is never created by this method.
|
||||
*/
|
||||
public void requestStarted(HttpServletRequest request) {
|
||||
if (request.getAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, ?> inputFlashMap = lookupFlashMap(request);
|
||||
FlashMap inputFlashMap = lookupFlashMap(request);
|
||||
if (inputFlashMap != null) {
|
||||
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, inputFlashMap);
|
||||
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
|
||||
}
|
||||
|
||||
FlashMap outputFlashMap = new FlashMap(this.hashCode());
|
||||
|
|
@ -78,17 +79,17 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Look up the "input" FlashMap by matching the target request path and
|
||||
* the target request parameters configured in each available FlashMap
|
||||
* to the current request.
|
||||
* Find the "input" FlashMap for the current request target by matching it
|
||||
* to the target request information of all stored FlashMap instances.
|
||||
* @return a FlashMap instance or {@code null}
|
||||
*/
|
||||
private Map<String, ?> lookupFlashMap(HttpServletRequest request) {
|
||||
private FlashMap lookupFlashMap(HttpServletRequest request) {
|
||||
List<FlashMap> allFlashMaps = retrieveFlashMaps(request, false);
|
||||
if (CollectionUtils.isEmpty(allFlashMaps)) {
|
||||
return null;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved flash maps: " + allFlashMaps);
|
||||
logger.debug("Retrieved FlashMap(s): " + allFlashMaps);
|
||||
}
|
||||
List<FlashMap> result = new ArrayList<FlashMap>();
|
||||
for (FlashMap flashMap : allFlashMaps) {
|
||||
|
|
@ -99,19 +100,19 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
if (!result.isEmpty()) {
|
||||
Collections.sort(result);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Matching flash maps: " + result);
|
||||
logger.debug("Found matching FlashMap(s): " + result);
|
||||
}
|
||||
FlashMap match = result.remove(0);
|
||||
allFlashMaps.remove(match);
|
||||
return Collections.unmodifiableMap(match);
|
||||
return match;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the target request path and the target request parameters in the
|
||||
* given FlashMap and returns "true" if they match. If the FlashMap does not
|
||||
* have target request information, it matches any request.
|
||||
* Whether the given FlashMap matches the current request.
|
||||
* The default implementation uses the target request path and query params
|
||||
* saved in the FlashMap.
|
||||
*/
|
||||
protected boolean isFlashMapForRequest(FlashMap flashMap, HttpServletRequest request) {
|
||||
if (flashMap.getTargetRequestPath() != null) {
|
||||
|
|
@ -122,8 +123,8 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
}
|
||||
}
|
||||
if (flashMap.getTargetRequestParams() != null) {
|
||||
for (Map.Entry<String, String> entry : flashMap.getTargetRequestParams().entrySet()) {
|
||||
if (!entry.getValue().equals(request.getParameter(entry.getKey()))) {
|
||||
for (String paramName : flashMap.getTargetRequestParams().keySet()) {
|
||||
if (!flashMap.getTargetRequestParams().get(paramName).equals(request.getParameter(paramName))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -132,10 +133,13 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve all available FlashMap instances from the HTTP session.
|
||||
* Retrieve all FlashMap instances from the current HTTP session.
|
||||
* If {@code allowCreate} is "true" and no flash maps exist yet, a new list
|
||||
* is created and stored as a session attribute.
|
||||
* @param request the current request
|
||||
* @param allowCreate whether to create and save the FlashMap in the session
|
||||
* @return a Map with all FlashMap instances; or {@code null}
|
||||
* @param allowCreate whether to create the session if necessary
|
||||
* @return a List to add FlashMap instances to or {@code null}
|
||||
* assuming {@code allowCreate} is "false".
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request, boolean allowCreate) {
|
||||
|
|
@ -157,7 +161,7 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Iterate available FlashMap instances and remove the ones that have expired.
|
||||
* Iterate all flash maps and remove expired ones.
|
||||
*/
|
||||
private void removeExpiredFlashMaps(HttpServletRequest request) {
|
||||
List<FlashMap> allMaps = retrieveFlashMaps(request, false);
|
||||
|
|
@ -173,40 +177,52 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
|||
expiredMaps.add(flashMap);
|
||||
}
|
||||
}
|
||||
if (!expiredMaps.isEmpty()) {
|
||||
allMaps.removeAll(expiredMaps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>An HTTP session is never created if the "output" FlashMap is empty.
|
||||
*/
|
||||
public void requestCompleted(HttpServletRequest request) {
|
||||
FlashMap flashMap = (FlashMap) request.getAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE);
|
||||
if (flashMap == null) {
|
||||
throw new IllegalStateException(
|
||||
"Did not find a FlashMap exposed as the request attribute " + OUTPUT_FLASH_MAP_ATTRIBUTE);
|
||||
throw new IllegalStateException("requestCompleted called but \"output\" FlashMap was never created");
|
||||
}
|
||||
if (!flashMap.isEmpty() && flashMap.isCreatedBy(this.hashCode())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Saving FlashMap=" + flashMap);
|
||||
}
|
||||
decodeAndNormalizeTargetPath(flashMap, request);
|
||||
flashMap.startExpirationPeriod(this.flashTimeout);
|
||||
onSaveFlashMap(flashMap, request);
|
||||
retrieveFlashMaps(request, true).add(flashMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the target request path in the given FlashMap is decoded and also
|
||||
* normalized (if it is relative) against the current request URL.
|
||||
* Update a FlashMap before it is stored in the HTTP Session.
|
||||
* <p>The default implementation starts the expiration period and ensures the
|
||||
* target request path is decoded and normalized if it is relative.
|
||||
* @param flashMap the flash map to be saved
|
||||
* @param request the current request
|
||||
*/
|
||||
private void decodeAndNormalizeTargetPath(FlashMap flashMap, HttpServletRequest request) {
|
||||
String path = flashMap.getTargetRequestPath();
|
||||
protected void onSaveFlashMap(FlashMap flashMap, HttpServletRequest request) {
|
||||
String targetPath = flashMap.getTargetRequestPath();
|
||||
flashMap.setTargetRequestPath(decodeAndNormalizePath(targetPath, request));
|
||||
flashMap.startExpirationPeriod(this.flashTimeout);
|
||||
}
|
||||
|
||||
private String decodeAndNormalizePath(String path, HttpServletRequest request) {
|
||||
if (path != null) {
|
||||
path = urlPathHelper.decodeRequestString(request, path);
|
||||
path = this.urlPathHelper.decodeRequestString(request, path);
|
||||
if (path.charAt(0) != '/') {
|
||||
String requestUri = this.urlPathHelper.getRequestUri(request);
|
||||
path = requestUri.substring(0, requestUri.lastIndexOf('/') + 1) + path;
|
||||
path = StringUtils.cleanPath(path);
|
||||
}
|
||||
flashMap.setTargetRequestPath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,9 +157,11 @@ public abstract class RequestContextUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return a read-only Map with flash attributes saved during the previous request.
|
||||
* Return a read-only {@link Map} with "input" flash attributes saved on a
|
||||
* previous request.
|
||||
* @param request the current request
|
||||
* @return a read-only Map, or {@code null}
|
||||
* @see FlashMap
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, ?> getInputFlashMap(HttpServletRequest request) {
|
||||
|
|
@ -167,9 +169,10 @@ public abstract class RequestContextUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return a FlashMap to add attributes to during the current request.
|
||||
* @param request current HTTP request
|
||||
* @return the flash map for the current request; never {@code null}.
|
||||
* Return the "output" FlashMap with attributes to save for a subsequent request.
|
||||
* @param request current request
|
||||
* @return a {@link FlashMap} instance, never {@code null}
|
||||
* @see FlashMap
|
||||
*/
|
||||
public static FlashMap getOutputFlashMap(HttpServletRequest request) {
|
||||
return (FlashMap) request.getAttribute(FlashMapManager.OUTPUT_FLASH_MAP_ATTRIBUTE);
|
||||
|
|
|
|||
Loading…
Reference in New Issue