28 changed files with 1151 additions and 704 deletions
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.servlet; |
||||
|
||||
import org.springframework.ui.ModelMap; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Stores attributes that need to be made available in the next request. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
*/ |
||||
public class FlashMap extends ModelMap { |
||||
|
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
private final String key; |
||||
|
||||
private final String keyParameterName; |
||||
|
||||
private long expirationStartTime; |
||||
|
||||
private int timeToLive; |
||||
|
||||
/** |
||||
* Create a FlashMap with a unique key. |
||||
*/ |
||||
public FlashMap(String key, String keyParameterName) { |
||||
Assert.notNull("The key is required", key); |
||||
Assert.notNull("The key parameter name is required", keyParameterName); |
||||
this.key = key; |
||||
this.keyParameterName = keyParameterName; |
||||
} |
||||
|
||||
/** |
||||
* Create a FlashMap without a key. |
||||
*/ |
||||
public FlashMap() { |
||||
this.key = null; |
||||
this.keyParameterName = null; |
||||
} |
||||
|
||||
/** |
||||
* Return the key assigned to this FlashMap instance; |
||||
* or {@code null} if a unique key has not been assigned. |
||||
*/ |
||||
public String getKey() { |
||||
return this.key; |
||||
} |
||||
|
||||
/** |
||||
* Return the name of the request parameter to use when appending the flash |
||||
* key to a redirect URL. |
||||
*/ |
||||
public String getKeyParameterName() { |
||||
return keyParameterName; |
||||
} |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
public void startExpirationPeriod(int timeToLive) { |
||||
this.expirationStartTime = System.currentTimeMillis(); |
||||
this.timeToLive = timeToLive; |
||||
} |
||||
|
||||
/** |
||||
* Whether the flash map has expired depending on the number of seconds |
||||
* elapsed since the call to {@link #startExpirationPeriod}. |
||||
*/ |
||||
public boolean isExpired() { |
||||
if (this.expirationStartTime != 0) { |
||||
return (System.currentTimeMillis() - this.expirationStartTime) > this.timeToLive * 1000; |
||||
} |
||||
else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.servlet; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
|
||||
import org.springframework.web.servlet.support.RequestContextUtils; |
||||
|
||||
/** |
||||
* A strategy interface for maintaining {@link FlashMap} instances in some |
||||
* underlying storage between two requests. This is typically used when |
||||
* redirecting from one URL to another. |
||||
* |
||||
* TODO ... |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
* |
||||
* @see FlashMap |
||||
*/ |
||||
public interface FlashMapManager { |
||||
|
||||
/** |
||||
* Request attribute to hold the current request FlashMap. |
||||
* @see RequestContextUtils#getFlashMap |
||||
*/ |
||||
public static final String CURRENT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".CURRENT_FLASH_MAP"; |
||||
|
||||
/** |
||||
* Request attribute to hold the FlashMap from the previous request. |
||||
*/ |
||||
public static final String PREVIOUS_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".PREVIOUS_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. |
||||
* <li>Remove expired flash map instances. |
||||
* </ul> |
||||
* |
||||
* @param request the current request |
||||
* |
||||
* @return "true" if flash storage tasks were performed; "false" otherwise |
||||
* if the {@link #CURRENT_FLASH_MAP_ATTRIBUTE} request attribute exists. |
||||
*/ |
||||
boolean requestStarted(HttpServletRequest request); |
||||
|
||||
/** |
||||
* Access the current FlashMap through the {@link #CURRENT_FLASH_MAP_ATTRIBUTE} |
||||
* request attribute and if not empty, save it in the underlying storage. This |
||||
* method should be invoked after {@link #requestStarted} and if it returned "true". |
||||
*/ |
||||
void requestCompleted(HttpServletRequest request); |
||||
|
||||
} |
||||
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.servlet.mvc.method.support; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
|
||||
import org.springframework.web.context.request.NativeWebRequest; |
||||
import org.springframework.web.method.support.ModelAndViewContainer; |
||||
import org.springframework.web.servlet.FlashMap; |
||||
import org.springframework.web.servlet.support.RequestContextUtils; |
||||
|
||||
/** |
||||
* Provides annotated controller methods with convenience methods for setting |
||||
* up response with a view name that will result in a redirect. |
||||
* |
||||
* <p>An instance of this class is obtained via {@link ResponseContext#redirect}. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Rossen Stoyanchev |
||||
* |
||||
* @since 3.1 |
||||
*/ |
||||
public class RedirectResponse { |
||||
|
||||
private final NativeWebRequest webRequest; |
||||
|
||||
private final ModelAndViewContainer mavContainer; |
||||
|
||||
RedirectResponse(NativeWebRequest webRequest, ModelAndViewContainer mavContainer) { |
||||
this.webRequest = webRequest; |
||||
this.mavContainer = mavContainer; |
||||
} |
||||
|
||||
/** |
||||
* Add a URI template variable to use to expand the URI template into a URL. |
||||
* <p><strong>Note:</strong> URI template variables from the current |
||||
* request are automatically used when expanding the redirect URI template. |
||||
* They don't need to be added explicitly here. |
||||
*/ |
||||
public RedirectResponse uriVariable(String name, Object value) { |
||||
this.mavContainer.addAttribute(name, value); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add a URI template variable to use to expand the URI template into a URL. |
||||
* The name of the variable is selected using a |
||||
* {@link org.springframework.core.Conventions#getVariableName generated name}. |
||||
* <p><strong>Note:</strong> URI template variables from the current |
||||
* request are automatically used when expanding the redirect URI template. |
||||
* They don't need to be added explicitly here. |
||||
*/ |
||||
public RedirectResponse uriVariable(Object value) { |
||||
this.mavContainer.addAttribute(value); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add a query parameter to append to the redirect URL. |
||||
*/ |
||||
public RedirectResponse queryParam(String name, Object value) { |
||||
this.mavContainer.addAttribute(name, value); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add a query parameter to append to the redirect URL. |
||||
* The name of the parameter is selected using a |
||||
* {@link org.springframework.core.Conventions#getVariableName generated name}. |
||||
*/ |
||||
public RedirectResponse queryParam(Object value) { |
||||
this.mavContainer.addAttribute(value); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add a flash attribute to save and make available in the model of the |
||||
* target controller method after the redirect. |
||||
*/ |
||||
public RedirectResponse flashAttribute(String name, Object value) { |
||||
getFlashMap().addAttribute(name, value); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add a flash attribute to save and make available in the model of the |
||||
* target controller method after the redirect. |
||||
* The name of the attribute is selected using a |
||||
* {@link org.springframework.core.Conventions#getVariableName generated name}. |
||||
*/ |
||||
public RedirectResponse flashAttribute(Object value) { |
||||
getFlashMap().addAttribute(value); |
||||
return this; |
||||
} |
||||
|
||||
private FlashMap getFlashMap() { |
||||
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); |
||||
return RequestContextUtils.getFlashMap(servletRequest); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,68 @@
@@ -0,0 +1,68 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.servlet.mvc.method.support; |
||||
|
||||
import org.springframework.web.context.request.NativeWebRequest; |
||||
import org.springframework.web.method.support.ModelAndViewContainer; |
||||
|
||||
/** |
||||
* Provides annotated controllers with convenience methods for setting up view |
||||
* resolution. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Rossen Stoyanchev |
||||
* |
||||
* @since 3.1 |
||||
*/ |
||||
public class ResponseContext { |
||||
|
||||
private final NativeWebRequest webRequest; |
||||
|
||||
private final ModelAndViewContainer mavContainer; |
||||
|
||||
public ResponseContext(NativeWebRequest webRequest, ModelAndViewContainer mavContainer) { |
||||
this.webRequest = webRequest; |
||||
this.mavContainer = mavContainer; |
||||
} |
||||
|
||||
/** |
||||
* Set up view resolution based on the given view name and the implicit model |
||||
* of the current request. |
||||
*/ |
||||
public ViewResponse view(String viewName) { |
||||
this.mavContainer.setViewName(viewName); |
||||
return new ViewResponse(this.mavContainer); |
||||
} |
||||
|
||||
/** |
||||
* Set up view resolution for a redirect. This method clears the implicit |
||||
* model. Use convenience methods on the returned {@link RedirectResponse} |
||||
* instance to add URI variables, query parameters, and flash attributes |
||||
* as necessary. |
||||
* @param redirectUri a URI template either relative to the current URL or |
||||
* absolute; do not prefix with "redirect:" |
||||
*/ |
||||
public RedirectResponse redirect(String redirectUri) { |
||||
if (!redirectUri.startsWith("redirect:")) { |
||||
redirectUri = "redirect:" + redirectUri; |
||||
} |
||||
this.mavContainer.getModel().clear(); |
||||
this.mavContainer.setViewName(redirectUri); |
||||
return new RedirectResponse(this.webRequest, this.mavContainer); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.servlet.mvc.method.support; |
||||
|
||||
import org.springframework.web.method.support.ModelAndViewContainer; |
||||
|
||||
/** |
||||
* Provides annotated controller methods with convenience methods for setting |
||||
* up a response with a view name that does not have the "redirect:" prefix . |
||||
* |
||||
* <p>An instance of this class is obtained via {@link ResponseContext#view}. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Rossen Stoyanchev |
||||
* |
||||
* @since 3.1 |
||||
*/ |
||||
public class ViewResponse { |
||||
|
||||
private final ModelAndViewContainer mavContainer; |
||||
|
||||
ViewResponse(ModelAndViewContainer mavContainer) { |
||||
this.mavContainer = mavContainer; |
||||
} |
||||
|
||||
public ViewResponse attribute(String attributeName, Object attributeValue) { |
||||
this.mavContainer.addAttribute(attributeName, attributeValue); |
||||
return this; |
||||
} |
||||
|
||||
public ViewResponse attribute(Object attributeValue) { |
||||
this.mavContainer.addAttribute(attributeValue); |
||||
return this; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,200 @@
@@ -0,0 +1,200 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.servlet.support; |
||||
|
||||
import java.util.Iterator; |
||||
import java.util.Map; |
||||
import java.util.Random; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpSession; |
||||
|
||||
import org.springframework.web.servlet.FlashMap; |
||||
import org.springframework.web.servlet.FlashMapManager; |
||||
|
||||
/** |
||||
* A default implementation that saves and retrieves FlashMap instances to and |
||||
* from the HTTP session. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
*/ |
||||
public class DefaultFlashMapManager implements FlashMapManager { |
||||
|
||||
static final String FLASH_MAPS_SESSION_ATTRIBUTE = DefaultFlashMapManager.class + ".FLASH_MAPS"; |
||||
|
||||
private boolean useUniqueFlashKey = true; |
||||
|
||||
private String flashKeyParameterName = "_flashKey"; |
||||
|
||||
private int flashTimeout = 180; |
||||
|
||||
private static final Random random = new Random(); |
||||
|
||||
/** |
||||
* Whether each FlashMap instance should be stored with a unique key. |
||||
* The unique key needs to be passed as a parameter in the redirect URL |
||||
* and then used to look up the FlashMap instance avoiding potential |
||||
* issues with concurrent requests. |
||||
* <p>The default setting is "true". |
||||
* <p>When set to "false" only one FlashMap is maintained making it |
||||
* possible for a second concurrent request (e.g. via Ajax) to "consume" |
||||
* the FlashMap inadvertently. |
||||
*/ |
||||
public void setUseUniqueFlashKey(boolean useUniqueFlashKey) { |
||||
this.useUniqueFlashKey = useUniqueFlashKey; |
||||
} |
||||
|
||||
/** |
||||
* Customize the name of the request parameter to be appended to the |
||||
* redirect URL when using a unique flash key. |
||||
* <p>The default value is "_flashKey". |
||||
*/ |
||||
public void setFlashKeyParameterName(String parameterName) { |
||||
this.flashKeyParameterName = parameterName; |
||||
} |
||||
|
||||
/** |
||||
* The amount of time in seconds after a request has completed processing |
||||
* and before a FlashMap is considered expired. |
||||
* The default value is 180. |
||||
*/ |
||||
public void setFlashMapTimeout(int flashTimeout) { |
||||
this.flashTimeout = flashTimeout; |
||||
} |
||||
|
||||
/** |
||||
* {@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}. |
||||
*/ |
||||
public boolean requestStarted(HttpServletRequest request) { |
||||
if (request.getAttribute(CURRENT_FLASH_MAP_ATTRIBUTE) != null) { |
||||
return false; |
||||
} |
||||
|
||||
FlashMap currentFlashMap = |
||||
this.useUniqueFlashKey ? |
||||
new FlashMap(createFlashKey(request), this.flashKeyParameterName) : new FlashMap(); |
||||
request.setAttribute(CURRENT_FLASH_MAP_ATTRIBUTE, currentFlashMap); |
||||
|
||||
FlashMap previousFlashMap = lookupPreviousFlashMap(request); |
||||
if (previousFlashMap != null) { |
||||
for (String name : previousFlashMap.keySet()) { |
||||
if (request.getAttribute(name) == null) { |
||||
request.setAttribute(name, previousFlashMap.get(name)); |
||||
} |
||||
} |
||||
// For exposing flash attributes in other places (e.g. annotated controllers)
|
||||
request.setAttribute(PREVIOUS_FLASH_MAP_ATTRIBUTE, previousFlashMap); |
||||
} |
||||
|
||||
// Check and remove expired instances
|
||||
Map<String, FlashMap> allFlashMaps = retrieveAllFlashMaps(request, false); |
||||
if (allFlashMaps != null && !allFlashMaps.isEmpty()) { |
||||
Iterator<FlashMap> iterator = allFlashMaps.values().iterator(); |
||||
while (iterator.hasNext()) { |
||||
if (iterator.next().isExpired()) { |
||||
iterator.remove(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Create a unique flash key. The default implementation uses {@link Random}. |
||||
* @return the unique key; never {@code null}. |
||||
*/ |
||||
protected String createFlashKey(HttpServletRequest request) { |
||||
return String.valueOf(random.nextInt()); |
||||
} |
||||
|
||||
/** |
||||
* Return the FlashMap from the previous request, if available. |
||||
* If {@link #useUniqueFlashKey} is "true", a flash key parameter is |
||||
* expected to be in the request. Otherwise there can be only one |
||||
* FlashMap instance to return. |
||||
* |
||||
* @return the FlashMap from the previous request; or {@code null} if none. |
||||
*/ |
||||
private FlashMap lookupPreviousFlashMap(HttpServletRequest request) { |
||||
Map<String, FlashMap> flashMaps = retrieveAllFlashMaps(request, false); |
||||
if (flashMaps != null && !flashMaps.isEmpty()) { |
||||
if (this.useUniqueFlashKey) { |
||||
String key = request.getParameter(this.flashKeyParameterName); |
||||
if (key != null) { |
||||
return flashMaps.remove(key); |
||||
} |
||||
} |
||||
else { |
||||
String key = flashMaps.keySet().iterator().next(); |
||||
return flashMaps.remove(key); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Retrieve all FlashMap instances from the HTTP session in a thread-safe way. |
||||
* @param request the current request |
||||
* @param allowCreate whether to create and the FlashMap container if not found |
||||
* @return a Map with all stored FlashMap instances; or {@code null} |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
private Map<String, FlashMap> retrieveAllFlashMaps(HttpServletRequest request, boolean allowCreate) { |
||||
HttpSession session = request.getSession(allowCreate); |
||||
if (session == null) { |
||||
return null; |
||||
} |
||||
Map<String, FlashMap> result = (Map<String, FlashMap>) session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE); |
||||
if (result == null && allowCreate) { |
||||
synchronized (DefaultFlashMapManager.class) { |
||||
result = (Map<String, FlashMap>) session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE); |
||||
if (result == null) { |
||||
result = new ConcurrentHashMap<String, FlashMap>(5); |
||||
session.setAttribute(FLASH_MAPS_SESSION_ATTRIBUTE, result); |
||||
} |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* {@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); |
||||
if (flashMap == null) { |
||||
throw new IllegalStateException( |
||||
"Did not find current FlashMap exposed as request attribute " + CURRENT_FLASH_MAP_ATTRIBUTE); |
||||
} |
||||
if (!flashMap.isEmpty()) { |
||||
Map<String, FlashMap> allFlashMaps = retrieveAllFlashMaps(request, true); |
||||
flashMap.startExpirationPeriod(this.flashTimeout); |
||||
String key = this.useUniqueFlashKey ? flashMap.getKey() : "flashMap"; |
||||
allFlashMaps.put(key, flashMap); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,215 +0,0 @@
@@ -1,215 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.servlet.mvc.method.annotation; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertNull; |
||||
|
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
|
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.context.ApplicationContextInitializer; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.mock.web.MockHttpServletResponse; |
||||
import org.springframework.stereotype.Controller; |
||||
import org.springframework.ui.Model; |
||||
import org.springframework.web.bind.annotation.FlashAttributes; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RequestMethod; |
||||
import org.springframework.web.bind.support.FlashStatus; |
||||
import org.springframework.web.context.WebApplicationContext; |
||||
import org.springframework.web.context.support.GenericWebApplicationContext; |
||||
import org.springframework.web.method.annotation.FlashAttributesHandler; |
||||
import org.springframework.web.servlet.View; |
||||
import org.springframework.web.servlet.ViewResolver; |
||||
|
||||
/** |
||||
* Test controllers with @{@link FlashAttributes} through the DispatcherServlet. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
*/ |
||||
public class FlashAttributesServletTests extends AbstractServletHandlerMethodTests { |
||||
|
||||
private static final String MESSAGE_KEY = "message"; |
||||
|
||||
@Test |
||||
public void successMessage() throws Exception { |
||||
|
||||
initServletWithModelExposingViewResolver(MessageController.class); |
||||
|
||||
MockHttpServletRequest req = new MockHttpServletRequest("GET", "/message"); |
||||
MockHttpServletResponse res = new MockHttpServletResponse(); |
||||
getServlet().service(req, res); |
||||
|
||||
assertEquals(200, res.getStatus()); |
||||
assertNull(getModelAttribute(req, MESSAGE_KEY)); |
||||
assertNull(getFlashAttribute(req, MESSAGE_KEY)); |
||||
|
||||
req.setMethod("POST"); |
||||
getServlet().service(req, res); |
||||
|
||||
assertEquals(200, res.getStatus()); |
||||
assertEquals("Yay!", ((Message) getModelAttribute(req, MESSAGE_KEY)).getText()); |
||||
assertEquals("Yay!", ((Message) getFlashAttribute(req, MESSAGE_KEY)).getText()); |
||||
|
||||
req.setMethod("GET"); |
||||
getServlet().service(req, res); |
||||
|
||||
assertEquals(200, res.getStatus()); |
||||
assertEquals("Yay!", ((Message) getModelAttribute(req, MESSAGE_KEY)).getText()); |
||||
assertNull(getFlashAttribute(req, MESSAGE_KEY)); |
||||
} |
||||
|
||||
@Test |
||||
public void successMessageAcrossControllers() throws Exception { |
||||
|
||||
initServletWithModelExposingViewResolver(MessageController.class, SecondMessageController.class); |
||||
|
||||
MockHttpServletRequest req = new MockHttpServletRequest("POST", "/message"); |
||||
MockHttpServletResponse res = new MockHttpServletResponse(); |
||||
getServlet().service(req, res); |
||||
|
||||
req.setParameter("another", "true"); |
||||
getServlet().service(req, res); |
||||
|
||||
assertEquals(200, res.getStatus()); |
||||
assertEquals("Nay!", ((Message) getModelAttribute(req, MESSAGE_KEY)).getText()); |
||||
assertEquals("Nay!", ((Message) getFlashAttribute(req, MESSAGE_KEY)).getText()); |
||||
|
||||
req.setMethod("GET"); |
||||
req.setRequestURI("/second/message"); |
||||
getServlet().service(req, res); |
||||
|
||||
assertEquals(200, res.getStatus()); |
||||
assertEquals("Nay!", ((Message) getModelAttribute(req, MESSAGE_KEY)).getText()); |
||||
assertNull(getFlashAttribute(req, MESSAGE_KEY)); |
||||
} |
||||
|
||||
@Controller |
||||
@FlashAttributes("message") |
||||
static class MessageController { |
||||
|
||||
@RequestMapping(value="/message", method=RequestMethod.GET) |
||||
public void message(Model model) { |
||||
} |
||||
|
||||
@RequestMapping(value="/message", method=RequestMethod.POST) |
||||
public String sendMessage(Model model, FlashStatus status) { |
||||
status.setActive(); |
||||
model.addAttribute(Message.success("Yay!")); |
||||
return "redirect:/message"; |
||||
} |
||||
|
||||
@RequestMapping(value="/message", method=RequestMethod.POST, params="another") |
||||
public String sendMessageToSecondController(Model model, FlashStatus status) { |
||||
status.setActive(); |
||||
model.addAttribute(Message.error("Nay!")); |
||||
return "redirect:/second/message"; |
||||
} |
||||
} |
||||
|
||||
@Controller |
||||
static class SecondMessageController { |
||||
|
||||
@RequestMapping(value="/second/message", method=RequestMethod.GET) |
||||
public void message(Model model) { |
||||
} |
||||
} |
||||
|
||||
private static class Message { |
||||
|
||||
private final MessageType type; |
||||
|
||||
private final String text; |
||||
|
||||
private Message(MessageType type, String text) { |
||||
this.type = type; |
||||
this.text = text; |
||||
} |
||||
|
||||
public static Message success(String text) { |
||||
return new Message(MessageType.success, text); |
||||
} |
||||
|
||||
public static Message error(String text) { |
||||
return new Message(MessageType.error, text); |
||||
} |
||||
|
||||
public MessageType getType() { |
||||
return type; |
||||
} |
||||
|
||||
public String getText() { |
||||
return text; |
||||
} |
||||
|
||||
public String toString() { |
||||
return type + ": " + text; |
||||
} |
||||
|
||||
} |
||||
|
||||
private static enum MessageType { |
||||
info, success, warning, error |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private Object getModelAttribute(MockHttpServletRequest req, String key) { |
||||
Map<String, ?> model = (Map<String, ?>) req.getAttribute(ModelExposingViewResolver.REQUEST_ATTRIBITE_MODEL); |
||||
return model.get(key); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private Object getFlashAttribute(MockHttpServletRequest req, String key) { |
||||
String flashAttributesKey = FlashAttributesHandler.FLASH_ATTRIBUTES_SESSION_KEY; |
||||
Map<String, Object> attrs = (Map<String, Object>) req.getSession().getAttribute(flashAttributesKey); |
||||
return (attrs != null) ? attrs.get(key) : null; |
||||
} |
||||
|
||||
private WebApplicationContext initServletWithModelExposingViewResolver(Class<?>... controllerClasses) |
||||
throws ServletException { |
||||
|
||||
return initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { |
||||
public void initialize(GenericWebApplicationContext wac) { |
||||
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); |
||||
} |
||||
}, controllerClasses); |
||||
} |
||||
|
||||
static class ModelExposingViewResolver implements ViewResolver { |
||||
|
||||
static String REQUEST_ATTRIBITE_MODEL = "ModelExposingViewResolver.model"; |
||||
|
||||
public View resolveViewName(final String viewName, Locale locale) throws Exception { |
||||
return new View() { |
||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { |
||||
request.setAttribute(REQUEST_ATTRIBITE_MODEL, model); |
||||
} |
||||
public String getContentType() { |
||||
return null; |
||||
} |
||||
}; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,174 @@
@@ -0,0 +1,174 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.servlet.support; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
import static org.junit.Assert.assertNotNull; |
||||
import static org.junit.Assert.assertNull; |
||||
import static org.junit.Assert.assertSame; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.web.servlet.FlashMap; |
||||
import org.springframework.web.servlet.FlashMapManager; |
||||
|
||||
/** |
||||
* Test fixture for {@link DefaultFlashMapManager} tests. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
*/ |
||||
public class DefaultFlashMapManagerTests { |
||||
|
||||
private DefaultFlashMapManager flashMapManager; |
||||
|
||||
private MockHttpServletRequest request; |
||||
|
||||
@Before |
||||
public void setup() { |
||||
this.flashMapManager = new DefaultFlashMapManager(); |
||||
this.request = new MockHttpServletRequest(); |
||||
} |
||||
|
||||
@Test |
||||
public void requestAlreadyStarted() { |
||||
request.setAttribute(FlashMapManager.CURRENT_FLASH_MAP_ATTRIBUTE, new FlashMap()); |
||||
boolean actual = this.flashMapManager.requestStarted(this.request); |
||||
|
||||
assertFalse(actual); |
||||
} |
||||
|
||||
@Test |
||||
public void createFlashMap() { |
||||
boolean actual = this.flashMapManager.requestStarted(this.request); |
||||
FlashMap flashMap = RequestContextUtils.getFlashMap(this.request); |
||||
|
||||
assertTrue(actual); |
||||
assertNotNull(flashMap); |
||||
assertNotNull(flashMap.getKey()); |
||||
assertEquals("_flashKey", flashMap.getKeyParameterName()); |
||||
} |
||||
|
||||
@Test |
||||
public void createFlashMapWithoutKey() { |
||||
this.flashMapManager.setUseUniqueFlashKey(false); |
||||
boolean actual = this.flashMapManager.requestStarted(this.request); |
||||
FlashMap flashMap = RequestContextUtils.getFlashMap(this.request); |
||||
|
||||
assertTrue(actual); |
||||
assertNotNull(flashMap); |
||||
assertNull(flashMap.getKey()); |
||||
assertNull(flashMap.getKeyParameterName()); |
||||
} |
||||
|
||||
@Test |
||||
public void lookupPreviousFlashMap() { |
||||
FlashMap flashMap = new FlashMap("key", "_flashKey"); |
||||
flashMap.put("name", "value"); |
||||
Map<String, FlashMap> allFlashMaps = new HashMap<String, FlashMap>(); |
||||
allFlashMaps.put(flashMap.getKey(), flashMap); |
||||
|
||||
this.request.getSession().setAttribute(DefaultFlashMapManager.FLASH_MAPS_SESSION_ATTRIBUTE, allFlashMaps); |
||||
this.request.addParameter("_flashKey", flashMap.getKey()); |
||||
this.flashMapManager.requestStarted(this.request); |
||||
|
||||
assertSame(flashMap, request.getAttribute(DefaultFlashMapManager.PREVIOUS_FLASH_MAP_ATTRIBUTE)); |
||||
assertEquals("value", request.getAttribute("name")); |
||||
} |
||||
|
||||
@Test |
||||
public void lookupPreviousFlashMapWithoutKey() { |
||||
Map<String, FlashMap> allFlashMaps = new HashMap<String, FlashMap>(); |
||||
request.getSession().setAttribute(DefaultFlashMapManager.FLASH_MAPS_SESSION_ATTRIBUTE, allFlashMaps); |
||||
|
||||
FlashMap flashMap = new FlashMap(); |
||||
flashMap.put("name", "value"); |
||||
allFlashMaps.put("key", flashMap); |
||||
|
||||
this.flashMapManager.setUseUniqueFlashKey(false); |
||||
this.flashMapManager.requestStarted(this.request); |
||||
|
||||
assertSame(flashMap, this.request.getAttribute(DefaultFlashMapManager.PREVIOUS_FLASH_MAP_ATTRIBUTE)); |
||||
assertEquals("value", this.request.getAttribute("name")); |
||||
} |
||||
|
||||
@SuppressWarnings("static-access") |
||||
@Test |
||||
public void removeExpired() throws InterruptedException { |
||||
FlashMap[] flashMapArray = new FlashMap[5]; |
||||
flashMapArray[0] = new FlashMap("key0", "_flashKey"); |
||||
flashMapArray[1] = new FlashMap("key1", "_flashKey"); |
||||
flashMapArray[2] = new FlashMap("key2", "_flashKey"); |
||||
flashMapArray[3] = new FlashMap("key3", "_flashKey"); |
||||
flashMapArray[4] = new FlashMap("key4", "_flashKey"); |
||||
|
||||
Map<String, FlashMap> allFlashMaps = new HashMap<String, FlashMap>(); |
||||
for (FlashMap flashMap : flashMapArray) { |
||||
allFlashMaps.put(flashMap.getKey(), flashMap); |
||||
} |
||||
|
||||
flashMapArray[1].startExpirationPeriod(0); |
||||
flashMapArray[3].startExpirationPeriod(0); |
||||
|
||||
Thread.currentThread().sleep(5); |
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
request.getSession().setAttribute(DefaultFlashMapManager.FLASH_MAPS_SESSION_ATTRIBUTE, allFlashMaps); |
||||
request.setParameter("_flashKey", "key0"); |
||||
this.flashMapManager.requestStarted(request); |
||||
|
||||
assertEquals(2, allFlashMaps.size()); |
||||
assertNotNull(allFlashMaps.get("key2")); |
||||
assertNotNull(allFlashMaps.get("key4")); |
||||
} |
||||
|
||||
@SuppressWarnings({ "unchecked", "static-access" }) |
||||
@Test |
||||
public void saveFlashMap() throws InterruptedException { |
||||
FlashMap flashMap = new FlashMap("key", "_flashKey"); |
||||
flashMap.put("name", "value"); |
||||
request.setAttribute(DefaultFlashMapManager.CURRENT_FLASH_MAP_ATTRIBUTE, flashMap); |
||||
|
||||
this.flashMapManager.setFlashMapTimeout(0); |
||||
this.flashMapManager.requestCompleted(this.request); |
||||
|
||||
Thread.currentThread().sleep(1); |
||||
|
||||
String sessionKey = DefaultFlashMapManager.FLASH_MAPS_SESSION_ATTRIBUTE; |
||||
Map<String, FlashMap> allFlashMaps = (Map<String, FlashMap>) this.request.getSession().getAttribute(sessionKey); |
||||
|
||||
assertSame(flashMap, allFlashMaps.get("key")); |
||||
assertTrue(flashMap.isExpired()); |
||||
} |
||||
|
||||
@Test |
||||
public void saveEmptyFlashMap() throws InterruptedException { |
||||
FlashMap flashMap = new FlashMap("key", "_flashKey"); |
||||
request.setAttribute(DefaultFlashMapManager.CURRENT_FLASH_MAP_ATTRIBUTE, flashMap); |
||||
|
||||
this.flashMapManager.setFlashMapTimeout(0); |
||||
this.flashMapManager.requestCompleted(this.request); |
||||
|
||||
assertNull(this.request.getSession().getAttribute(DefaultFlashMapManager.FLASH_MAPS_SESSION_ATTRIBUTE)); |
||||
} |
||||
|
||||
} |
||||
@ -1,56 +0,0 @@
@@ -1,56 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2010 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.bind.annotation; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* Annotation that indicates what attributes should be stored in the session or in |
||||
* some conversational storage in order to survive a client-side redirect. |
||||
* |
||||
* TODO ... |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
* |
||||
* @see org.springframework.web.bind.support.FlashStatus |
||||
*/ |
||||
@Target({ElementType.TYPE}) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Inherited |
||||
@Documented |
||||
public @interface FlashAttributes { |
||||
|
||||
/** |
||||
* The names of flash attributes in the model to be stored. |
||||
* |
||||
* TODO ... |
||||
*/ |
||||
String[] value() default {}; |
||||
|
||||
/** |
||||
* TODO ... |
||||
* |
||||
*/ |
||||
Class[] types() default {}; |
||||
|
||||
} |
||||
@ -1,51 +0,0 @@
@@ -1,51 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.bind.support; |
||||
|
||||
import org.springframework.web.bind.annotation.FlashAttributes; |
||||
|
||||
|
||||
/** |
||||
* Simple interface to pass into controller methods to allow them to activate |
||||
* a mode in which model attributes identified as "flash attributes" are |
||||
* temporarily stored in the session to make them available to the next |
||||
* request. The most common scenario is a client-side redirect. |
||||
* |
||||
* <p>In active mode, model attributes that match the attribute names or |
||||
* types declared via @{@link FlashAttributes} are saved in the session. |
||||
* On the next request, any flash attributes found in the session are |
||||
* automatically added to the model of the target controller method and |
||||
* are also cleared from the session. |
||||
* |
||||
* TODO ... |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
*/ |
||||
public interface FlashStatus { |
||||
|
||||
/** |
||||
* TODO ... |
||||
*/ |
||||
void setActive(); |
||||
|
||||
/** |
||||
* TODO ... |
||||
*/ |
||||
boolean isActive(); |
||||
|
||||
} |
||||
@ -1,37 +0,0 @@
@@ -1,37 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.bind.support; |
||||
|
||||
/** |
||||
* TODO ... |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
*/ |
||||
public class SimpleFlashStatus implements FlashStatus { |
||||
|
||||
private boolean active = false; |
||||
|
||||
public void setActive() { |
||||
this.active = true; |
||||
} |
||||
|
||||
public boolean isActive() { |
||||
return this.active; |
||||
} |
||||
|
||||
} |
||||
@ -1,108 +0,0 @@
@@ -1,108 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.method.annotation; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.HashSet; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils; |
||||
import org.springframework.web.bind.annotation.FlashAttributes; |
||||
import org.springframework.web.context.request.WebRequest; |
||||
|
||||
/** |
||||
* Manages flash attributes declared via @{@link FlashAttributes}. |
||||
* |
||||
* TODO ... |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
*/ |
||||
public class FlashAttributesHandler { |
||||
|
||||
public static final String FLASH_ATTRIBUTES_SESSION_KEY = FlashAttributesHandler.class.getName() + ".attributes"; |
||||
|
||||
private final Set<String> attributeNames = new HashSet<String>(); |
||||
|
||||
private final Set<Class<?>> attributeTypes = new HashSet<Class<?>>(); |
||||
|
||||
/** |
||||
* TODO ... |
||||
*/ |
||||
public FlashAttributesHandler(Class<?> handlerType) { |
||||
FlashAttributes annotation = AnnotationUtils.findAnnotation(handlerType, FlashAttributes.class); |
||||
if (annotation != null) { |
||||
this.attributeNames.addAll(Arrays.asList(annotation.value())); |
||||
this.attributeTypes.addAll(Arrays.<Class<?>>asList(annotation.types())); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Whether the controller represented by this handler has declared flash |
||||
* attribute names or types via @{@link FlashAttributes}. |
||||
*/ |
||||
public boolean hasFlashAttributes() { |
||||
return ((this.attributeNames.size() > 0) || (this.attributeTypes.size() > 0)); |
||||
} |
||||
|
||||
/** |
||||
* TODO ... |
||||
*/ |
||||
public boolean isFlashAttribute(String attributeName, Class<?> attributeType) { |
||||
return (this.attributeNames.contains(attributeName) || this.attributeTypes.contains(attributeType)); |
||||
} |
||||
|
||||
/** |
||||
* TODO ... |
||||
*/ |
||||
public void storeAttributes(WebRequest request, Map<String, ?> attributes) { |
||||
Map<String, Object> filtered = filterAttributes(attributes); |
||||
if (!filtered.isEmpty()) { |
||||
request.setAttribute(FLASH_ATTRIBUTES_SESSION_KEY, filtered, WebRequest.SCOPE_SESSION); |
||||
} |
||||
} |
||||
|
||||
private Map<String, Object> filterAttributes(Map<String, ?> attributes) { |
||||
Map<String, Object> result = new LinkedHashMap<String, Object>(); |
||||
for (String name : attributes.keySet()) { |
||||
Object value = attributes.get(name); |
||||
Class<?> type = (value != null) ? value.getClass() : null; |
||||
if (isFlashAttribute(name, type)) { |
||||
result.put(name, value); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* TODO ... |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public Map<String, Object> retrieveAttributes(WebRequest request) { |
||||
return (Map<String, Object>) request.getAttribute(FLASH_ATTRIBUTES_SESSION_KEY, WebRequest.SCOPE_SESSION); |
||||
} |
||||
|
||||
/** |
||||
* TODO ... |
||||
*/ |
||||
public void cleanupAttributes(WebRequest request) { |
||||
request.removeAttribute(FLASH_ATTRIBUTES_SESSION_KEY, WebRequest.SCOPE_SESSION); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue