1 Response对象概述

方向: 服务器 -> 浏览器

负责对浏览器进行响应的对象

什么是响应: 服务器接收到请求需要进行处理,将处理以后的结果显示回浏览器端(将这个过程称为是响应Response)。

  • 查看Servlet中的service方法得知, Servlet中使用的ServletResponse接口, 而我们使用的是ServletResponse的子接口HttpServletResponse, 它继承自ServletResponse, 是与HTTP协议相关的Response响应对象
  • 我们使用的子接口HttpServletResponse, 此接口对象由Tomcat引擎提供
  • 可以实现对客户端的响应, 响应内容包括: 响应行,响应头,响应体
    其中设置响应行可以设置返回的状态码
    而设置返回头就可以设置给浏览器的指导信息,而通过响应头和响应体的组合可以设置重定向的操作(当然也有直接的命令可以使用)
    而设置响应体则是设置给浏览器显示的内容

2 Response设置响应行

方法

返回值

描述

setStatus(int sc)

void

设置响应的状态码

  • 设置响应的状态码
  • 200 正确
  • 302 重定向
  • 304 查找本地缓存
  • 404 请求资源不存在
  • 500 服务器内部错误
response.setStatus(500);

3 Response设置响应头

HTTP协议的响应头,数据格式键值对 k:v

包含指导性信息,指导客户端

方法

返回值

描述

addHeader(String key,String value)

void

添加响应头,值为String类型

addIntHeader(String key,int value)

void

添加响应头,值为int类型

addDateHeader(String key,long l)

void

添加响应头,值为日期类型

setHeader(String key,String value)

void

更改响应头,值为String类型

setIntHeader(String key,int value)

void

更改响应头,值为int类型

setDateHeader(String key,long l)

void

更改响应头,值为日期类型

  • add开头的方法:针对一个key对应多个value的情况。
比如已有一个响应头 heima:java
然后执行 addHeader(“heima”,”java2222”);
最终得到响应头的结果:heima:java,java2222
  • set开头的方法:针对一个key对应一个value的情况。
比如已有一个响应头 heima:java
然后执行 setHeader(“heima”,”java2222”);
最终得到响应头的结果:heima:java2222

演示:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    /*
     * response对象设置响应头
     */
    response.addHeader("heima","java");
  /*  response.addIntHeader("heima2",5);
    response.addDateHeader("date",System.currentTimeMillis());*/
    /*
     * addHeader() 添加,实现一个键对应多个值
     * setHeader() 设置,原来的键覆盖
     */
    response.setHeader("heima","java2222");
}

4 重定向

HTTP中的重定向和请求转发的区别
一、调用方式

我们知道,在servlet中调用转发、重定向的语句如下:

request.getRequestDispatcher("new.jsp").forward(request, response);//转发到new.jsp response.sendRedirect("new.jsp");//重定向到new.jsp

在jsp页面中你也会看到通过下面的方式实现转发:

<jsp:forward page="apage.jsp" />

当然也可以在jsp页面中实现重定向:

<%response.sendRedirect("new.jsp");//重定向到new.jsp%>

二、本质区别
解释一

一句话,转发是服务器行为,重定向是客户端行为。为什么这样说呢,这就要看两个动作的工作流程:

转发过程:客户浏览器发送http请求----》web服务器接受此请求–》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。

重定向过程:客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器–》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。

解释二
重定向,其实是两次request,
第一次,客户端request A,服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。

请求转发是服务器内部把对一个request/response的处理权,移交给另外一个
对于客户端而言,它只知道自己最早请求的那个A,而不知道中间的B,甚至C、D。 传输的信息不会丢失。

解释三

假设你去办理某个执照,

重定向:你先去了A局,A局的人说:“这个事情不归我们管,去B局”,然后,你就从A退了出来,自己乘车去了B局。

转发:你先去了A局,A局看了以后,知道这个事情其实应该B局来管,但是他没有把你退回来,而是让你坐一会儿,自己到后面办公室联系了B的人,让他们办好后,送了过来。

4.1 重定向的写法

浏览器进行重新的定向:

  • 设置302状态码: setStatus(302)
  • 设置重定向资源的地址: setHeader(“location”,“资源”)

通过HttpServletResponse对象中的以下方法实现重定向

方法

返回值

描述

sendRedirect(String location)

void

重定向

4.2 重定向的代码实现

package cn.itcast.web;

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;

@WebServlet("/demo07")
public class ServletDemo07 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 解决服务器给浏览器的数据中文乱码问题
        response.setContentType("text/html;charset=utf-8");

        System.out.println("77777777777777777777777");

        // 需求: 演示重定向: 访问 demo07 跳转到 demo08
        // 方式一: 分解式
        // 1 设置状态码 为 302 , 通知浏览器访问新资源
        // response.setStatus(302);
        // 2 设置响应头 location, 通知浏览器访问新资源的路径
        // 新资源的路径 可以使 项目内的资源,也可以是项目外的资源
        // response.setHeader("location", "/web0201/demo08");

        // 方式二: 合并式
        response.sendRedirect("/web0201/demo08");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

5 Response设置响应体

HTTP的响应体,就是页面的正文部分
不能同时使用字符流和字节流,二者只能选其一,否则程序会报错

5.1 字符流向浏览器写数据

方法

返回值

描述

write()

PrintWriter

使用字符串数据,没有差别, 输出是整数,查询编码表

print()

PrintWriter

无论是什么,原样打印

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    /*
     * response对象方法getWriter()
     * 打印流的响应体
     * write() 使用字符串数据,没有差别, 输出是整数,查询编码表
     * print() 无论是什么,原样打印
     */
     PrintWriter pw =  response.getWriter();
     pw.write(100);
     pw.print(100);
}

5.2 字符流的中文乱码问题

产生乱码原因: 编码和解码不一致

提问:在Servlet中编写以下代码,向页面输出中文是否会产生乱码?

response.getWriter().print("中文");

会乱码:

  • 原因:
  • 字符流是有缓冲区的,response获得字符流,response设计默认的缓冲区编码是ISO-8859-1。这个字符集不支持中文的。
  • 解决:
  • 设置response获得字符流缓冲区的编码 与 设置浏览器默认打开时候采用的字符集一致即可。

方法

放回值

描述

setHeader(“Content-Type”, “text/html;charset=UTF-8”)

void

设置浏览器打开页面时采用的字符集

setContextType(String type)

void

设置浏览器打开页面时采用的字符集

// 设置浏览器默认打开的时候采用的字符集:
// response.setHeader("Content-Type", "text/html;charset=UTF-8");
// 简化代码
response.setContentType("text/html;charset=UTF-8");
// 输出中文汉字
response.getWriter().println("中文");

5.3 字节流向浏览器写数据

方法

返回值

描述

getOutputStream()

OutputStream

返回字节输出流OutputStream,响应非文本类型的数据

5.3.1 案例 验证码

验证码的本质是个图片,图片里面是个随机生成字符串

随机字符串的思想:
String str ="abcdefABCDE1234567890";
Random.nextInt(  str.length() )产生整数随机数
str.charAt(索引)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        function changeImg(){
            // 1 获取验证码图片对象
            var codeImgObj = document.getElementById("codeImg");
            // 2 修改图片的路径
            // ?key=val 目的: 欺骗浏览器这是一个新资源
            codeImgObj.src = "/web0202/demo11?r=" + Math.random();
        }
    </script>
</head>
<body>
    <form action="xx" method="post">
        <table>
            <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="text" name="code_form"/>
                    <img src="/web0202/demo11" onclick="changeImg()" id="codeImg"/>
                </td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="提交"/></td>
            </tr>
        </table>
    </form>
</body>
</html>
package cn.itcast.web;

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;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/demo11")
public class ServletDemo11 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 解决服务器给浏览器的数据中文乱码问题
        // response.setContentType("text/html;charset=utf-8");

        // 1 创建画布对象
        int width = 120;
        int height = 40;
        BufferedImage bufi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 3 获取画笔
        Graphics g = bufi.getGraphics();

        // 4 修改背景色
        g.fillRect(0, 0, width, height);

        // 5 绘制边框
        g.setColor(Color.red);
        g.drawRect(0, 0, width-1, height-1);

        // 6 生成随机字符 且 显示
        // 6.1 准备数据
        String data = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz123456789";
        // 6.2 创建随机对象
        Random r = new Random();
        // 7.1 准备变量保存 生成的 随机字符
        String code = "";
        // 6.3 循环输出
        for (int i = 0; i < 4; i++) {
            // 6.3.2 设置字体
            g.setFont(new Font("楷体", Font.BOLD, 30));

            // 6.3.3 设置随机颜色
            g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));

            // 6.3.1 绘制字符
            char c = data.charAt(r.nextInt(data.length()));
            g.drawString(c + "", 10 + i * 30, 30);

            // 7.1 将生成的随机字符 保存到 随机字符串中
            code += c +"";
        }

        // 7 将生成的字符输出到控制台
        System.out.println(code);

        // 8 绘制干扰线
        for (int i = 0; i < 10; i++) {
            // 8.2 设置随机颜色
            g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
            // 8.1 绘制干扰线
            g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
        }

        // 2 将画布输出到浏览器中
        ImageIO.write(bufi, "jpg", response.getOutputStream());
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}