Response☔

Response☔


一、HTTP协议:响应消息

1. 数据格式

  • 请求消息

    • 数据格式
      • 请求行
      • 请求头
      • 请求空行
      • 请求体
  • 响应消息:服务器端发送给客户端的数据

    • 数据格式
      • 响应行
      • 响应头
      • 响应空行
      • 响应体
  • 响应字符串格式

    HTTP/1.1 200 OK
    Content-Type: text/html;charset=UTF-8
    Content-Length: 167
    Date: Wed, 18 Aug 2021 08:46:44 GMT

    <!DOCTYPE html>
    <html>
    <head>
      <title>JSP - Hello World</title>
    </head>
    <body>
    <h1>Hello World!</h1>
    <br/>
    <a href="hello-servlet">Hello Response</a>
    </body>
    </html>
    

2. 响应行

  1. 组成:协议/版本 响应状态码 状态码描述
  2. 响应 状态码 :服务器告诉客户端浏览器本次请求和响应的状态
    • 状态码都是3位数字
    • 分类:
      1. 1xx:服务器接收客户端消息,但没有接受完成,等待一段时间后,发送1xx状态码(询问客户端,还要不还要发消息)
      2. 2xx:成功。代表:200
      3. 3xx:重定向。代表:302(重定向);304(访问缓存)
      4. 4xx:客户端错误。
        • 代表:
          • 404(请求路径没有对应的资源)
          • 405(请求方式没有对应的doXxx()方法,如,没有doGet方法,却使用get方法访问)
      5. 5xx:服务器端错误。代表:500(服务器端出现异常)

3. 响应头

  1. 格式:头名称:值
  2. 常见的响应头:
    1. Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
    2. Content-disposition:服务器告诉客户端以什么格式打开响应体数据
      • 值:
        • in-line:默认值,在当前页面内打开
        • attachment;filename=xxx:以附件形式打开响应体。文件下载

4. 响应体

真实的传输的数据

二、Response对象

1. 功能

功能:设置响应消息

  1. 设置响应行
    1. 格式:HTTP/1.1 200 ok
    2. 设置状态码:void setStatus(int sc)
  2. 设置响应头
    1. 设置头:void setHeader(String name, String value)
  3. 设置响应体
    1. 使用步骤
      1. 获取输出流
        • 字符输出流:PrintWriter getWriter()
        • 字节输出流:ServletOutputStream getOutputStream()
      2. 使用输出流,将输出流输出到客户端浏览器

2. 案例

2.1 完成重定向

在这里插入图片描述

  1. 重定向:资源跳转的方式

  2. 代码实现(2种方式)

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo01被访问了");
        // 访问这个资源,会自动跳转到demo02
        // 1. 设置状态码为302
    //        response.setStatus(302);
        // 2. 设置响应头location
        // 获取虚拟目录
    //        String contextPath = request.getContextPath();
    //        System.out.println(contextPath);
    //        response.setHeader("location", request.getContextPath() + "/responseDemo02");
    
        // 简单的重定向方法
        response.sendRedirect(request.getContextPath() + "/responseDemo02");
    
    }
    
  3. 重定向的特点:redirect

    1. 重定向地址栏路径发生变化
    2. 重定向可以访问其他站点(服务器)的资源
    3. 重定向是两次请求 (重要)。不能使用request对象来共享数据了
  4. 转发的特点:forward

    1. 转发地址栏路径不变
    2. 转发只能访问当前服务器下的资源
    3. 转发是一次请求,可以使用request对象来共享数据
  5. == 面试题:forward和redirect的区别 ==

  6. 路径的写法

    1. 路径的分类

      1. 相对路径

        • 通过相对路径不可以确定唯一值资源
        • 如:./index.html。以.开头
        • 规则:找到当前资源和目标资源之间的相对位置关系
          • ./:当前目录
          • …/:后退一级目录
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
        <h1>找到当前资源和目标资源之间的相对位置关系</h1>
        <p>
            当前资源:location.html
            http://localhost/Response/location.html
        </p>
        <p>
            目标资源:ResponseDemo02.java
            http://localhost/Response/responseDemo02
        </p>
        <a href="./responseDemo02">
            responseDemo02
        </a>
        <br>
        
        <a href="responseDemo02">
            responseDemo02
        </a>
        </body>
        </html>
        
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
        <h1>找到当前资源和目标资源之间的相对位置关系</h1>
        <p>
            当前资源:location2.html
            http://localhost/Response/htmls/location2.html
        </p>
        <p>
            目标资源:ResponseDemo02.java
            http://localhost/Response/responseDemo02
        </p>
        <a href="../responseDemo02">
            responseDemo02
        </a>
        </body>
        </html>
        
      2. 绝对路径

        • 通过绝对路径可以确定唯一资源,如:http://localhost/Response/responseDemo02
        • 以/开头的路径成为绝对路径
        • 规则:判断定义的路径给谁用的?判断请求将来从哪里发出
          • 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
            • 建议虚拟目录动态获取:request.getContextPath()
            • , , 重定向
          • 给服务器使用:不需要加虚拟目录
            • 转发路径
