文章目录
1、请求转发与重定向
当处理器对请求处理完毕后,向其他资源进行跳转时,有两种跳转方式:请求转发(服务器内跳转)与重定向(服务器外跳转)。而根据所要跳转的资源类型,又可以分为两类:跳转到页面与跳转到其他处理器。
注意,对于请求转发的页面,可以是WEB-INF中的页面;而重定向的页面是不能为WEB-INF中的页面。 因为重定向相当于用户再次发出一次请求,而用户是不能直接访问WEB-INF中资源的。
关于请求转发与重定向的概念,如下图所示:
2、返回ModelAndView时的请求转发
默认情况下,当处理器方法返回ModelAndView时,跳转到指定的View,使用的是请求转发。 但也可以显示的进行指出。此时,需要在setViewName()指定的视图前添加forward:,且此时的视图不会在与视图解析器中的前缀与后缀进行拼接。即必须写出相对于项目根的路径。故此时的视图解析器不再需要前缀与后缀。
当通过请求转发跳转到目标资源(页面或者其他Controller)时,若需要向下传递数据,除了可以使用request,session外,还可以将数据存放于ModelAndView中的Model中。页面通过EL表达式可直接访问该数据。
2.1 请求转发到页面
在演示案例中实现如下功能:当用户想要访问某一页面时(show.action),由于目前用户没有登录,因此系统会首先先跳转到登录页面让用户完成登录。
在处理器(Handler)中的请求转发到页面的核心代码如下所示:
@RequestMapping("/show")
public ModelAndView show(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/jsp/user/login.jsp");
return modelAndView;
}
视图页面login.jsp的具体代码如下所示:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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=UTF-8">
<title>用户登录</title>
</head>
<body>
<h3>用户登录</h3>
<form action="doLogin.action" method="post">
<table width="300px;" border=1>
<tr>
<td>用户编号:</td>
<td><input type="text" name="userId" id="userId" /></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username" /></td>
</tr>
<tr>
<td>密 码:</td>
<td><input type="password" name="password" id="password" /></td>
</tr>
</table>
<br/>
<input type="submit" id="login_button" value="用户登录" />
</form>
</body>
</html>
将项目部署到Tomcat服务器上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后,系统将采用请求转发的形式在服务器内部自动跳转到登录页面(login.jsp)。具体结果如下所示:
2.2 请求转发到其他Controller
当用户未登录访问show.action时会请求转发到登录页面login.jsp。而当用户在登录页面输入登录信息后,点击登录按钮,则会提示用户登录成功。
处理器(Handler)中的方法如下所示:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public ModelAndView show(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/jsp/user/login.jsp");
return modelAndView;
}
@RequestMapping("/doLogin")
public ModelAndView doLogin(User user){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
modelAndView.setViewName("forward:success.action");
return modelAndView;
}
@RequestMapping("/success")
public String success(User user, Model model){
model.addAttribute("user",user);
return "user/success";
}
}
提示用户登录成功的JSP页面(success.jsp)如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<h2 align="center">登录成功!</br></br>欢迎您${user.username}!</h2>
</body>
</html>
将项目重新部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后,在请求转发到的login.jsp页面中输入登录信息后,点击登录按钮,此时表单会提交给处理器中的doLogin方法处理数据,而当验证用户登录成功后,在doLogin方法中使用了请求转发到其他方法进行登录成功提示显示。具体结果如下:
3、返回ModelAndView时的重定向
返回ModelAndView时的重定向,需要在setViewName()指定的视图前添加redirect:,且此时的视图不会再与视图解析器中的前缀和后缀进行拼接。 即必须写出相对于项目根的路径。故此时的视图解析器不再需要前缀与后缀。
重定向的目标资源中,将无法访问用户提交请求的request中的数据。
3.1 重定向到页面
在重定向时,请求参数是无法通过request的属性向下一级资源中传递的。但是可以通过下面两种方式将请求参数向下传递。
3.1.1 通过ModelAndView的Model携带参数
当ModelAndView中的Model存入数据后,视图解析器InternalResourceViewResolver会将map中的key与value,以请求参数的形式放到请求的URL后。
不过需要注意以下几点:
第一,由于视图解析器会将Map的value放入到URL后作为请求参数传递出去,所以无论什么类型的value均会变为String。故此,放入到Model中的value,只能是基本数据类型与String,不能是自定义类型的数据对象。
第二,重定向的页面中是无法从request中读取数据的。但是由于map中的key与value,以请求参数的形式放到了请求的URL后,所以,页面可以通过EL表达式中的请求参数param读取。
第三,重定向的页面不能是/WEB-INF中的页面。
以之前的用户登录项目为例,当用户在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后,在请求转发到的login.jsp页面中输入登录信息后,点击登录按钮,此时表单会提交给处理器中的doLogin方法处理数据,而当验证用户登录成功后,在doLogin方法中使用了重定向的方式重定向到了welcome.jsp页面以示登录成功。
首先在web文件夹中创建名为“welcome.jsp”的JSP页面,当用户登录成功后用来显示提示页面。由于login.jsp页面未做修改,因此不再贴出代码。welcome.jsp页面具体代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>欢迎页</title>
</head>
<body>
<% String res = new String(request.getParameter("username").getBytes("iso8859-1"), "utf-8"); %>
<h2>【<%=res%>】您好,您已经登录到首页!</h2>
</body>
</html>
然后,修改处理器(Handler)中的方法,具体代码如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public ModelAndView show(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/jsp/user/login.jsp");
return modelAndView;
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/doLogin")
public ModelAndView doLogin(User user) throws UnsupportedEncodingException {
ModelAndView modelAndView = new ModelAndView();
//modelAndView.addObject("user",user);
modelAndView.addObject("username",user.getUsername());
modelAndView.addObject("userId",user.getUserId());
modelAndView.addObject("password",user.getPassword());
modelAndView.setViewName("redirect:/welcome.jsp");
return modelAndView;
}
}
最后,将项目重新部署到Tomcat上后,访问请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后输入用户信息,点击“用户登录”按钮后,则可以通过重定向的方法直接跳转到welcome.jsp页面。结果如下图所示:
3.1.2 使用HttpSession携带参数
当使用HttpSession携带参数进行重定向到页面时,参数不再通过get方式拼接到请求的URL后面。而是通过HttpSession对象的setAttribute()方法保存到Session中进行传递。而前端接收的时候则通过sessionScope对象。
由于传递的参数保存在Session中传递,因此可以传递自定义类型的参数。
首先,修改处理器(Handler)如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public ModelAndView show(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/jsp/user/login.jsp");
return modelAndView;
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/doLogin")
public ModelAndView doLogin(User user, HttpSession session) {
session.setAttribute("loginedUser",user);
return new ModelAndView("redirect:/welcome.jsp");
}
}
然后,修改welcome.jsp页面如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>欢迎页</title>
</head>
<body>
<h2>【${sessionScope.loginedUser.username}】您好,您已经登录到首页!</h2>
</body>
</html>
最后,将项目重新部署到Tomcat上后,访问请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后输入用户信息,点击“用户登录”按钮后,则可以通过重定向的方法直接跳转到welcome.jsp页面。结果如下图所示:
3.2 重定向到Controller
重定向到其他Controller时,若要携带参数,完全可以采用前面的方式(通过ModelAndView或HttpSession)。而对于目标Controller接收这些参数,则各不相同。
3.2.1 通过ModelAndView的Model携带参数
目标Controller在接收这些参数时,只要保证目标Controller的方法形参名称与发送Controller发送的参数名称相同即可接收参数。当然,目标Controller也可以进行参数的整体接收。只要保证参数名称与目标Controller接收参数类型的属性名相同即可。
继续以前面的用户登录项目为例,这里添加用户登录信息验证功能。当用户输入信息通过表单进行提交后,首先提交给处理器(Handler)中的checkLogin方法进行登录信息的验证,验证后再通过重定向的方式重定向到doLogin方法处理登录,最后再通过重定向的方式跳转到welcome.jsp页面提示登录成功。
首先,修改login.jsp页面,将表单提交的方法修改为“checkLogin.action”,具体代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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=UTF-8">
<title>用户登录</title>
</head>
<body>
<h3>用户登录</h3>
<form action="checkLogin.action" method="post">
<table width="300px;" border=1>
<tr>
<td>用户编号:</td>
<td><input type="text" name="userId" id="userId" /></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username" /></td>
</tr>
<tr>
<td>密 码:</td>
<td><input type="password" name="password" id="password" /></td>
</tr>
</table>
<br/>
<input type="submit" id="login_button" value="用户登录" />
</form>
</body>
</html>
然后,在处理器(Handler)中增加checkLogin方法,并且将doLogin方法的参数修改为逐个接收参数的方式,具体代码如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public ModelAndView show(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/jsp/user/login.jsp");
return modelAndView;
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/checkLogin")
public ModelAndView checkLogin(User user){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("userId",user.getUserId());
modelAndView.addObject("username",user.getUsername());
modelAndView.addObject("password",user.getPassword());
modelAndView.setViewName("redirect:doLogin.action");
return modelAndView;
}
@RequestMapping("/doLogin")
public ModelAndView doLogin(int userId, String username, String password) throws UnsupportedEncodingException {
ModelAndView modelAndView = new ModelAndView();
username = new String(username.getBytes("iso8859-1"), "utf-8");
modelAndView.addObject("username",username);
modelAndView.addObject("userId",userId);
modelAndView.addObject("password",password);
modelAndView.setViewName("redirect:/welcome.jsp");
return modelAndView;
}
}
由于welcome.jsp页面并未做修改,此处不再赘述。
最后,将项目重新部署到Tomcat上后,访问请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后输入用户信息,点击“用户登录”按钮后,表单首先提交给checkLogin方法进行验证,然后通过重定向的方式重定向到doLogin方法处理登录,最后再通过重定向的方式重定向到welcome.jsp页面提示登录成功。结果如下图所示:
再将处理器(Handler)中的doLogin方法修改为通过整体接收参数的形式,具体修改如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public ModelAndView show(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/jsp/user/login.jsp");
return modelAndView;
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/checkLogin")
public ModelAndView checkLogin(User user){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("userId",user.getUserId());
modelAndView.addObject("username",user.getUsername());
modelAndView.addObject("password",user.getPassword());
modelAndView.setViewName("redirect:doLogin.action");
return modelAndView;
}
@RequestMapping("/doLogin")
public ModelAndView doLogin(User user) throws UnsupportedEncodingException {
ModelAndView modelAndView = new ModelAndView();
//modelAndView.addObject("user",user);
modelAndView.addObject("username",new String(user.getUsername().getBytes("iso8859-1"), "utf-8"));
modelAndView.addObject("userId",user.getUserId());
modelAndView.addObject("password",user.getPassword());
modelAndView.setViewName("redirect:/welcome.jsp");
return modelAndView;
}
}
重新将项目部署到Tomcat上运行后,应该得到相同的结果。
3.2.2 使用HttpSession携带参数
使用HttpSession携带参数时,主要是利用HttpSession对象中的setAttribute()方法和getAttribute()方法。
首先,修改welcome.jsp页面,使用sessionScope对象接收并显示最后重定向过来的参数。由于login.jsp页面并没有修改,此处不再赘述。具体修改的代码如下所示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>欢迎页</title>
</head>
<body>
<h2>【${sessionScope.loginedUser.username}】您好,您已经登录到首页!</h2>
</body>
</html>
然后,修改处理器(Handler),具体代码如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public ModelAndView show(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/jsp/user/login.jsp");
return modelAndView;
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/checkLogin")
public ModelAndView checkLogin(User user, HttpSession session){
ModelAndView modelAndView = new ModelAndView();
session.setAttribute("user",user);
modelAndView.setViewName("redirect:doLogin.action");
return modelAndView;
}
@RequestMapping("/doLogin")
public ModelAndView doLogin(HttpSession session) {
User user = (User) session.getAttribute("user");
session.setAttribute("loginedUser",user);
return new ModelAndView("redirect:/welcome.jsp");
}
}
最后,将项目重新部署到Tomcat上后,访问请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后输入用户信息,点击“用户登录”按钮后,表单首先提交给checkLogin方法进行验证,然后通过重定向的方式重定向到doLogin方法处理登录,最后再通过重定向的方式重定向到welcome.jsp页面提示登录成功。结果如下图所示:
4、返回String时的请求转发
当处理器方法返回String时,该String即为要跳转的视图。在其前面加上前缀forward:,则可显式的指定跳转方式为请求转发。同样,视图解析器不会对其进行前缀与后缀的拼接。 请求转发的目标资源无论是一个页面,还是一个Controller,用法相同。
对之前的用户登录项目进行一定的修改。当用户访问http://localhost:8080/demo/ForwardRedirectTest/show.action 时,由于用户处于未登录状态,因此处理器(Handler)采用请求转发的方式将页面跳转到login.jsp页面。之前采用的是返回ModelAndView类型的对象,现在修改为返回String类型的视图名。
修改处理器(Handler)如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public String show(){
return "forward:/WEB-INF/jsp/user/login.jsp";
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
}
l 此时将项目部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后,由于用户并未登录,因此处理器(Handler)会通过请求转发的方式跳转到login.jsp页面。如下所示:
将login.jsp页面中的表单提交方法再次设置为doLogin.action,具体代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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=UTF-8">
<title>用户登录</title>
</head>
<body>
<h3>用户登录</h3>
<form action="doLogin.action" method="post">
<table width="300px;" border=1>
<tr>
<td>用户编号:</td>
<td><input type="text" name="userId" id="userId" /></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username" /></td>
</tr>
<tr>
<td>密 码:</td>
<td><input type="password" name="password" id="password" /></td>
</tr>
</table>
<br/>
<input type="submit" id="login_button" value="用户登录" />
</form>
</body>
</html>
接着,当用户提交表单后,交给处理器(Handler)的doLogin方法处理。而在doLogin方法中,采用请求转发的形式,将参数存放到了request域属性中进行传递。 具体代码如下所示:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public String show(){
return "forward:/WEB-INF/jsp/user/login.jsp";
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/doLogin")
public String doLogin(User user){
return "forward:/WEB-INF/jsp/user/success.jsp";
}
}
然后,/WEB-INF/jsp/user/success.jsp页面的代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<h2>登录成功!</br></br>欢迎您${requestScope.user.username}!</h2>
</body>
</html>
这里需要特别说明一下,就是当传递的参数通过request域属性传递的时候,在JSP页面中使用EL表达式进行接收并显示时,可以使用requestScope对象接收,也可以直接使用参数名接收并显示。即,在success.jsp页面中接收参数时,采用下面的方式接收并显示也是可以的:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<h2>登录成功!</br></br>欢迎您${user.username}!</h2>
</body>
</html>
最后,将项目重新部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后通过请求转发的形式跳转到登录页面。当用户输入登录信息提交表单后,交给处理器(Handler)的doLogin方法处理,而在doLogin方法中又采用了请求转发的方式将user对象转发给了success.jsp页面进行显示,具体结果如下:
若将处理器(Handler)中的doLogin方法修改为通过请求转发的方式跳转到其他Controller(success.action),然后再通过请求转发的方式跳转到页面(success.jsp)。即修改处理器(Handler)如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public String show(){
return "forward:/WEB-INF/jsp/user/login.jsp";
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/doLogin")
public String doLogin(User user){
return "forward:success.action";
}
@RequestMapping("/success")
public String success(User user){
return "forward:/WEB-INF/jsp/user/success.jsp";
}
}
最后,将项目重新部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后通过请求转发的形式跳转到登录页面。当用户输入登录信息提交表单后,交给处理器(Handler)的doLogin方法处理,而在doLogin方法中又采用了请求转发的方式将user对象转发给了success方法,在success方法中通过请求转发的方式将success.jsp页面进行显示,具体结果如下:
注意,此时不能使用ModelAndView传递数据了。因为在处理器方法中定义的ModelAndView对象就是个局部变量,方法运行结束,变量销毁。而当前的处理器方法返回的为String,而非ModelAndView,所以这个创建的ModelAndView就不起作用了。
不过,需要注意的是,对于处理器方法返回字符串的情况,当处理器接收到请求中的参数后,发现用于接收这些参数的处理器方法形参为包装类对象,则除了会将参数封装为对象传递给形参外,还会存放到request域属性中。
5、返回String时的重定向
在处理器方法返回的视图字符串的前面添加前缀redirect:,则可试下重定向跳转。
当重定向到目标资源时,若需要向下传递参数值,除了可以直接通过请求URL携带参数,通过HttpSession携带参数外,还可使用其他方式。
5.1 重定向到页面
5.1.1 通过Model形参携带参数
可以在Controller形参中添加Model参数,将要传递的数据放入Model中进行参数传递。该方式同样也是将参数拼接到了重定向请求的URL后,所以放入其中的数据只能是基本数据类型,不能是自定义类型。
login.jsp页面如下所示:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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=UTF-8">
<title>用户登录</title>
</head>
<body>
<h3>用户登录</h3>
<form action="doLogin.action" method="post">
<table width="300px;" border=1>
<tr>
<td>用户编号:</td>
<td><input type="text" name="userId" id="userId" /></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username" /></td>
</tr>
<tr>
<td>密 码:</td>
<td><input type="password" name="password" id="password" /></td>
</tr>
</table>
<br/>
<input type="submit" id="login_button" value="用户登录" />
</form>
</body>
</html>
welcome.jsp页面如下所示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>欢迎页</title>
</head>
<body>
<% String res = new String(request.getParameter("username").getBytes("iso8859-1"), "utf-8"); %>
<h2>【<%=res%>】您好,您已经登录到首页!</h2>
</body>
</html>
修改处理器(Handler)如下所示:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public String show(){
return "forward:/WEB-INF/jsp/user/login.jsp";
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/doLogin")
public String doLogin(User user, Model model) {
model.addAttribute("username",user.getUsername());
model.addAttribute("userId",user.getUserId());
model.addAttribute("password",user.getPassword());
return "redirect:/welcome.jsp";
}
}
将项目重新部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后处理器(Handler)首先访问show方法,通过请求转发跳转到登录页面(login.jsp),具体结果如图所示:
当用户输入信息提交表单后,处理器(Handler)由doLogin方法处理登录,在该方法中通过Model形参对象采用重定向的方式跳转到welcome.jsp页面,显示用户信息表示登录成功。具体结果如图所示:
5.1.2 使用形参RedirectAttributes的addAttribute()携带参数
RedirectAttributes是Spring 3.1版本后新增的功能,专门是用于携带重定向参数的。它是一个继承自Model的接口,其底层仍然使用ModelMap实现。通过addAttribute()方法会将参数名及参数值放入该Map中,然后视图解析器会将其拼接到请求的URL中。所以,这种携带参数的方式,不能携带自定义对象。
在前一个项目的基础上,只需把处理器(Handler)中的doLogin方法中的形参由Model换为RedirectAttributes即可。具体代码如下所示:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public String show(){
return "forward:/WEB-INF/jsp/user/login.jsp";
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/doLogin")
public String doLogin(User user, RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("username",user.getUsername());
redirectAttributes.addAttribute("userId",user.getUserId());
redirectAttributes.addAttribute("password",user.getPassword());
return "redirect:/welcome.jsp";
}
}
按照上一个案例进行演示,应该能够得到相同的结果,这里不再截图显示。
这里需要注意,由于RedirectAttributes是个接口,而这个接口参数的实参值是由MVC的注解驱动为期自动赋的值,所以若要使用RedirectAttributes参数,则需要在Spring MVC的核心配置文件中注册MVC的注解驱动。
由于我们整个项目全部使用基于注解的开发,因此在原有的Spring MVC的核心配置文件中已经注册了MVC的注解驱动。
5.2 重定向到Controller
重定向到Controller时,携带参数的方式,除了可以使用请求URL后携带方式,HttpSession携带方式,Model形参携带方式,以及RedirectAttributes形参的addAttribute()携带方式外,还可以使用RedirectAttributes形参的addFlushAttribute()携带方式。
5.2.1 通过Model形参携带参数
首先,修改login.jsp。将用户登录表单的提交方法修改为:checkLogin.action,即在处理登录之前交由处理器(Handler)的checkLogin方法对登录信息进行验证,具体代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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=UTF-8">
<title>用户登录</title>
</head>
<body>
<h3>用户登录</h3>
<form action="checkLogin.action" method="post">
<table width="300px;" border=1>
<tr>
<td>用户编号:</td>
<td><input type="text" name="userId" id="userId" /></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username" /></td>
</tr>
<tr>
<td>密 码:</td>
<td><input type="password" name="password" id="password" /></td>
</tr>
</table>
<br/>
<input type="submit" id="login_button" value="用户登录" />
</form>
</body>
</html>
然后,在处理器(Handler)中添加checkLogin方法,具体代码如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public String show(){
return "forward:/WEB-INF/jsp/user/login.jsp";
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/checkLogin")
public String checkLogin(User user, Model model){
model.addAttribute("userId",user.getUserId());
model.addAttribute("username",user.getUsername());
model.addAttribute("password",user.getPassword());
return "redirect:doLogin.action";
}
@RequestMapping("/doLogin")
public String doLogin(User user, RedirectAttributes redirectAttributes) throws UnsupportedEncodingException {
redirectAttributes.addAttribute("username",new String(user.getUsername().getBytes("iso8859-1"), "utf-8"));
redirectAttributes.addAttribute("userId",user.getUserId());
redirectAttributes.addAttribute("password",user.getPassword());
return "redirect:/welcome.jsp";
}
}
最后,将项目部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后通过请求转发跳转到登录页面。当用户填写信息提交表单后,表单交由处理器(Handler)中的checkLogin处理,在该方法中通过重定向的方式利用Model形参将参数传递给了doLogin方法,最终在doLogin方法中处理登录信息,通过重定向的方式跳转到welcome.jsp页面显示用户登录信息,提示登录成功。具体结果如下所示:
5.2.2 使用形参RedirectAttributes的addFlushAttribute()携带参数
RedirectAttributes形参的addFlushAttribute()携带方式不会将放入其中的属性值通过请求URL传递,所以其中可以存放任意对象。
addFlushAttribute()方法的传值的实现原理是:将其中数据临时性的放入到HttpSession中。一旦目标Controller接收到了这个数据,则系统会立即将这个放入到HttpSession中的数据删除。即刷新时会发现,这个数据已为空。
应用场景:适合于在各Controller间传递对象,但这个被传递的对象,不适合在页面显示。因为该对象数据时“昙花一现”的。
修改处理器(Handler)中的checkLogin方法和doLogin方法,具体代码如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public String show(){
return "forward:/WEB-INF/jsp/user/login.jsp";
}
@RequestMapping("/login")
public String login(){
return "user/login";
}
@RequestMapping("/checkLogin")
public String checkLogin(User user, RedirectAttributes redirectAttributes){
redirectAttributes.addFlashAttribute("user",user);
return "redirect:doLogin.action";
}
@RequestMapping("/doLogin")
public String doLogin(User user, RedirectAttributes redirectAttributes) throws UnsupportedEncodingException {
redirectAttributes.addAttribute("username",user.getUsername());
redirectAttributes.addAttribute("userId",user.getUserId());
redirectAttributes.addAttribute("password",user.getPassword());
return "redirect:/welcome.jsp";
}
}
再次将项目部署到Tomcat上后,按照之前的演示流程测试后,得到如下结果:
6、返回void时的请求转发
当处理器方法返回void时,若要实现请求转发,则需要使用HttpServletRequest的请求转发方法。无论下一级资源是页面还是Controller,用法相同。
不过,需要注意的是,若有数据需要向下一级资源传递,则需要昂数据放入到request或session中。不能讲数据放入到Model、RedirectAttributes中。因为它们中的数据都是通过拼接到处理器放上的返回值中,作为请求的一部分出现向下传递的。这里没有返回值,所以它们中的数据便无法向下传递了。
修改login.jsp页面如下所示:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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=UTF-8">
<title>用户登录</title>
</head>
<body>
<h3>用户登录</h3>
<form action="doLogin.action" method="post">
<table width="300px;" border=1>
<tr>
<td>用户编号:</td>
<td><input type="text" name="userId" id="userId" /></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username" /></td>
</tr>
<tr>
<td>密 码:</td>
<td><input type="password" name="password" id="password" /></td>
</tr>
</table>
<br/>
<input type="submit" id="login_button" value="用户登录" />
</form>
</body>
</html>
修改success.jsp页面如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<h2>登录成功!</br></br>欢迎您${user.username}!</h2>
</body>
</html>
修改处理器(Handler)如下:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public void show(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/jsp/user/login.jsp").forward(request,response);
}
@RequestMapping("/doLogin")
public void doLogin(User user, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doLogin");
request.setAttribute("user",user);
request.getRequestDispatcher("/WEB-INF/jsp/user/success.jsp").forward(request,response);
}
}
将项目部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action 后,由于用户此时并未登录,因此通过请求转发的方式跳转到登录页面(login.jsp),具体如下所示:
当用户填写登录信息并提交表单后,交由处理器(Handler)中的doLogin方法处理,在该方法中通过请求转发的方式将user对象作为参数传递到了welcome.jsp页面中,用来提示用户登录成功并显示用户信息,具体如下图所示:
7、返回void时的重定向
当处理器方法返回void时,若要实现重定向,则需要使用HttpServletResponse的重定向方法sendRedirect()。
不过,需要注意的是,若有数据需要向下一级资源传递,则需要将数据放入到session中。
修改welcome.jsp页面如下所示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>欢迎页</title>
</head>
<body>
<h2>【${user.username}】您好,您已经登录到首页!</h2>
</body>
</html>
修改处理器(Handler)如下所示:
package com.ccff.controller;
import com.ccff.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@Controller
@RequestMapping("/ForwardRedirectTest")
public class ForwardRedirectController {
@RequestMapping("/show")
public void show(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/jsp/user/login.jsp").forward(request,response);
}
@RequestMapping("/doLogin")
public void doLogin(User user, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
System.out.println("doLogin");
session.setAttribute("user",user);
response.sendRedirect(request.getContextPath() + "/welcome.jsp");
}
}
将项目部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/ForwardRedirectTest/show.action,首先处理器中的show方法会通过请求转发的方式跳转到登录页面,具体如下所示:
当用户输入登录信息提交表单后,处理器通过doLogin方法处理表单提交过来的数据,在该方法中通过重定向的方式将user对象作为参数传递给了welcome.jsp页面,用于显示用户登录信息,具体如图所示: