20. Servlet入门 - response介绍以及使用

2022-01-14 17:47:19 浏览数 (1)

20. Servlet入门 - response介绍以及使用

Response概述

在前面的篇章中我们已经认识了 resquest 请求的相关作用,那么下面来继续认识一下 response 响应。

image-20210108214841273

HttpServletResponse概述

在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法

作用
  • 操作响应的三部分(响应行,响应头,响应体)

小结

  1. Response代表响应对象. 原型是HttpServletResponse, 服务器创建的, 以形参的形式存在doGet()/doPost()方法
  2. Response的作用
    • 操作响应的三部分(行, 头, 体)

Response 设置响应状态码(操作响应行)

当 Servlet 返回响应信息给浏览器的时候,可以设置返回浏览器的响应状态码。

例如:

代码语言:javascript复制
HTTP/1.1 200

可以使用 setStatus(int sc) 方法来设置响应状态码:

img/

其中常用的状态码:

200:成功

302:重定向

304:访问缓存

404:客户端错误

500:服务器错误

下面我们来写一个Demo来演示一下。

1.创建一个演示的Servlet程序,并设置响应状态码 403

image-20210108220708037

代码语言:javascript复制
@WebServlet("/ResponseDemo1")
public class ResponseDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("访问 ResponseDemo1 ....");
        //设置响应状态码: 403 forbidden
        response.setStatus(403);
    }
}

2.在浏览器上测试访问

image-20210108220811810

3. 小结

  1. 设置的API: response.setStatus(int code);
  2. 一般不需要设置, 可能302 重定向需要设置
  3. 常见的响应状态码
    • 200 成功
    • 302 重定向
    • 304 读缓存
    • 404 客户端错误
    • 500 服务器错误

Response 设置 refresh 响应头来进行定时跳转(操作响应头)

上面已经学会了如何使用 Response 来设置响应状态码,那么下面来操作一下响应头。

1.操作响应头的 API 介绍

响应头: 是服务器指示浏览器去做什么

一个key对应一个value

一个key对应多个value

关注的方法: setHeader(String name,String value);

常用的响应头

Refresh:定时跳转 (eg:服务器告诉浏览器5s之后跳转到百度)

Location:重定向地址(eg: 服务器告诉浏览器跳转到xxx)

Content-Disposition: 告诉浏览器下载

Content-Type:设置响应内容的MIME类型(服务器告诉浏览器内容的类型)

下面来演示一下 Refresh 进行定时跳转。

2.创建一个演示的Servlet程序,设置响应头定时跳转

image-20210108223112151

代码语言:javascript复制
@WebServlet("/ResponseDemo2")
public class ResponseDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //目标: 让浏览器在访问ResponseDemo2后三秒,跳转到百度首页
        System.out.println("ResponseDemo2收到了请求。。。");
        //通过"Refresh"响应头
        response.setHeader("Refresh","3;url=https://www.baidu.com");
    }
}

3.在浏览器上测试访问

image-20210108224213961

等待3秒之后,自动跳转至百度,如下:

image-20210108224233411

Response 发起重定向(操作响应头)

上面我们已经通过设置响应头的方式实现了定时跳转,那么下面我们再来看看重定向。

1. Response 设置Location响应头,来进行重定向跳转(立即跳转)

首先创建一个Servlet程序来演示重定向,如下:

image-20210108225507845

代码语言:javascript复制
@WebServlet("/ResponseDemo3")
public class ResponseDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("ResponseDemo3收到了一个请求...");
        //目标1:浏览器访问ResponseDemo3,会跳转到百度首页
        //重定向跳转的步骤:1. 设置响应状态码为302  2. 设置响应头Location的值为要跳转到的地址
        response.setStatus(302);
        response.setHeader("Location","https://www.baidu.com");
    }
}

2.浏览器测试访问,发现浏览器成功立即跳转至百度

访问 http://localhost:8080/ResponseDemo3

image-20210108225751120

在这是测试中,我们可以确定重定向可以转发至项目外的资源。那么下面我们来转发至项目内的资源看看。

3.设置重定向至项目内的资源

3.1 在 WEB-INF 下创建一个 index.html

image-20210108230052784

3.2 在Servlet中设置重定向到该 index.html ,如下:

image-20210108231529080

代码语言:javascript复制
@WebServlet("/ResponseDemo3")
public class ResponseDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("ResponseDemo3收到了一个请求...");
        //目标1:浏览器访问ResponseDemo3,会跳转到百度首页
        //重定向跳转的步骤:1. 设置响应状态码为302  2. 设置响应头Location的值为要跳转到的地址
//        response.setStatus(302);
//        response.setHeader("Location","https://www.baidu.com");

        //目标2:浏览器访问ResponseDemo3,会跳转到本项目的index.html页面
        response.setStatus(302);
        response.setHeader("Location","/index.html"); // 路径设置: /项目部署路径/文件在webapp下的路径
    }
}

使用浏览器访问 http://localhost:8080/ResponseDemo3 如下:

image-20210108231635621

那么能不能访问 WEB-INF 中的资源呢?