2.2 服务器输出字符数据到浏览器
  1. 步骤:
    1. 获取字符输出流
    2. 输出数据
  2. 注意乱码问题
    1. 原因:编解码不一致
    2. PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1
    3. 设置该流的默认编码,以及高速浏览器响应体使用的编码:response.setContentType("text/html;charset=utf-8");
2.3 服务器输出字节数据到浏览器

步骤:

  1. 获取字节输出流
  2. 输出数据
2.4 验证码
  1. 本质:图片
  2. 目的:防止恶意表单注册
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    int width = 100;
    int height = 50;
    // 1.创建一个对象,在内存中代表一个图片(验证码的图片对象)
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    // 2.美化图片
    // 2.1背景色
    Graphics g = image.getGraphics(); //画笔对象
    g.setColor(Color.pink); //设置画笔颜色
    g.fillRect(0, 0, width, height);
    // 2.2花边框
    g.setColor(Color.BLUE);
    g.drawRect(0, 0, width - 1, height - 1);
    // 2.3写验证码
    String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    // 创建随机角标
    Random r = new Random();
    int location = 20;
    for (int i = 0; i < 4; i++) {
        int index = r.nextInt(str.length());
        // 获取随机字符
        char ch = str.charAt(index);
        g.drawString(String.valueOf(ch), location * (i + 1), 25);
    }
    // 2.4花干扰线
    g.setColor(Color.green);
    // 随机生成10条线
    for (int i = 0; i < 10; i++) {
        g.drawLine(r.nextInt(width), r.nextInt(width), r.nextInt(height), r.nextInt(height));
    }
    // 3.将图片输出到页面展示
    ImageIO.write(image, "jpg", response.getOutputStream());
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        /*
            点击超链接或图片,换一张图
            1. 给超链接或图片,绑定单击事件
            2. 重新设定图片的src属性值
         */
        window.onload = function () {
            // 获取图片对象
            var img = document.getElementById("checkCode");
            img.onclick = function () {
                // 加时间戳
                var date = new Date().getTime();
                img.src = "/Response/checkCodeServlet?" + date;
            };
            var a = document.getElementById("refresh");
            a.onclick = function () {
                // 加时间戳
                var date = new Date().getTime();
                img.src = "/Response/checkCodeServlet?" + date;
            };
        };
    </script>
</head>
<body>
<img src="/Response/checkCodeServlet" alt="" id="checkCode">
<a href="javascript:void(0)" id="refresh">看不清?换一张</a>
</body>
</html>

三、ServletContext对象

1. 概念和获取

1.1 概念

代表整个web应用,可以和程序的容器(服务器)通信

1.2 获取
  1. 通过request对象获取:request.getServletContext();
  2. 通过HttpServlet获取:this.getServletContext();

2. 功能

2.1 获取MIME类型

