Skip to content

Commit 5c1d9d5

Browse files
author
Micha Kiener
committed
SPR-6464, FlashMap implementation
1 parent af0bb19 commit 5c1d9d5

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2002-2008 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
package org.springframework.web.filter;
14+
15+
import java.io.IOException;
16+
import java.util.Map;
17+
18+
import javax.servlet.FilterChain;
19+
import javax.servlet.ServletException;
20+
import javax.servlet.http.HttpServletRequest;
21+
import javax.servlet.http.HttpServletResponse;
22+
23+
import org.springframework.web.util.FlashMap;
24+
25+
/**
26+
* The filter needed to be activated to support the {@link FlashMap}, writing parameters within the flash map to the
27+
* current request and flushing out the map afterwards.
28+
*
29+
* @author Micha Kiener
30+
* @since 3.1
31+
*/
32+
public class FlashMapFilter extends OncePerRequestFilter {
33+
34+
/**
35+
* @see org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(javax.servlet.http.HttpServletRequest,
36+
* javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
37+
*/
38+
@Override
39+
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
40+
throws ServletException, IOException {
41+
Map<String, Object> flashMap = FlashMap.getFlashMap(false);
42+
if (flashMap != null) {
43+
for (Map.Entry<String, ?> entry : flashMap.entrySet()) {
44+
Object currentValue = request.getAttribute(entry.getKey());
45+
if (currentValue == null) {
46+
request.setAttribute(entry.getKey(), entry.getValue());
47+
}
48+
}
49+
FlashMap.removeFlashMap();
50+
}
51+
52+
filterChain.doFilter(request, response);
53+
}
54+
55+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2002-2008 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
package org.springframework.web.util;
14+
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
18+
import org.springframework.web.context.request.RequestAttributes;
19+
import org.springframework.web.context.request.RequestContextHolder;
20+
import org.springframework.web.filter.FlashMapFilter;
21+
22+
/**
23+
* The Redirect-After-Post pattern is a solution for many problems and the flash map utility is able to store state
24+
* which persists to the next request. For instance, if you're having an error in the login handler, you could actually
25+
* store messages or any other state within the flash map and then redirect to an appropriate view where the state would
26+
* be still available. The content of the flash map is actually added as request parameters in the next request and then
27+
* being flushed out which is done by the {@link FlashMapFilter}.
28+
* <p>
29+
* If window management is activated, the flash map is stored within window scope to avoid concurrent tabs / windows
30+
* affecting each other, it falls back to the session, if window management is not activated.
31+
*
32+
* @author Micha Kiener
33+
* @since 3.1
34+
*
35+
* @see FlashMapFilter
36+
*/
37+
public class FlashMap {
38+
public static final String FLASH_MAP_ATTRIBUTE = FlashMap.class.getName();
39+
40+
/**
41+
* Stores the given name / value pair in the flash map to become available as a request parameter in the next
42+
* request using the same name.
43+
*
44+
* @param <T> the type of the parameter value to put in the flash map
45+
* @param parameterName the name of the parameter under which the value will become available in the next request
46+
* @param parameterValue the parameter value to be stored in flash
47+
* @return any old value already in the flash map, if any, <code>null</code> otherwise
48+
*/
49+
@SuppressWarnings("unchecked")
50+
public static <T> T put(String parameterName, T parameterValue) {
51+
Map<String, Object> flashMap = getFlashMap(true);
52+
return (T) flashMap.put(parameterName, parameterValue);
53+
}
54+
55+
/**
56+
* Returns the flash map typically stored in window or session scope and creates a new one, if not existing and if
57+
* needed.
58+
*
59+
* @param createIfNotExisting flag, indicating whether to create the flash map, if it does not exist already
60+
* @return the flash map currently bound to the session or window scope, if available
61+
*/
62+
@SuppressWarnings("unchecked")
63+
public static Map<String, Object> getFlashMap(boolean createIfNotExisting) {
64+
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
65+
Map<String, Object> flashMap = (Map<String, Object>) requestAttributes.getAttribute(FLASH_MAP_ATTRIBUTE,
66+
getFlashMapScope());
67+
68+
if (flashMap == null && createIfNotExisting) {
69+
flashMap = new HashMap<String, Object>();
70+
requestAttributes.setAttribute(FLASH_MAP_ATTRIBUTE, flashMap, getFlashMapScope());
71+
}
72+
73+
return flashMap;
74+
}
75+
76+
/**
77+
* Removes the flash map from the window or session scope.
78+
*/
79+
public static void removeFlashMap() {
80+
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
81+
requestAttributes.removeAttribute(FLASH_MAP_ATTRIBUTE, getFlashMapScope());
82+
}
83+
84+
/**
85+
* @return the scope to store the flash map in which is window scope by default, if window management is activated,
86+
* session otherwise
87+
*/
88+
protected static int getFlashMapScope() {
89+
// TODO: check for window management and return value accordingly
90+
return RequestAttributes.SCOPE_SESSION;
91+
}
92+
93+
/**
94+
* Private constructor as the map is only to be used using its static accessor methods.
95+
*/
96+
private FlashMap() {
97+
}
98+
}

0 commit comments

Comments
 (0)