3.3 尝试重定向至 WEB-INF 中的资源

image-20210108231939579

可以看到浏览器是无法访问 WEB-INF 下的资源的,也就导致无法重定向到。

3.4 使用 sendRedirect 简写重定向

在上面我们重定向既然设置响应码,还是设置请求头,那么有没有简写的方法呢?当然有,下面来看看。

image-20210108232209845

代码语言:javascript复制
// 重定向的简写方法
response.sendRedirect("/index.html");

在浏览器测试一下,如下:

image-20210108232249318

可以看到一样可以达到重定向的效果的,那么我们只要记住这种写法就好了。

4.小结

img/

  1. 重定向会导致浏览器进行两次请求
  2. 重定向的地址栏路径改变
  3. 重定向的路径写绝对路径(带域名/ip地址的, 如果是同一个项目里面的,域名/ip地址可以省略)
  4. 重定向的路径可以是项目内部的,也可以是项目以外的(eg:百度)
  5. 重定向不能重定向到WEB-INF下的资源
  6. 把数据存到request里面, 重定向不可用
代码语言:javascript复制
//方式一: 重定向
//1.设置状态码
//response.setStatus(302);
//2.设置重定向的路径(绝对路径,带域名/ip地址的,如果是同一个项目里面的,域名/ip地址可以省略)
//response.setHeader("Location","https://www.baidu.com");
//response.setHeader("Location","/index.html");

//方式二:  直接调用sendRedirect方法, 内部封装了上面两行
response.sendRedirect("/index.html");
  • 重定向
代码语言:javascript复制
 response.sendRedirect("重定向的路径");

重定向和请求转发的对比

1. 重定向的特点:

  1. 重定向的跳转是由浏览器发起的,在这个过程中浏览器会发起两次请求
  2. 重定向跳转可以跳转到任意服务器的资源,但是无法跳转到WEB-INF中的资源
  3. 重定向跳转不能和request域对象一起使用
  4. 重定向跳转浏览器的地址栏中的地址会变成跳转到的路径

2. 请求转发的特点:

代码语言:javascript复制
1. 请求转发的跳转是由服务器发起的,在这个过程中浏览器只会发起一次请求
2. 请求转发只能跳转到本项目的资源,但是可以跳转到WEB-INF中的资源
3. 请求转发可以和request域对象一起使用

使用 Response 的字符输出流向浏览器输出响应体的文本内容(操作响应体)

1.操作响应体的API

页面输出只能使用其中的一个流实现,两个流是互斥的.

一般用法:

  • 如果是输出文本内容到浏览器,那么则需要输出字符到浏览器,用 getWriter()
  • 如果是下载图片等资源,那么则需要输出字节流到浏览器,用getOutputStream()

下面我们首先演示一下输出文本内容的情况。

2.使用 getWriter() 向浏览器输出文本内容

2.1 response.getWriter().writer()方法,只能输出字符串,如果输出int、float等等类型的话,则会有问题

image-20210109085839072

代码语言:javascript复制
@WebServlet("/ResponseDemo4")
public class ResponseDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //要向浏览器输出响应体的信息,需要通过流来进行操作
        //第一种:字符串,输出文本内容
        PrintWriter writer = response.getWriter();
        //使用字符流往浏览器输出文本
        //1. writer()方法,只能输出字符串,如果输出int、float等等类型的话,则会有问题
        writer.write("hello world");
    }
}

如果输出 int、float 类型,则会报错如下:

image-20210109085940913

可以看到无法正常显示数字,那么就是需要显示数字呢?这个时候一般就是将其作为字符串输出,如下:

image-20210109090049756

但是如果不想这样,就是向直接输出 int、float 等内容,可以怎么办呢?可以使用 writer.print() 方法。

2.2 response.getWriter().print()方法,可以输出数字、字符串

image-20210109092911409

代码语言:javascript复制
//2. print()方法,可以输出数字、字符串
writer.print(123456);

可以看到使用 print() 方法的确可以输出数字了,但是我们一般都是只要记住使用 writer() 方法输出字符串即可。

2.3 输出中文字符串,出现乱码问题

上面我们输出英文字符串、数字的情况都是可以的,那么当我们尝试输出中文内容,则会出现乱码,如下:

image-20210109093255116

那么为什么出现乱码呢,当然就是因为编码格式不一致导致的。那么下面我们来看看如何解决乱码问题。

3.中文响应乱码问题的解决

中文乱码的问题是因为服务端的编码格式 与 浏览器的编码格式不一致导致。那么我们只要将其服务端的编码格式设置为 UTF8,然后通知浏览器也设置为 UTF8 编码格式就可以了。

那么如果通知浏览器设置 UTF8 编码格式呢?可以在响应的时候设置如下:

  • 解决字符流输出中文乱码问题
代码语言:javascript复制
response.setContentType("text/html;charset=utf-8");
/*
 * 这句代码底层做了什么?
 * 1. 设置服务器响应的字符集为UTF-8
 * 2. 设置Content-Type响应头的信息为 "text/html;charset=UTF-8"
 *    让浏览器知道了服务器的响应字符集UTF-8,那么浏览器也会使用UTF-8解码
 */