在互联网通信过程中定义的一种文件数据类型

  • 格式:大类型/小类型 text/html image/jpeg
  • 获取:String getMimeType(String file)
2.2 域对象(共享数据)
  1. setAttribute(String name, Object value):存储数据(键值对)
  2. getAttribute(String name):通过键获取值
  3. removeAttribute(String name):通过键移除键值对

ServletContext的范围:所有用户请求的数据

2.3 获取文件的真实(服务器)路径

在这里插入图片描述

  1. 方法很重要String getRealPath(String path)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    // 获取文件的服务器路径
    String realPath = context.getRealPath("/b.txt"); //web目录下资源访问
    System.out.println(realPath);
//        File file = new File(realPath);
    String realPath1 = context.getRealPath("/WEB-INF/c.txt"); // WEB-INF目录下的文件访问
    System.out.println(realPath1);
    String a = context.getRealPath("/WEB-INF/classes/a.txt");
    System.out.println(a); // resources目录下的
}

在这里插入图片描述

3. 案例

文件下载需求:

  1. 页面显示超链接
  2. 点击超链接后弹出下载提示框
  3. 完成图片文件下载

分析:

  1. 超链接指向的资源,如果能被浏览器解析则展示;如果不能解析,则弹出下载提示框。现在不满足需求
  2. 任何资源都必须弹出下载提示框
  3. 使用响应头,来设置资源的打开方式
    • content-disposition:attachment;filename=xxx

步骤

  1. 定义页面,编辑超链接href属性,只想Servlet,传递资源名称filename
  2. 定义servlet
    1. 获取文件的名称
    2. 使用字节输入流加载文件进内存
    3. 指定response的响应头:content-disposition:attachment;filename=xxx
    4. 将数据写出到response输出流

问题:

  • 中文文件名问题解决思路
    1. 获取客户端使用的浏览器版本信息
    2. 根据不同的版本信息,设置filename的编码方式不同
@WebServlet(name = "Test01Download", value = "/test01Download")
public class Test01Download extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*// 获取文件名
        String filename = request.getParameter("filename");
        // 找到该图片所在服务器的路径
        ServletContext context = this.getServletContext();
        String realPath = context.getRealPath("/images/" + filename);
//        System.out.println(realPath);

        // 设置响应头类型content-type
        String mimeType = context.getMimeType(filename); // 获取文件的MIME类型
        response.setHeader("content-type",mimeType);
        // 指定response的响应头:content-disposition:attachment;filename=xxx
        response.setHeader("content-disposition", "attachment;filename=" + filename);

        // 用字节流关联
        FileInputStream fis = new FileInputStream(realPath);
        // 将数据写出到response输出流
        ServletOutputStream sos = response.getOutputStream();
        byte[] bys = new byte[1024 * 8];
        int len;
        while ((len = fis.read(bys)) != -1) {
            sos.write(bys, 0, len);
        }
        fis.close();*/

        // 从html中的请求体中获取文件名称
        String filename = request.getParameter("filename");
        System.out.println(filename);
        // 找到该资源在服务器中的位置
        ServletContext context = this.getServletContext();
        // 设置字节输入流,将文件读取到内存中
        String realPath = context.getRealPath("/images/" + filename);
        FileInputStream fis = new FileInputStream(realPath);
        // 设置两个响应头
        // 解决中文文件名的问题
        // 1.获取user-agent响应头
        String agent = request.getHeader("user-agent");
        // 2.使用工具类方法编码文件名即可
        filename = DownLoadUtils.getFileName(agent, filename);
        System.out.println(filename);
        response.setHeader("content-type", context.getMimeType(filename));
        response.setHeader("content-disposition", "attachment;filename=" + filename);
        // 字节对流
        ServletOutputStream sos = response.getOutputStream();
        byte[] bys = new byte[1024 * 8];
        int len;
        while ((len = fis.read(bys)) != -1) {
            sos.write(bys, 0, len);
        }
    }

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

工具类:

package utils;

import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;


public class DownLoadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值