Skip to content
This repository
Browse code

REDIRECT AND FLASH ATTRIBUTE RELATED IMPROVEMENTS

Remove custom FlashMap extension.
Update FormController to use Spring 3.1 flash attributes.
Use @ModelAttribute method to pre-load "ajaxRequest" attribute.
USe @SessionAttribute to store "formBean" attribute in the session.
Add "Redirect" tab showing options for building the redirect URL.
  • Loading branch information...
commit b1c4b3d36c80f6ed1bc85bab560172a2ce1cafb3 1 parent e5b82d0
authored September 20, 2011
2  pom.xml
@@ -9,7 +9,7 @@
9 9
 	<version>1.0.0-BUILD-SNAPSHOT</version>
10 10
 	<properties>
11 11
 		<java-version>1.6</java-version>
12  
-		<org.springframework-version>3.1.0.M2</org.springframework-version>
  12
+		<org.springframework-version>3.1.0.BUILD-SNAPSHOT</org.springframework-version>
13 13
 		<org.aspectj-version>1.6.10</org.aspectj-version>
14 14
 		<org.slf4j-version>1.6.1</org.slf4j-version>
15 15
 	</properties>
86  src/main/java/org/springframework/mvc/extensions/flash/FlashMap.java
... ...
@@ -1,86 +0,0 @@
1  
-package org.springframework.mvc.extensions.flash;
2  
-
3  
-import java.util.HashMap;
4  
-import java.util.Map;
5  
-
6  
-import javax.servlet.http.HttpServletRequest;
7  
-import javax.servlet.http.HttpSession;
8  
-
9  
-import org.springframework.web.context.request.RequestAttributes;
10  
-import org.springframework.web.context.request.RequestContextHolder;
11  
-import org.springframework.web.context.request.ServletRequestAttributes;
12  
-
13  
-public final class FlashMap {
14  
-	
15  
-	static final String FLASH_MAP_ATTRIBUTE = FlashMap.class.getName();
16  
-	
17  
-	@SuppressWarnings("unchecked")
18  
-	public static Map<String, Object> getCurrent(HttpServletRequest request) {
19  
-		HttpSession session = request.getSession(); 
20  
-		Map<String, Object> flash = (Map<String, Object>) session.getAttribute(FLASH_MAP_ATTRIBUTE);
21  
-		if (flash == null) {
22  
-			flash = new HashMap<String, Object>();
23  
-			session.setAttribute(FLASH_MAP_ATTRIBUTE, flash);
24  
-		}
25  
-		return flash;
26  
-	}
27  
-	
28  
-	private FlashMap() {
29  
-	}
30  
-
31  
-	public static void put(String key, Object value) {
32  
-		getCurrent(getRequest(RequestContextHolder.currentRequestAttributes())).put(key, value);
33  
-	}
34  
-
35  
-	public static void setInfoMessage(String info) {
36  
-		put(MESSAGE_KEY, new Message(MessageType.info, info));
37  
-	}
38  
-
39  
-	public static void setWarningMessage(String warning) {
40  
-		put(MESSAGE_KEY, new Message(MessageType.warning, warning));
41  
-	}
42  
-
43  
-	public static void setErrorMessage(String error) {
44  
-		put(MESSAGE_KEY, new Message(MessageType.error, error));
45  
-	}
46  
-
47  
-	public static void setSuccessMessage(String success) {
48  
-		put(MESSAGE_KEY, new Message(MessageType.success, success));
49  
-	}
50  
-
51  
-	private static HttpServletRequest getRequest(RequestAttributes requestAttributes) {
52  
-		return ((ServletRequestAttributes)requestAttributes).getRequest();
53  
-	}
54  
-
55  
-	private static final String MESSAGE_KEY = "message";
56  
-
57  
-	public static final class Message {
58  
-		
59  
-		private final MessageType type;
60  
-		
61  
-		private final String text;
62  
-
63  
-		public Message(MessageType type, String text) {
64  
-			this.type = type;
65  
-			this.text = text;
66  
-		}
67  
-
68  
-		public MessageType getType() {
69  
-			return type;
70  
-		}
71  
-
72  
-		public String getText() {
73  
-			return text;
74  
-		}
75  
-		
76  
-		public String toString() {
77  
-			return type + ": " + text;
78  
-		}
79  
-	
80  
-	}
81  
-	
82  
-	public static enum MessageType {
83  
-		info, success, warning, error
84  
-	}
85  
-	
86  
-}
36  src/main/java/org/springframework/mvc/extensions/flash/FlashMapFilter.java
... ...
@@ -1,36 +0,0 @@
1  
-package org.springframework.mvc.extensions.flash;
2  
-
3  
-import java.io.IOException;
4  
-import java.util.Map;
5  
-
6  
-import javax.servlet.FilterChain;
7  
-import javax.servlet.ServletException;
8  
-import javax.servlet.http.HttpServletRequest;
9  
-import javax.servlet.http.HttpServletResponse;
10  
-import javax.servlet.http.HttpSession;
11  
-
12  
-import org.springframework.web.filter.OncePerRequestFilter;
13  
-
14  
-public class FlashMapFilter extends OncePerRequestFilter {
15  
-
16  
-	@Override
17  
-	@SuppressWarnings("unchecked")
18  
-	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
19  
-		throws ServletException, IOException {
20  
-		HttpSession session = request.getSession(false);
21  
-		if (session != null) {
22  
-			Map<String, ?> flash = (Map<String, ?>) session.getAttribute(FlashMap.FLASH_MAP_ATTRIBUTE);
23  
-			if (flash != null) {
24  
-				for (Map.Entry<String, ?> entry : flash.entrySet()) {
25  
-					Object currentValue = request.getAttribute(entry.getKey());
26  
-					if (currentValue == null) {
27  
-						request.setAttribute(entry.getKey(), entry.getValue());
28  
-					}					
29  
-				}
30  
-				session.removeAttribute(FlashMap.FLASH_MAP_ATTRIBUTE);
31  
-			}
32  
-		}
33  
-		filterChain.doFilter(request, response);
34  
-	}
35  
-
36  
-}
18  src/main/java/org/springframework/samples/mvc/fileupload/FileUploadController.java
@@ -3,10 +3,9 @@
3 3
 import java.io.IOException;
4 4
 
5 5
 import org.springframework.mvc.extensions.ajax.AjaxUtils;
6  
-import org.springframework.mvc.extensions.flash.FlashMap.Message;
7  
-import org.springframework.mvc.extensions.flash.FlashMap.MessageType;
8 6
 import org.springframework.stereotype.Controller;
9 7
 import org.springframework.ui.Model;
  8
+import org.springframework.web.bind.annotation.ModelAttribute;
10 9
 import org.springframework.web.bind.annotation.RequestMapping;
11 10
 import org.springframework.web.bind.annotation.RequestMethod;
12 11
 import org.springframework.web.bind.annotation.RequestParam;
@@ -17,17 +16,18 @@
17 16
 @RequestMapping("/fileupload")
18 17
 public class FileUploadController {
19 18
 
  19
+	@ModelAttribute
  20
+	public void ajaxAttribute(WebRequest request, Model model) {
  21
+		model.addAttribute("ajaxRequest", AjaxUtils.isAjaxRequest(request));
  22
+	}
  23
+
20 24
 	@RequestMapping(method=RequestMethod.GET)
21  
-	public void fileUploadForm(WebRequest webRequest, Model model) {
22  
-		model.addAttribute("ajaxRequest", AjaxUtils.isAjaxRequest(webRequest));	
  25
+	public void fileUploadForm() {
23 26
 	}
24 27
 
25 28
 	@RequestMapping(method=RequestMethod.POST)
26  
-	public void processUpload(@RequestParam MultipartFile file, WebRequest webRequest, Model model) throws IOException {
27  
-		String message = "File '" + file.getOriginalFilename() + "' uploaded successfully";
28  
-		// prepare model for rendering success message in this request
29  
-		model.addAttribute("message", new Message(MessageType.success, message));
30  
-		model.addAttribute("ajaxRequest", AjaxUtils.isAjaxUploadRequest(webRequest));			
  29
+	public void processUpload(@RequestParam MultipartFile file, Model model) throws IOException {
  30
+		model.addAttribute("message", "File '" + file.getOriginalFilename() + "' uploaded successfully");
31 31
 	}
32 32
 	
33 33
 }
47  src/main/java/org/springframework/samples/mvc/form/FormController.java
... ...
@@ -1,49 +1,60 @@
1 1
 package org.springframework.samples.mvc.form;
2 2
 
3  
-import javax.servlet.http.HttpSession;
4 3
 import javax.validation.Valid;
5 4
 
6 5
 import org.springframework.mvc.extensions.ajax.AjaxUtils;
7  
-import org.springframework.mvc.extensions.flash.FlashMap;
8  
-import org.springframework.mvc.extensions.flash.FlashMap.Message;
9  
-import org.springframework.mvc.extensions.flash.FlashMap.MessageType;
10 6
 import org.springframework.stereotype.Controller;
11 7
 import org.springframework.ui.Model;
12 8
 import org.springframework.validation.BindingResult;
  9
+import org.springframework.web.bind.annotation.ModelAttribute;
13 10
 import org.springframework.web.bind.annotation.RequestMapping;
14 11
 import org.springframework.web.bind.annotation.RequestMethod;
  12
+import org.springframework.web.bind.annotation.SessionAttributes;
15 13
 import org.springframework.web.context.request.WebRequest;
  14
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
16 15
 
17 16
 @Controller
18 17
 @RequestMapping("/form")
  18
+@SessionAttributes("formBean")
19 19
 public class FormController {
20 20
 
  21
+	// Invoked on every request
  22
+
  23
+	@ModelAttribute
  24
+	public void ajaxAttribute(WebRequest request, Model model) {
  25
+		model.addAttribute("ajaxRequest", AjaxUtils.isAjaxRequest(request));
  26
+	}
  27
+
  28
+	// Invoked initially to create the "form" attribute
  29
+	// Once created the "form" attribute comes from the HTTP session (see @SessionAttributes)
  30
+
  31
+	@ModelAttribute("formBean")
  32
+	public FormBean createFormBean() {
  33
+		return new FormBean();
  34
+	}
  35
+	
21 36
 	@RequestMapping(method=RequestMethod.GET)
22  
-	public void form(WebRequest webRequest, HttpSession session, Model model) {
23  
-		FormBean form = (FormBean) session.getAttribute("form");
24  
-		model.addAttribute(form != null ? form : new FormBean());
25  
-		model.addAttribute("ajaxRequest", AjaxUtils.isAjaxRequest(webRequest));
  37
+	public void form() {
26 38
 	}
27 39
 
28 40
 	@RequestMapping(method=RequestMethod.POST)
29  
-	public String processSubmit(@Valid FormBean form, BindingResult result, WebRequest webRequest, HttpSession session, Model model) {
  41
+	public String processSubmit(@Valid FormBean formBean, BindingResult result, boolean ajaxRequest, 
  42
+			Model model, RedirectAttributes redirectAttrs) {
30 43
 		if (result.hasErrors()) {
31  
-			model.addAttribute("ajaxRequest", AjaxUtils.isAjaxRequest(webRequest));
32 44
 			return null;
33 45
 		}
34  
-		// simply store form bean in the session for demo purposes, typically you would save form bean values to a db
35  
-		session.setAttribute("form", form);
36  
-		String message = "Form submitted successfully.  Bound " + form;
37  
-		// success response handling
38  
-		if (AjaxUtils.isAjaxRequest(webRequest)) {
  46
+		// Typically you would save to a db and clear the "form" attribute from the session 
  47
+		// via SessionStatus.setCompleted(). For the demo we leave it in the session.
  48
+		String message = "Form submitted successfully.  Bound " + formBean;
  49
+		// Success response handling
  50
+		if (ajaxRequest) {
39 51
 			// prepare model for rendering success message in this request
40  
-			model.addAttribute("message", new Message(MessageType.success, message));
41  
-			model.addAttribute("ajaxRequest", true);
  52
+			model.addAttribute("message", message);
42 53
 			return null;
43 54
 		} else {
44 55
 			// store a success message for rendering on the next request after redirect
45  
-			FlashMap.setSuccessMessage(message);
46 56
 			// redirect back to the form to render the success message along with newly bound values
  57
+			redirectAttrs.addFlashAttribute("message", message);
47 58
 			return "redirect:/form";			
48 59
 		}
49 60
 	}
47  src/main/java/org/springframework/samples/mvc/redirect/RedirectController.java
... ...
@@ -0,0 +1,47 @@
  1
+package org.springframework.samples.mvc.redirect;
  2
+
  3
+import javax.inject.Inject;
  4
+
  5
+import org.joda.time.LocalDate;
  6
+import org.springframework.core.convert.ConversionService;
  7
+import org.springframework.stereotype.Controller;
  8
+import org.springframework.web.bind.annotation.PathVariable;
  9
+import org.springframework.web.bind.annotation.RequestMapping;
  10
+import org.springframework.web.bind.annotation.RequestMethod;
  11
+import org.springframework.web.bind.annotation.RequestParam;
  12
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
  13
+import org.springframework.web.util.UriComponents;
  14
+import org.springframework.web.util.UriComponentsBuilder;
  15
+
  16
+@Controller
  17
+@RequestMapping("/redirect")
  18
+public class RedirectController {
  19
+	
  20
+	private final ConversionService conversionService;
  21
+
  22
+	@Inject
  23
+	public RedirectController(ConversionService conversionService) {
  24
+		this.conversionService = conversionService;
  25
+	}
  26
+
  27
+	@RequestMapping(value="/uriTemplate", method=RequestMethod.GET)
  28
+	public String uriTemplate(RedirectAttributes redirectAttrs) {
  29
+		redirectAttrs.addAttribute("account", "a123");  // Used as URI template variable
  30
+		redirectAttrs.addAttribute("date", new LocalDate(2011, 12, 31));  // Appended as a query parameter
  31
+		return "redirect:/redirect/{account}";
  32
+	}
  33
+
  34
+	@RequestMapping(value="/uriComponentsBuilder", method=RequestMethod.GET)
  35
+	public String uriComponentsBuilder() {
  36
+		String date = this.conversionService.convert(new LocalDate(2011, 12, 31), String.class);
  37
+		UriComponents redirectUri = UriComponentsBuilder.fromPath("/redirect/{account}").queryParam("date", date)
  38
+				.build().expand("a123").encode();
  39
+		return "redirect:" + redirectUri.toUriString();
  40
+	}
  41
+
  42
+	@RequestMapping(value="/{account}", method=RequestMethod.GET)
  43
+	public String show(@PathVariable String account, @RequestParam(required=false) LocalDate date) {
  44
+		return "redirect/redirectResults";
  45
+	}
  46
+
  47
+}
5  src/main/java/org/springframework/samples/mvc/views/ViewsController.java
@@ -25,13 +25,16 @@ public void usingRequestToViewNameTranslator(Model model) {
25 25
 		model.addAttribute("fruit", "apple");
26 26
 	}
27 27
 
28  
-	@RequestMapping(value="pathVars/{foo}/{fruit}", method=RequestMethod.GET)
  28
+	@RequestMapping(value="pathVariables/{foo}/{fruit}", method=RequestMethod.GET)
29 29
 	public String pathVars(@PathVariable String foo, @PathVariable String fruit) {
  30
+		// No need to add @PathVariables "foo" and "fruit" to the model
  31
+		// They will be merged in the model before rendering
30 32
 		return "views/html";
31 33
 	}
32 34
 
33 35
 	@RequestMapping(value="dataBinding/{foo}/{fruit}", method=RequestMethod.GET)
34 36
 	public String dataBinding(@Valid JavaBean javaBean, Model model) {
  37
+		// JavaBean "foo" and "fruit" properties populated from URI variables 
35 38
 		return "views/dataBinding";
36 39
 	}
37 40
 
2  src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
@@ -27,7 +27,7 @@
27 27
 	<!-- Only needed because we install custom converters to support the examples in the org.springframewok.samples.mvc.convert package -->
28 28
 	<beans:bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
29 29
 		<beans:property name="formatters">
30  
-			<beans:bean class="org.springframework.samples.mvc.convert.MaskFormatAnnotationFormatterFactory" />
  30
+            <beans:bean class="org.springframework.samples.mvc.convert.MaskFormatAnnotationFormatterFactory" />
31 31
 		</beans:property>
32 32
 	</beans:bean>
33 33
 
2  src/main/webapp/WEB-INF/views/fileupload.jsp
@@ -18,7 +18,7 @@
18 18
 			<div class="header">
19 19
 		  		<h2>Form</h2>
20 20
 		  		<c:if test="${not empty message}">
21  
-					<div id="message" class="${message.type}">${message.text}</div>	  		
  21
+					<div id="message" class="success">${message}</div>	  		
22 22
 		  		</c:if>
23 23
 			</div>
24 24
 			<label for="file">File</label>
2  src/main/webapp/WEB-INF/views/form.jsp
@@ -20,7 +20,7 @@
20 20
 			<div class="header">
21 21
 		  		<h2>Form</h2>
22 22
 		  		<c:if test="${not empty message}">
23  
-					<div id="message" class="${message.type}">${message.text}</div>	
  23
+					<div id="message" class="success">${message}</div>	
24 24
 		  		</c:if>
25 25
 		  		<s:bind path="*">
26 26
 		  			<c:if test="${status.error}">
19  src/main/webapp/WEB-INF/views/home.jsp
@@ -7,7 +7,7 @@
7 7
 	<link href="<c:url value="/resources/jqueryui/1.8/themes/base/jquery.ui.all.css" />" rel="stylesheet" type="text/css"/>
8 8
 </head>
9 9
 <body>
10  
-<h1>spring-mvc-showcase</h1>
  10
+<h1><a href="<c:url value="/" />">spring-mvc-showcase</a></h1>
11 11
 <p>Recommended: Using a Web Developer tool such a Firebug to inspect the client/server interaction</p>
12 12
 <div id="tabs">
13 13
 	<ul>
@@ -22,6 +22,7 @@
22 22
 		<li><a href="<c:url value="/form" />" title="forms">Forms</a></li>
23 23
 		<li><a href="<c:url value="/fileupload" />" title="fileupload">File Upload</a></li>
24 24
 		<li><a href="#exceptions">Exception Handling</a></li>
  25
+		<li><a href="#redirect">Redirecting</a></li>
25 26
     </ul>
26 27
     <div id="simple">
27 28
 		<h2>Simple</h2>
@@ -261,7 +262,7 @@
261 262
 		</ul>	
262 263
 		<ul>
263 264
 			<li>
264  
-				<a href="<c:url value="/views/pathVars/bar/apple" />">Using path variables in a view template</a>
  265
+				<a href="<c:url value="/views/pathVariables/bar/apple" />">Using path variables in a view template</a>
265 266
 			</li>
266 267
 		</ul>
267 268
 		<ul>
@@ -350,6 +351,20 @@
350 351
 			</li>
351 352
 		</ul>
352 353
 	</div>
  354
+	<div id="redirect">
  355
+		<h2>Redirecting</h2>
  356
+		<p>
  357
+			See the <code>org.springframework.samples.mvc.redirect</code> package for the @Controller code	
  358
+		</p>
  359
+		<ul>
  360
+			<li>
  361
+				<a href="<c:url value="/redirect/uriTemplate" />">URI Template String</a>
  362
+			</li>
  363
+			<li>
  364
+				<a href="<c:url value="/redirect/uriComponentsBuilder" />">UriComponentsBuilder</a>
  365
+			</li>
  366
+		</ul>
  367
+	</div>
353 368
 </div>
354 369
 <script type="text/javascript" src="<c:url value="/resources/jquery/1.6/jquery.js" />"></script>
355 370
 <script type="text/javascript" src="<c:url value="/resources/jqueryform/2.8/jquery.form.js" />"></script>
15  src/main/webapp/WEB-INF/views/redirect/redirectResults.jsp
... ...
@@ -0,0 +1,15 @@
  1
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  2
+<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
  3
+<%@ page session="false" %>
  4
+<html>
  5
+<head>
  6
+	<title>Redirect Results</title>
  7
+	<link href="<c:url value="/resources/form.css" />" rel="stylesheet"  type="text/css" />		
  8
+</head>
  9
+<body>
  10
+<div class="success">
  11
+	<h3>Path variable 'account': ${account}</h3>
  12
+	<h3>Query param 'date': ${param.date}</h3>
  13
+</div>
  14
+</body>
  15
+</html>
9  src/main/webapp/WEB-INF/views/views/dataBinding.jsp
@@ -2,10 +2,13 @@
2 2
 <%@ page session="false" %>
3 3
 <html>
4 4
 <head>
5  
-	<title>My HTML View (Data Binding)</title>
  5
+	<title>Data Binding with URI Template Variables</title>
  6
+	<link href="<c:url value="/resources/form.css" />" rel="stylesheet"  type="text/css" />		
6 7
 </head>
7 8
 <body>
8  
-<h1>foo = ${javaBean.foo}</h1>
9  
-<h1>fruit = ${javaBean.fruit}</h1>
  9
+<div class="success">
  10
+	<h3>javaBean.foo: ${javaBean.foo}</h3>
  11
+	<h3>javaBean.fruit: ${javaBean.fruit}</h3>
  12
+</div>
10 13
 </body>
11 14
 </html>
7  src/main/webapp/WEB-INF/views/views/html.jsp
@@ -3,9 +3,12 @@
3 3
 <html>
4 4
 <head>
5 5
 	<title>My HTML View</title>
  6
+	<link href="<c:url value="/resources/form.css" />" rel="stylesheet"  type="text/css" />		
6 7
 </head>
7 8
 <body>
8  
-<h1>foo = ${foo}</h1>
9  
-<h1>fruit = ${fruit}</h1>
  9
+<div class="success">
  10
+	<h3>foo: "${foo}"</h3>
  11
+	<h3>fruit: "${fruit}"</h3>
  12
+</div>
10 13
 </body>
11 14
 </html>
7  src/main/webapp/WEB-INF/views/views/viewName.jsp
@@ -3,9 +3,12 @@
3 3
 <html>
4 4
 <head>
5 5
 	<title>My HTML View</title>
  6
+	<link href="<c:url value="/resources/form.css" />" rel="stylesheet"  type="text/css" />		
6 7
 </head>
7 8
 <body>
8  
-<h1>foo = ${foo}</h1>
9  
-<h1>fruit = ${fruit}</h1>
  9
+<div class="success">
  10
+	<h3>foo: "${foo}"</h3>
  11
+	<h3>fruit: "${fruit}"</h3>
  12
+</div>
10 13
 </body>
11 14
 </html>
13  src/main/webapp/WEB-INF/web.xml
@@ -13,19 +13,6 @@
13 13
 	<listener>
14 14
 		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
15 15
 	</listener>
16  
-
17  
-	<!-- Allows attributes to be accessed on the next request (typically success messages) -->
18  
-	<!-- Note: this is a sample-specific implementation of the FlashMap concept -->
19  
-	<!-- Official flash map support is planned for a future release of Spring MVC -->
20  
-	<filter>
21  
-		<filter-name>flashMapFilter</filter-name>
22  
-		<filter-class>org.springframework.mvc.extensions.flash.FlashMapFilter</filter-class>
23  
-	</filter>
24  
-		
25  
-    <filter-mapping>
26  
-      <filter-name>flashMapFilter</filter-name>
27  
-      <url-pattern>/*</url-pattern>
28  
-    </filter-mapping>
29 16
     
30 17
 	<!-- Processes application requests -->
31 18
 	<servlet>

0 notes on commit b1c4b3d

Please sign in to comment.
Something went wrong with that request. Please try again.