3.1 解决输出中文乱码问题演示

image-20210109094414469

代码语言:javascript复制
@WebServlet("/ResponseDemo4")
public class ResponseDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //解决响应中文乱码
        response.setContentType("text/html;charset=utf-8");

        //要向浏览器输出响应体的信息,需要通过流来进行操作
        //第一种:字符串,输出文本内容
        PrintWriter writer = response.getWriter();
        //使用字符流往浏览器输出文本
        //1. writer()方法,只能输出字符串,如果输出int、float等等类型的话,则会有问题
        writer.write("你好,世界...");

        //2. print()方法,可以输出数字、字符串
//        writer.print(123456);
    }
}
3.2 设置响应编码格式的快捷方式

虽然说解决响应中文乱码就一行代码,但是每次都要去记住还是挺麻烦的。所以我们可以将其设置为一个快捷方式来输入。

File | Settings | Editor | Live Templates

image-20210109094658303

image-20210109094926227

代码语言:javascript复制
//解决响应中文乱码
response.setContentType("text/html;charset=utf-8");

测试效果如下:

image-20210109094950444

image-20210109095004275

使用 Response 的 字节流 getOutputStream() 向浏览器输出图片内容(操作响应体)

在上面我们已经实现了将字符串内容输出到了浏览器,那么当然我们还要考虑如何将图片内容输出到浏览器。

首先我们来看看默认的DefaultServlet如何处理静态资源。

DefaultServlet 处理静态资源

1.拷贝一张图片到 webapp 目录下

image-20210109101643743

2.启动 tomcat 服务,使用工程路径访问图片资源

image-20210109101820588

那么如果自己写一个Servlet程序,该如何实现这个功能呢?

自己写Servlet,使用 getOutputStream() 将图片资源输出到浏览器

image-20210109102247476

代码语言:javascript复制
@WebServlet("/ResponseDemo5")
public class ResponseDemo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 读取b.jpg图片,将其转换成字节输入流,使用ServletContext
        ServletContext servletContext = getServletContext();
        InputStream is = servletContext.getResourceAsStream("1.jpeg");

        //2. 使用字节输出流,将is中的字节都输出到浏览器
        //2.1 获取响应字节流
        ServletOutputStream os = response.getOutputStream();
        //2.2 读取文件输入流 拷贝到 响应输出字节流
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = is.read(buffer)) != -1){
            os.write(buffer,0,len);
        }

        //3.关闭流
        os.close();
        is.close();
    }
}

在上面的代码中,我们已经实现了图片资源输出浏览器的效果,但是我们可以发现。

当我们每次操作字节流的时候,都要写一串字节流 buffer 拷贝到另一个输出流的操作,比较繁琐:

代码语言:javascript复制
        //2.2 读取文件输入流 拷贝到 响应输出字节流
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = is.read(buffer)) != -1){
            os.write(buffer,0,len);
        }

有没有比较简便的方法呢?这个当然有,就是可以将其封装为一个公共方法,而这个公共方法已经有第三方提供了,我们可以直接使用。

IO流工具的使用:简化字节流的拷贝操作

  • 引入commons-io的jar包
  • 使用 commons-io 简化字节流的拷贝操作

1.使用 Maven 导入 commons-io的 jar 包依赖

1.1 访问 Maven 仓库,搜索 commons-io 的依赖

访问 https://mvnrepository.com 搜索 commons-io 如下:

image-20210109102853302

image-20210109103030512

image-20210109103057156

代码语言:javascript复制
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>
1.2 在项目的 pom.xml 导入 commons-io 坐标依赖

image-20210109103247691

代码语言:javascript复制
<!-- 导入 commons-io       -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

2.使用 commons-io 中的 IOUtils.copy(is,os); 方法来拷贝流

image-20210109103429361

image-20210109103529178

代码语言:javascript复制
import org.apache.commons.io.IOUtils;

//2.2 使用 commons-io 中的 IOUtils.copy(is,os); 方法来拷贝流
IOUtils.copy(is, os);

3.查看 IOUtils.copy(is, os) 的源码

image-20210109103717733

image-20210109103730824

可以看到,其实这个 copy 方法也是同样拷贝字节流,只不过封装比较好,方便我们大家的使用。

response的总结

  1. 设置响应状态码:setStatus()
  2. 设置响应头:setHeader(name,value)
    1. refresh响应头,用于隔几秒钟之后跳转到某个页面
    2. location响应头,用于重定向到某个页面
  3. 重定向的写法: sendRedirect(地址)
  4. 设置响应体的内容
    1. response.getOutputStream()获取字节输出流
    2. response.getWriter()获取字符输出流
    3. writer.write()/print()输出字符串
    4. 解决响应数据的中文乱码:response.setContentType("text/html;charset=UTF-8")
    5. 使用字符输出流输出文本内容
    6. 使用字节输出流输出文件
  5. 使用IO流的框架进行边读边写

0 人点赞