Response详解

Mr.he...大约 6 分钟JavaWebResponse

1. 功能

设置响应消息,包括响应行、响应头、响应体的数据。

2. 设置响应行

主要是来设置状态码,使用setStatus(int sc)方法。

3. 设置响应头

使用setHeader(String name, String value)方法。

4. 设置响应体

  1. 获取输出流;

    • 字符输出流,使用PrintWriter getWriter()方法;
    • 字节输出流,使用ServletOutputStream getOutputStream()方法。
  2. 使用输出流,将数据输出到客户端浏览器。

5. Response的更多使用

5.1. 重定向

5.1.1. 概念

资源跳转的一种方式。

5.1.2. 使用

  • 核心代码:
//重定向,访问 /responseDemo1 路径会自动跳转到 /responseDemo2 路径。
/*
//1.设置状态码为302
resp.setStatus(302);
//2.设置响应头location
resp.setHeader("location","/today/responseDemo2");
*/
//更简单的重定向,一般都使用该种方式
resp.sendRedirect("/today/responseDemo2");

请求转发是一种在服务器内部的资源跳转方式。

这里需要和请求转发区分开:请求转发的路径不会变,状态码为200,拥有共享域对象,只能在服务器内部进行跳转;重定向的路径会变,状态码为302,没有共享域对象,可跳转服务器内部和外部的资源。

5.1.3. 重定向和转发的区别

5.1.3.1. 重定向(redirect)
  1. 地址栏发生变化,状态码为302;
  2. 重定向可以访问当前服务器内部和其他站点(服务器外部)的资源;
  3. 重定向是两次请求,有两个request对象,不能使用request对象来共享数据;
  4. 路径需要加虚拟目录。
5.1.3.2. 转发(forward)
  1. 转发地址栏路径不变,状态码为200;
  2. 转发只能访问当前服务器内部的资源;
  3. 转发是一次请求,可以使用request对象来共享数据;
  4. 路径不需要加虚拟目录。

请求转发的更多解析可到文章servlet&http&request中的[请求转发]({% post_path 'JavaWEB-4.Servlet&HTTP&Request-note' %}#请求转发)查看。

5.2. 服务器输出字符数据(String)到浏览器

5.2.1. 使用步骤

  1. 获取字符输出流
  2. 输出数据

一般用于服务器输出文本信息、HTML代码块到浏览器。

5.2.2. 乱码问题

  1. PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1;
  2. 设置该流的默认编码;
  3. 告诉浏览器响应体使用的编码。

简单的形式设置编码,是在获取流之前设置,使用代码:response.setContentType("text/html;charset=utf-8");

5.2.3. 核心代码

package io.gitee.hek97.web.servlet;
//去掉了导包的代码

@WebServlet("/responseDemo3")
public class ResponseDemo3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取流对象之前,设置流的编码
        //response.setCharacterEncoding("utf-8");该行可省略,下一行设置响应头中编码的代码会间接设置流的编码。
        //告诉浏览器,服务器发送的消息体数据的编码,建议浏览器使用该编码解码,这里使用的是设置响应头中编码的方法
        response.setHeader("content-type","text/html;charset=utf-8");
        //1.获取字符输出流
        PrintWriter pw = response.getWriter();
        //2.输出数据
        pw.write("你好,response");
    }

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

5.3. 服务器输出字节数据(Byte)到浏览器

5.3.1. 使用步骤

  1. 获取字节输出流
  2. 输出数据

一般用于从服务器输出图片到浏览器。

5.3.2. 核心代码

package io.gitee.hek97.web.servlet;

//省略导包代码

@WebServlet("/responseDemo4")
public class ResponseDemo4 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置响应消息编码
        response.setHeader("content-type","text/html;charset=utf-8");
        //1.获取字节输出流
        ServletOutputStream sos = response.getOutputStream();
        //2.输出数据
        sos.write("你好".getBytes("utf-8"));
    }

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

5.4. 练习:验证码

本质就是一张图片,为了防止恶意表单注册。

5.4.1. 使用步骤

  1. 在内存中生成一张图片
  2. 美化图片
  3. 输出图片

5.4.2. 核心代码

package io.gitee.hek97.web.servlet;

//去除导包代码

@WebServlet("/demo")
public class CheckCodeServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int width = 100;
        int height = 50;
        //1.创建对象,在内存中存图片(验证码)对象
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
        //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);//设置边框范围
        String str ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        //生成随机角标
        Random ran = new Random();//获取随机数对象
        for (int i = 1; i <= 4; i++) {
            int index = ran.nextInt(str.length());//生成随机数
            char ch = str.charAt(index);//获取相应位置的字符
            //2.3写验证码
            g.drawString(ch+"",width/5*i,height/2);
        }
        //2.4画干扰线
        g.setColor(Color.GREEN);//设置画笔颜色
        //画10条干扰线
        for (int i = 0; i < 10; i++) {
            //随机生成坐标点
            int x1=ran.nextInt(width);
            int x2=ran.nextInt(width);
            int y1=ran.nextInt(height);
            int y2=ran.nextInt(height);
            //画1条干扰线
            g.drawLine(x1,x2,y1,y2);
        }
        //3.将图片输出到页面展示
        ImageIO.write(image,"jpg",response.getOutputStream());
    }

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

5.4.3. 使用代码

在网页中使用验证码,并实现点击图片切换验证码的功能。

<!--login.html-->
<!DOCTYPE html>
<html lang="en">
<script>
    window.onload=function () {
        //1.获取图片对象
        var img =document.getElementById("checkCode");
        //2.绑定单击事件
        img.onclick=function () {
            //加时间戳
            var date = new Date().getTime();
            img.src = "/today/demo?"+date;//时间戳可以防止浏览器认读取本地缓存的图片
        }

    }
</script>
<head>
    <meta charset="UTF-8">
    <title>点击图片切换验证码</title>
</head>
<body>
<img id="checkCode" src="/today/demo"/>//点击图片切换验证码
</body>
</html>

6. 相对路径和绝对路径

6.1. 相对路径

6.1.1. 概念

通过相对路径不可以确定唯一资源,如:./index.html,一般以.开头的路径,其中的./也可以省略。

6.1.2. 使用规则

找到当前资源和目标资源之间的相对位置关系。

常用的有./:当前目录,../:上一级目录。

6.2. 绝对路径

6.2.1. 概念

通过绝对路径可以确定唯一资源,如:http://localhost/day15/responseDemo2,因为服务器地址是一样的,所以可简化书写为:/day15/responseDemo2,以/开头。

6.2.2. 使用规则

通过判断定义的路径是给谁使用的?

  • 给客户端(浏览器)使用:需要加虚拟目录(项目的访问路径),相当于在教学楼门前叫张三,需要指明具体是那个班级的张三。
    • 建议虚拟目录动态获取,一但虚拟目录发生改变可以动态获取,不用修改,使用request.getContextPath()方法;例如重定向推荐使用:resp.sendRedirect(req.getContextPath()+"/responseDemo2");

Html中虚拟目录的获取在之后的jsp中学习<a> ,<form>

  • 给服务器内部使用:不需要加虚拟目录,相当于在班级门前叫张三,直接喊就可以了。

可以判断请求将来从哪儿发出,从客户端还是服务器端内部发出,比如转发是从服务器内部发出的,不需要加虚拟目录,重定向是两次请求,由客户端发出,需要加虚拟目录。