SPR-6464 Add getInputFlashMap and getOutputFlashMap methods to RequestContextUtils
This commit is contained in:
@@ -41,11 +41,11 @@ public class FlashMap extends HashMap<String, Object> implements Comparable<Flas
|
||||
|
||||
private final Map<String, String> expectedRequestParameters = new LinkedHashMap<String, String>();
|
||||
|
||||
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
|
||||
private long expirationStartTime;
|
||||
|
||||
private int timeToLive;
|
||||
|
||||
private final UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
|
||||
/**
|
||||
* Provide a URL to identify the target request for this FlashMap.
|
||||
|
||||
@@ -22,10 +22,12 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
|
||||
/**
|
||||
* A strategy interface for maintaining {@link FlashMap} instances in some
|
||||
* underlying storage until the next request. The most common use case is
|
||||
* a redirect. For example redirecting from a POST that creates a resource
|
||||
* to the page that shows the created resource and passing along a
|
||||
* success message that needs to be shown once only.
|
||||
* underlying storage until the next request.
|
||||
*
|
||||
* <p>The most common use case for using flash storage is a redirect.
|
||||
* For example creating a resource in a POST request and then redirecting
|
||||
* to the page that shows the resource. Flash storage may be used to
|
||||
* pass along a success message.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
@@ -33,48 +35,41 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
* @see FlashMap
|
||||
*/
|
||||
public interface FlashMapManager {
|
||||
|
||||
|
||||
/**
|
||||
* Request attribute to hold the current request FlashMap.
|
||||
* @see RequestContextUtils#getFlashMap
|
||||
* Request attribute holding the read-only Map with flash attributes saved
|
||||
* during the previous request.
|
||||
* @see RequestContextUtils#getInputFlashMap(HttpServletRequest)
|
||||
*/
|
||||
public static final String CURRENT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".CURRENT_FLASH_MAP";
|
||||
|
||||
public static final String INPUT_FLASH_MAP_ATTRIBUTE = FlashMapManager.class.getName() + ".INPUT_FLASH_MAP";
|
||||
|
||||
/**
|
||||
* Request attribute to hold the FlashMap from the previous request.
|
||||
* Access to the previous FlashMap should generally not be needed
|
||||
* since its content is exposed as attributes of the current
|
||||
* request. However, it may be useful to expose previous request
|
||||
* flash attributes in other ways such as in the model of annotated
|
||||
* controllers.
|
||||
* Request attribute holding the {@link FlashMap} to add attributes to during
|
||||
* the current request.
|
||||
* @see RequestContextUtils#getOutputFlashMap(HttpServletRequest)
|
||||
*/
|
||||
public static final String PREVIOUS_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".PREVIOUS_FLASH_MAP";
|
||||
public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = FlashMapManager.class.getName() + ".OUTPUT_FLASH_MAP";
|
||||
|
||||
/**
|
||||
* Perform flash storage tasks at the start of a new request:
|
||||
* <ul>
|
||||
* <li>Create a new FlashMap and make it available to the current request
|
||||
* under the request attribute {@link #CURRENT_FLASH_MAP_ATTRIBUTE}.
|
||||
* <li>Locate the FlashMap saved on the previous request and expose its
|
||||
* contents as attributes in the current request, also exposing the
|
||||
* previous FlashMap under {@link #PREVIOUS_FLASH_MAP_ATTRIBUTE}.
|
||||
* <li>Check for and remove expired FlashMap instances.
|
||||
* <li>Create a FlashMap and make it available under the request attribute
|
||||
* {@link #OUTPUT_FLASH_MAP_ATTRIBUTE}.
|
||||
* <li>Locate the FlashMap saved during the previous request and make it
|
||||
* available under the request attribute {@link #INPUT_FLASH_MAP_ATTRIBUTE}.
|
||||
* <li>Remove expired FlashMap instances.
|
||||
* </ul>
|
||||
*
|
||||
* <p>If the {@link #CURRENT_FLASH_MAP_ATTRIBUTE} request attribute exists
|
||||
* in the current request, this method should return "false" immediately.
|
||||
* <p>If the {@link #OUTPUT_FLASH_MAP_ATTRIBUTE} request attribute exists
|
||||
* return "false" immediately.
|
||||
*
|
||||
* @param request the current request
|
||||
*
|
||||
* @return "true" if flash storage tasks were performed; "false" otherwise.
|
||||
*/
|
||||
boolean requestStarted(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Access the current FlashMap through the request attribute
|
||||
* {@link #CURRENT_FLASH_MAP_ATTRIBUTE} and if it is not empty, save it
|
||||
* in the underlying storage.
|
||||
*
|
||||
* Access the FlashMap with attributes added during the current request and
|
||||
* if it is not empty, save it in the underlying storage.
|
||||
* <p>If the call to {@link #requestStarted} returned "false", this
|
||||
* method is not invoked.
|
||||
*/
|
||||
|
||||
@@ -516,10 +516,8 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
|
||||
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod);
|
||||
ModelFactory modelFactory = getModelFactory(handlerMethod);
|
||||
|
||||
FlashMap previousFlashMap = (FlashMap) request.getAttribute(FlashMapManager.PREVIOUS_FLASH_MAP_ATTRIBUTE);
|
||||
|
||||
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
|
||||
mavContainer.addAllAttributes(previousFlashMap);
|
||||
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
|
||||
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
|
||||
|
||||
SessionStatus sessionStatus = new SimpleSessionStatus();
|
||||
@@ -539,8 +537,8 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
|
||||
}
|
||||
if (model instanceof RedirectModel) {
|
||||
RedirectModel redirectModel = (RedirectModel) model;
|
||||
FlashMap currentFlashMap = RequestContextUtils.getFlashMap(request);
|
||||
currentFlashMap.putAll(redirectModel.getFlashAttributes());
|
||||
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
|
||||
flashMap.putAll(redirectModel.getFlashAttributes());
|
||||
}
|
||||
return mav;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ 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;
|
||||
@@ -29,7 +30,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.servlet.FlashMapManager;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* A {@link FlashMapManager} that saves and retrieves FlashMap instances in the
|
||||
@@ -58,48 +58,34 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>This method never creates an HTTP session. The current FlashMap is
|
||||
* exposed as a request attribute only and is not saved in the session
|
||||
* until {@link #requestCompleted}.
|
||||
* <p>This method never creates an HTTP session. The new FlashMap created
|
||||
* for the current request is exposed as a request attribute only and is
|
||||
* not saved in the session until {@link #requestCompleted} is called.
|
||||
*/
|
||||
public boolean requestStarted(HttpServletRequest request) {
|
||||
if (request.getAttribute(CURRENT_FLASH_MAP_ATTRIBUTE) != null) {
|
||||
if (request.getAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE) != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FlashMap currentFlashMap = new FlashMap();
|
||||
request.setAttribute(CURRENT_FLASH_MAP_ATTRIBUTE, currentFlashMap);
|
||||
FlashMap outputFlashMap = new FlashMap();
|
||||
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, outputFlashMap);
|
||||
|
||||
FlashMap previousFlashMap = lookupPreviousFlashMap(request);
|
||||
if (previousFlashMap != null) {
|
||||
WebUtils.exposeRequestAttributes(request, previousFlashMap);
|
||||
request.setAttribute(PREVIOUS_FLASH_MAP_ATTRIBUTE, previousFlashMap);
|
||||
Map<String, ?> inputFlashMap = getFlashMap(request);
|
||||
if (inputFlashMap != null) {
|
||||
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, inputFlashMap);
|
||||
}
|
||||
|
||||
// Remove expired flash maps
|
||||
List<FlashMap> allMaps = retrieveFlashMaps(request, false);
|
||||
if (allMaps != null && !allMaps.isEmpty()) {
|
||||
List<FlashMap> expiredMaps = new ArrayList<FlashMap>();
|
||||
for (FlashMap flashMap : allMaps) {
|
||||
if (flashMap.isExpired()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Removing expired FlashMap: " + flashMap);
|
||||
}
|
||||
expiredMaps.add(flashMap);
|
||||
}
|
||||
}
|
||||
allMaps.removeAll(expiredMaps);
|
||||
}
|
||||
removeExpiredFlashMaps(request);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FlashMap from the previous request.
|
||||
* Return the flash attributes saved during the previous request if any.
|
||||
*
|
||||
* @return the FlashMap from the previous request; or {@code null} if none.
|
||||
* @return a read-only Map; or {@code null} if not found.
|
||||
*/
|
||||
private FlashMap lookupPreviousFlashMap(HttpServletRequest request) {
|
||||
private Map<String, ?> getFlashMap(HttpServletRequest request) {
|
||||
List<FlashMap> allMaps = retrieveFlashMaps(request, false);
|
||||
if (CollectionUtils.isEmpty(allMaps)) {
|
||||
return null;
|
||||
@@ -123,7 +109,7 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
||||
Collections.sort(matches);
|
||||
FlashMap match = matches.remove(0);
|
||||
allMaps.remove(match);
|
||||
return match;
|
||||
return Collections.unmodifiableMap(match);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -156,16 +142,32 @@ public class DefaultFlashMapManager implements FlashMapManager {
|
||||
return allMaps;
|
||||
}
|
||||
|
||||
private void removeExpiredFlashMaps(HttpServletRequest request) {
|
||||
List<FlashMap> allMaps = retrieveFlashMaps(request, false);
|
||||
if (allMaps != null && !allMaps.isEmpty()) {
|
||||
List<FlashMap> expiredMaps = new ArrayList<FlashMap>();
|
||||
for (FlashMap flashMap : allMaps) {
|
||||
if (flashMap.isExpired()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Removing expired FlashMap: " + flashMap);
|
||||
}
|
||||
expiredMaps.add(flashMap);
|
||||
}
|
||||
}
|
||||
allMaps.removeAll(expiredMaps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The HTTP session is not created if the current FlashMap instance is empty.
|
||||
*/
|
||||
public void requestCompleted(HttpServletRequest request) {
|
||||
FlashMap flashMap = (FlashMap) request.getAttribute(CURRENT_FLASH_MAP_ATTRIBUTE);
|
||||
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 " + CURRENT_FLASH_MAP_ATTRIBUTE);
|
||||
"Did not find a FlashMap exposed as the request attribute " + OUTPUT_FLASH_MAP_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (!flashMap.isEmpty()) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.web.servlet.support;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
@@ -27,8 +28,8 @@ import org.springframework.ui.context.ThemeSource;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.FlashMapManager;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.servlet.FlashMapManager;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.ThemeResolver;
|
||||
|
||||
@@ -156,12 +157,22 @@ public abstract class RequestContextUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the flash map to use for the current request.
|
||||
* Return a read-only Map with flash attributes saved during the previous request.
|
||||
* @param request the current request
|
||||
* @return a read-only Map, or {@code null}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, ?> getInputFlashMap(HttpServletRequest request) {
|
||||
return (Map<String, ?>) request.getAttribute(FlashMapManager.INPUT_FLASH_MAP_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
public static FlashMap getFlashMap(HttpServletRequest request) {
|
||||
return (FlashMap) request.getAttribute(FlashMapManager.CURRENT_FLASH_MAP_ATTRIBUTE);
|
||||
public static FlashMap getOutputFlashMap(HttpServletRequest request) {
|
||||
return (FlashMap) request.getAttribute(FlashMapManager.OUTPUT_FLASH_MAP_ATTRIBUTE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ public class RedirectView extends AbstractUrlBasedView {
|
||||
model = removeKeys(model, uriTemplate.getVariableNames());
|
||||
}
|
||||
|
||||
FlashMap flashMap = RequestContextUtils.getFlashMap(request);
|
||||
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
|
||||
if (!CollectionUtils.isEmpty(flashMap)) {
|
||||
flashMap.setExpectedRequestUri(request, targetUrl.toString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user