Servlet重定向
重定向属于客户端行为。服务器在收到客户端请求后,会通知客户端浏览器重新向另外一个 URL 发送请求,这称为请求重定向。它本质上是两次 HTTP 请求,对应两个 request 对象和两个 response 对象。
	
	
		
	
		
在 responseDemo 的 WebContent 中,创建登录页面 login.html,代码如下。
在 net.biancheng.www 包下,创建名称为 CheckcodeServlet 的 Servlet 类,代码如下。
在 net.biancheng.www 包下,创建名称为 DoServlet 的 Servlet 类,代码如下。
在 net.biancheng.www 包下,创建名称为 RefreshServlet 的 Servlet 类,代码如下。
在 net.biancheng.www 包下,创建名称为 SuccessServlet 的 Servlet 类,代码如下。
启动 Tomcat,在地址栏输入“http://localhost:8080/responseDemo/login.html”,访问登录页,如下图所示。
	
在登录页面输入账号、密码、验证码等信息(该实例中没有使用数据库,所以当账号和密码都为 admin 时验证成功,否则验证失败),这里我们输入错误的验证码点击提交按钮,结果如下图。
	
点击提交按钮,结果如下图,倒计时完成后,自动跳转到登录页面。
	
输入正确信息,点击提交,结果如下图。
	
			
			
		重定向的工作流程
重定向的工作流程如下:
- 用户在浏览器中输入 URL,请求访问服务器端的 Web 资源。
 - 服务器端的 Web 资源返回一个状态码为 302 的响应信息,该响应的含义为:通知浏览器再次发送请求,访问另一个 Web 资源(在响应信息中提供了另一个资源的 URL)。
 - 当浏览器接收到响应后,立即自动访问另一个指定的 Web 资源。
 - 另一 Web 资源将请求处理完成后,由容器把响应信息返回给浏览器进行展示。
 
转发和重定向的区别
转发和重定向都能实现页面的跳转,但是两者也存在以下区别。| 区别 | 转发 | 重定向 | 
|---|---|---|
| 浏览器地址栏 URL 是否发生改变 | 否 | 是 | 
| 是否支持跨域跳转 | 否 | 是 | 
| 请求与响应的次数 | 一次请求和一次响应 | 两次请求和两次响应 | 
| 是否共享 request 对象和 response 对象 | 是 | 否 | 
| 是否能通过 request 域对象传递数据 | 是 | 否 | 
| 速度 | 相对要快 | 相对要慢 | 
| 行为类型 | 服务器行为 | 客户端行为 | 
response.sendRedirect()
HttpServletResponse 接口中的 sendRedirect() 方法用于实现重定向。| 返回值类型 | 方法 | 描述 | 
|---|---|---|
| void | sendRedirect(String location) | 向浏览器返回状态码为 302 的响应结果,让浏览器访问新的 URL。若指定的 URL 是相对路径,Servlet 容器会将相对路径转换为绝对路径。参数 location 表示重定向的URL。 | 
示例
下面我们通过一个案例加深对 response 对象和重定向的理解。在 responseDemo 的 WebContent 中,创建登录页面 login.html,代码如下。
<!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>Insert title here</title>
</head>
<body>
<form action="/responseDemo/DoServlet" method="GET">
    <table border="1" width="50%">
        <tr>
            <td colspan="2" align="center">
                编程帮wwww.biancheng.net
            </td>
        </tr>
        <tr>
            <td>账号</td>
            <td>
                <input type="text" name="username"/>
            </td>
        </tr>
        <tr>
            <td>密码</td>
            <td>
                <input type="password" name="password"/>
            </td>
        </tr>
        <tr>
            <td>选择性别</td>
            <td>
                <input type="radio" name="sex" value="男"/>男
                <input type="radio" name="sex" value="女"/>女
            </td>
        </tr>
        <tr>
            <td>选择使用的语言</td>
            <td>
                <input type="checkbox" name="language" value="JAVA"/>JAVA
                <input type="checkbox" name="language" value="C语言"/>C语言
                <input type="checkbox" name="language" value="PHP"/>PHP
                <input type="checkbox" name="language" value="Python"/>Python
            </td>
        </tr>
        <tr>
            <td>选择城市</td>
            <td>
                <select name="city">
                    <option value="none">--请选择--</option>
                    <option value="北京">北京</option>
                    <option value="北京">上海</option>
                    <option value="广州">广州</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>验证码</td>
            <td><input type="text" name="code"/>
                <img id="imgId" src="/responseDemo/CheckcodeServlet">
                <a href="#" onclick="run()">看不清,换一张</a>
            </td>
        </tr>
        <tr>
            <td colspan="2" align="center">
                <input type="submit" value="提交"/>
            </td>
        </tr>
    </table>
</form>
</body>
<script type="text/javascript">
    // 看不清,换一张,时间戳
    function run() {
        // 获取图片
        var image = document.getElementById("imgId");
        image.src = "/responseDemo/CheckcodeServlet?" + new Date().getTime();
    }
</script>
</html>
在 net.biancheng.www 包下,创建名称为 CheckcodeServlet 的 Servlet 类,代码如下。
package net.biancheng.www;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 使用 Java 生成验证码图片
* 了解即可
* 可将 demo保存直接使用
* 并通过 response 对象展示在页面上
*
* @author 编程帮 www.biancheng.net
*/
@WebServlet("/CheckcodeServlet")
public class CheckcodeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int width = 120;
        int height = 30;
        // 在内存中生成图片
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 先获取画笔对象
        Graphics2D g = (Graphics2D) image.getGraphics();
        // 设置灰色
        g.setColor(Color.GRAY);
        // 画填充的矩形
        g.fillRect(0, 0, width, height);
        // 设置颜色
        g.setColor(Color.BLUE);
        // 画边框
        g.drawRect(0, 0, width - 1, height - 1);
        // 准备数据,随机获取4个字符
        String words = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        // 设置颜色
        g.setColor(Color.YELLOW);
        // 设置字体
        g.setFont(new Font("隶书", Font.BOLD, 20));
        String code = "";
        //构造存储字符的数组
        char[] a = {};
        //构造存储字符串的集合
        List<String> list = new ArrayList<String>();
        Random random = new Random();
        int x = 20;
        int y = 20;
        for (int i = 0; i < 4; i++) {
            // void rotate(double theta, double x, double y)
            // theta 弧度
            // hudu = jiaodu * Math.PI / 180;
            // 获取正负30之间的角度
            int jiaodu = random.nextInt(60) - 30;
            double hudu = jiaodu * Math.PI / 180;
            g.rotate(hudu, x, y);
            // 获取下标
            int index = random.nextInt(words.length());
            // 返回指定下标位置的字符,随机获取下标
            char ch = words.charAt(index);
            //将字符存入字符数组中
            char[] chc = {ch};
            //使用字符数组构造字符串
            String string = new String(chc);
            //将构造好的字符串添加进list集合中
            list.add(string);
            // 写字符串
            g.drawString("" + ch, x, y);
            g.rotate(-hudu, x, y);
            x += 20;
        }
        for (int i = 0; i < list.size(); i++) {
            code += list.get(i);
        }
        //将验证码存入上下文中
        getServletContext().setAttribute("code", code);
        // 设置颜色
        g.setColor(Color.GREEN);
        int x1, x2, y1, y2;
        // 画干扰线
        for (int i = 0; i < 4; i++) {
            x1 = random.nextInt(width);
            y1 = random.nextInt(height);
            x2 = random.nextInt(width);
            y2 = random.nextInt(height);
            g.drawLine(x1, y1, x2, y2);
        }
        // 输出到客户端
        ImageIO.write(image, "jpg", response.getOutputStream());
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
在 net.biancheng.www 包下,创建名称为 DoServlet 的 Servlet 类,代码如下。
package net.biancheng.www;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 验证提交的信息
* @author 编程帮 www.biancheng.net
*/
@WebServlet("/DoServlet")
public class DoServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置向页面输出内容格式
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        String username = request.getParameter("username");
        // 获取密码
        String password = request.getParameter("password");
        // 获取性别
        String sex = request.getParameter("sex");
        // 获取城市
        String city = request.getParameter("city");
        // 获取爱好    返回是String数组
        String[] languages = request.getParameterValues("language");
        //获取验证码
        String code = request.getParameter("code");
        //设置是否成功标识
        Boolean IsSuccess = true;
        //从上下文获取存储的验证码
        String code1 = (String) getServletContext().getAttribute("code");
        //账号密码为admin.且验证码(忽略大小写)输入正确,则跳转到登陆成功页面
        if (!"".equals(code) && code != null && code.equalsIgnoreCase(code1) && "admin".equals(username) && "admin".equals(password)) {
            response.sendRedirect("/responseDemo/Success");
            //账号密码不为admin,设置错误信息
        } else if (!"admin".equals(username) || !"admin".equals(password)) {
            getServletContext().setAttribute("msg", "账号或密码不正确");
            IsSuccess = false;
            //验证码错误,设置错误信息
        } else if ("".equals(code) || code == null || !code.equalsIgnoreCase(code1)) {
            getServletContext().setAttribute("msg", "验证码输入错误");
            IsSuccess = false;
        }
        if (!IsSuccess) {
            //设置自动跳转的时间,存储在上下文中
            getServletContext().setAttribute("time", 5);
            //向request对象中设置属性requestAttr,在重定向之后取值。  
            request.setAttribute("requestAttr", "重定向中使用request域对象传递的数据");
            response.sendRedirect("/responseDemo/RefreshServlet");
        }
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
在 net.biancheng.www 包下,创建名称为 RefreshServlet 的 Servlet 类,代码如下。
package net.biancheng.www;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* 登录失败后,提示错误信息并定时跳转回登录页
* 通过设置响应头字段(refresh)实现页面的定时跳转
*
* @author 编程帮 www.biancheng.net
*/
@WebServlet("/RefreshServlet")
public class RefreshServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Object requestAttr = request.getAttribute("requestAttr");
        //获取存在上下文中的跳转时间
        int times = (int) getServletContext().getAttribute("time");
        //获取存在上下文中的错误信息
        String msg = (String) getServletContext().getAttribute("msg");
        /**
         *
         * 设置三个头信息,禁用浏览器缓存
         * Cache-Control : no-cache
         * Expires: -1 值是日期类型(setDateHeader())
         *     Pragma : no-cache
         */
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", -1);
        //
        response.setContentType("text/html;charset=UTF-8");
        //设置提示
        String title = msg + ",即将在" +
                times + "秒钟后跳转到登录页";
        //使用默认时区和语言环境获得一个日历
        Calendar cale = Calendar.getInstance();
        //将Calendar类型转换成Date类型
        Date tasktime = cale.getTime();
        //设置日期输出的格式
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //格式化输出
        String nowTime = df.format(tasktime);
        //只要倒计时时间没有到0,就直至输出下面内容
        if (times != 0) {
            response.getWriter().write("<html>\n" +
                    "<head><title >" + title + "</title></head>\n" +
                    "<body bgcolor=\"#f0f0f0\">\n" +
                    "<h1 align=\"center\">编程帮  www.biancheng.net  提醒您:</h1>" +
                    "<h1 align=\"center\" style=\"font-family:arial;color:red;\">" + title + "</h1>\n" +
                    "<h1 align=\"center\">当前时间 是:" + nowTime + "</h1>\n" +
                    "<h1 align=\"center\">重定向通过request传递的数据为:" + requestAttr + "</h1>\n");
            //倒计时
            times--;
            //将倒计时的时间重新存入上下文中覆盖原来的值
            getServletContext().setAttribute("time", times);
            // 通过refresh头完成页面刷新
            response.setHeader("refresh", "1;url=/responseDemo/RefreshServlet");
        } else {
            //倒计时归零,则跳转到登陆页面
            response.sendRedirect("/responseDemo/login.html");
        }
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}
在 net.biancheng.www 包下,创建名称为 SuccessServlet 的 Servlet 类,代码如下。
package net.biancheng.www;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录成功
* @author 编程帮 www.biancheng.net
*/
@WebServlet("/Success")
public class SuccessServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置响应输出的格式
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write("<h1>登录成功</h1>");
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
启动 Tomcat,在地址栏输入“http://localhost:8080/responseDemo/login.html”,访问登录页,如下图所示。

在登录页面输入账号、密码、验证码等信息(该实例中没有使用数据库,所以当账号和密码都为 admin 时验证成功,否则验证失败),这里我们输入错误的验证码点击提交按钮,结果如下图。

点击提交按钮,结果如下图,倒计时完成后,自动跳转到登录页面。

输入正确信息,点击提交,结果如下图。

 ICP备案:
 公安联网备案: