Spring MVC使用篇(十)—— 请求转发与重定向

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页面,用于显示用户登录信息,具体如图所示:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值