Spring MVC – Redirecting model attributes from one controller to other controller
In the real world applications, we are required to redirect the request from one controller to other controller.
In other words we are required to redirect the request without user interaction again.
Example : Registration controller accepts the registration request and saves the user data.
Then it has to redirect to home page after successful registration.
So here , we will have one controller for registration and another controller for getting the home page.
After registration , we are required to redirect the request to home page controller with user details.
So how do we pass the user information to other controller ?
Spring MVC 3.1 has come up with the solution called Flash Attributes.
We will see how request can be redirected and how flash attributes can be added.
Spring MVC redirect can be achived in 2 ways
1)org.springframework.web.servlet.view.RedirectView : This class redirects the URL(absolute or Relative)
It has a method called setContextRelative(boolean b)
By default . it is false and which means it takes absolute url.
If we set it to true,it takes relative url(starts from the application context)
So below code is representing the RedirectView example
- RedirectView redirectView = new RedirectView();
- redirectView.setContextRelative(true);
- redirectView.setUrl("/home");
- return redirectView;
RedirectView redirectView = new RedirectView(); redirectView.setContextRelative(true); redirectView.setUrl("/home"); return redirectView;
2)We can use redirect keyword rather than using RedirectView class as below
- return “redirect:/home”
return “redirect:/home”
Now , when we do Redirect, How are we adding Flash attributes to pass to other redirected controller ?
RedirectAttributes should be added as a parameter in the @RequestMapping method in the controller
Then we can use addFlashAttribute(“key”,”value”);
addFlashAttribute add the given parameter to the output flash map and pass it to the subsequent request.
How can we access the Flash Attribute in the redirected controller ?
3 ways to access Flash attributes
1)Using Model attribute argument in the @RequestMapping method and access the value as below
Model.asMap().get(“key”);
2)Using RequestContextUtils, the static method getInputFlashMap() accepts HttpServeltRequest as an argument and it returns a Map.
We can access the flash attribute by passing key to the map.
- Map<String, ?> flashInputMap = RequestContextUtils.getInputFlashMap(request);
- flashInputMap.get("key");
Map<String, ?> flashInputMap = RequestContextUtils.getInputFlashMap(request); flashInputMap.get("key");
3)Access directly using model parameter from the @RequestMapping method in the jsp page.
Problem with Flash Attributes is, they are accessible only in the first redirection.
Once redirection is done, the flash attributes are getting removed.
So after redirection, if user Refreshes the page these flash attributes will not be available .
So it is better if we do null check for the flashMap and take to the appropriate view.
Ex:
- If(flashInputMap !=null)
- return “home”;
- else
- return “someOtherView”;
If(flashInputMap !=null) return “home”; else return “someOtherView”;
Lets see the real world example for the same
Project structure
Create the model class as below
- package com.kb.model;
- public class Customer {
- private String emailId;
- private String password;
- private String confPassword;
- private int age;
- public String getEmailId() {
- return emailId;
- }
- public void setEmailId(String emailId) {
- this.emailId = emailId;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public String getConfPassword() {
- return confPassword;
- }
- public void setConfPassword(String confPassword) {
- this.confPassword = confPassword;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
package com.kb.model; public class Customer { private String emailId; private String password; private String confPassword; private int age; public String getEmailId() { return emailId; } public void setEmailId(String emailId) { this.emailId = emailId; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getConfPassword() { return confPassword; } public void setConfPassword(String confPassword) { this.confPassword = confPassword; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Create the Registration controller
- package com.kb.controller;
- import javax.validation.Valid;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.validation.BindingResult;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.servlet.mvc.support.RedirectAttributes;
- import com.kb.model.Customer;
- @Controller
- public class RegistrationController {
- @RequestMapping(value = "/register", method = RequestMethod.GET)
- public String viewRegistrationPage(Model model) {
- Customer customer = new Customer();
- model.addAttribute("customer", customer);
- return "register";
- }
- @RequestMapping(value = "/doRegister", method = RequestMethod.POST)
- public String doLogin(@Valid Customer customer, BindingResult result,Model model,RedirectAttributes redirectAttributes) {
- model.addAttribute("customer",customer);
- //Do the Registration logic and then redirect to home page without using action for home page
- redirectAttributes.addFlashAttribute("customerEmail", customer.getEmailId());
- return "redirect:/home";
- }
- }
package com.kb.controller; import javax.validation.Valid; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import com.kb.model.Customer; @Controller public class RegistrationController { @RequestMapping(value = "/register", method = RequestMethod.GET) public String viewRegistrationPage(Model model) { Customer customer = new Customer(); model.addAttribute("customer", customer); return "register"; } @RequestMapping(value = "/doRegister", method = RequestMethod.POST) public String doLogin(@Valid Customer customer, BindingResult result,Model model,RedirectAttributes redirectAttributes) { model.addAttribute("customer",customer); //Do the Registration logic and then redirect to home page without using action for home page redirectAttributes.addFlashAttribute("customerEmail", customer.getEmailId()); return "redirect:/home"; } }
Create the Home controller
- package com.kb.controller;
- import java.util.Map;
- import javax.servlet.http.HttpServletRequest;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.servlet.support.RequestContextUtils;
- @Controller
- public class HomeController {
- @RequestMapping(value = "/home", method = RequestMethod.GET)
- public String doLogin(HttpServletRequest request,Model model) {
- String emailId1 = (String)model.asMap().get("customerEmail");
- System.out.println(emailId1);
- Map<String, ?> flashMap = RequestContextUtils.getInputFlashMap(request);
- String emailId2 = (String) flashMap.get("customerEmail");
- System.out.println(emailId2);
- return "home";
- }
- }
package com.kb.controller; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.support.RequestContextUtils; @Controller public class HomeController { @RequestMapping(value = "/home", method = RequestMethod.GET) public String doLogin(HttpServletRequest request,Model model) { String emailId1 = (String)model.asMap().get("customerEmail"); System.out.println(emailId1); Map<String, ?> flashMap = RequestContextUtils.getInputFlashMap(request); String emailId2 = (String) flashMap.get("customerEmail"); System.out.println(emailId2); return "home"; } }
In the above controller, I have shown the different way of accessing flash attribute
Create the registration page
- <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
- <html>
- <head>
- <title>Spring MVC form Validation</title>
- </head>
- <body>
- <h2>Enter below details to Register</h2>
- <form:form method="POST" modelAttribute="customer" action="doRegister">
- <table>
- <tr>
- <td>Enter your E-mail:</td>
- <td><form:input path="emailId" /></td>
- <td><form:errors path="emailId" cssStyle="color: #ff0000;" /></td>
- </tr>
- <tr>
- <td>Enter your Age:</td>
- <td><form:input path="age"/></td>
- <td><form:errors path="age" cssStyle="color: #ff0000;"/></td>
- </tr>
- <tr>
- <td>Enter your password:</td>
- <td><form:password path="password" showPassword="true"/></td>
- <td><form:errors path="password" cssStyle="color: #ff0000;"/></td>
- </tr>
- <tr>
- <td>Confirm your password:</td>
- <td><form:password path="confPassword" showPassword="true"/></td>
- <td><form:errors path="confPassword" cssStyle="color: #ff0000;"/></td>
- </tr>
- <tr>
- <td><input type="submit" name="submit" value="Click here to Register"></td>
- </tr>
- </table>
- </form:form>
- </body>
- </html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <title>Spring MVC form Validation</title> </head> <body> <h2>Enter below details to Register</h2> <form:form method="POST" modelAttribute="customer" action="doRegister"> <table> <tr> <td>Enter your E-mail:</td> <td><form:input path="emailId" /></td> <td><form:errors path="emailId" cssStyle="color: #ff0000;" /></td> </tr> <tr> <td>Enter your Age:</td> <td><form:input path="age"/></td> <td><form:errors path="age" cssStyle="color: #ff0000;"/></td> </tr> <tr> <td>Enter your password:</td> <td><form:password path="password" showPassword="true"/></td> <td><form:errors path="password" cssStyle="color: #ff0000;"/></td> </tr> <tr> <td>Confirm your password:</td> <td><form:password path="confPassword" showPassword="true"/></td> <td><form:errors path="confPassword" cssStyle="color: #ff0000;"/></td> </tr> <tr> <td><input type="submit" name="submit" value="Click here to Register"></td> </tr> </table> </form:form> </body> </html>
Create the home page
- <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
- pageEncoding="ISO-8859-1"%>
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Registration Success</title>
- </head>
- <body>
- <div align="center">
- <h2>Welcome ${customerEmail}! Here is your Home Page.</h2>
- </div>
- </body>
- </html>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Registration Success</title> </head> <body> <div align="center"> <h2>Welcome ${customerEmail}! Here is your Home Page.</h2> </div> </body> </html>
Create the spring mvc configuration file
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.2.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
- <context:component-scan base-package="com.kb.*" />
- <mvc:annotation-driven />
- <bean id="viewResolver"
- class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/WEB-INF/pages/" />
- <property name="suffix" value=".jsp" />
- </bean>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> <context:component-scan base-package="com.kb.*" /> <mvc:annotation-driven /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/" /> <property name="suffix" value=".jsp" /> </bean> </beans>
Create the web.xml
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
- version="3.1">
- <display-name>Spring MVC Flash Attribute</display-name>
- <!-- Spring MVC dispatcher servlet -->
- <servlet>
- <servlet-name>mvc-dispatcher</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- /WEB-INF/spring-mvc.xml,
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>mvc-dispatcher</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- </web-app>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>Spring MVC Flash Attribute</display-name> <!-- Spring MVC dispatcher servlet --> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring-mvc.xml, </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
Create the pom.xml
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>Spring</groupId>
- <artifactId>SpringMVCFlashAttributes</artifactId>
- <packaging>war</packaging>
- <version>0.0.1-SNAPSHOT</version>
- <name>SpringMVCFlashAttributes Maven Webapp</name>
- <url>http://maven.apache.org</url>
- <properties>
- <org.springframework.version>4.2.0.RELEASE</org.springframework.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-web</artifactId>
- <version>${org.springframework.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>${org.springframework.version}</version>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.5</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.servlet.jsp.jstl</groupId>
- <artifactId>javax.servlet.jsp.jstl-api</artifactId>
- <version>1.2.1</version>
- </dependency>
- <dependency>
- <groupId>taglibs</groupId>
- <artifactId>standard</artifactId>
- <version>1.1.2</version>
- </dependency>
- <dependency>
- <groupId>javax.validation</groupId>
- <artifactId>validation-api</artifactId>
- <version>1.1.0.Final</version>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-validator</artifactId>
- <version>5.0.1.Final</version>
- </dependency>
- </dependencies>
- <build>
- <finalName>SpringMVCFlashAttributes</finalName>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>2.5.1</version>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Spring</groupId> <artifactId>SpringMVCFlashAttributes</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>SpringMVCFlashAttributes Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <org.springframework.version>4.2.0.RELEASE</org.springframework.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>javax.servlet.jsp.jstl-api</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.0.1.Final</version> </dependency> </dependencies> <build> <finalName>SpringMVCFlashAttributes</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
Build and deploy the project and access the below url
http://localhost:8080/SpringMVCFlashAttributes/register
Enter below details
Click on Register
Observe that flash attribute is accessed inside the jsp using model attribute.
One problem with Flash attribute is the Refresh(F5)
Now Refresh the above page and see the output, email id is not displayed as its null now
So To avoid this situation, its better to add null check on the flash attribute and handle it as below
I am going to display one more jsp if flash map is null by modifying the Home controller as below
- package com.kb.controller;
- import java.util.Map;
- import javax.servlet.http.HttpServletRequest;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.servlet.support.RequestContextUtils;
- @Controller
- public class HomeController {
- @RequestMapping(value = "/home", method = RequestMethod.GET)
- public String doLogin(HttpServletRequest request,Model model) {
- Map<String, ?> flashMap = RequestContextUtils.getInputFlashMap(request);
- if(flashMap != null){
- String emailId = (String) flashMap.get("customerEmail");
- System.out.println(emailId);
- return "home";
- }
- else{
- return "refreshNotAllowed";
- }
- }
- }
package com.kb.controller; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.support.RequestContextUtils; @Controller public class HomeController { @RequestMapping(value = "/home", method = RequestMethod.GET) public String doLogin(HttpServletRequest request,Model model) { Map<String, ?> flashMap = RequestContextUtils.getInputFlashMap(request); if(flashMap != null){ String emailId = (String) flashMap.get("customerEmail"); System.out.println(emailId); return "home"; } else{ return "refreshNotAllowed"; } } }
Create the refreshNotAllowed jsp as below
- <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
- pageEncoding="ISO-8859-1"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Insert title here</title>
- </head>
- <body>
- <h2>Sorry ,Refresh on this page is not allowed</h2>
- </body>
- </html>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <h2>Sorry ,Refresh on this page is not allowed</h2> </body> </html>
Build the project and deploy it and run it by accessing below url
http://localhost:8080/SpringMVCFlashAttributes/register
Click on Register by entering the details
Now Refresh the above page
So this is one way we can handle refresh on flash attribute.