20. Servlet入门 - response介绍以及使用
Response概述
在前面的篇章中我们已经认识了 resquest 请求的相关作用,那么下面来继续认识一下 response 响应。
image-20210108214841273
HttpServletResponse概述
在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法
作用
- 操作响应的三部分(响应行,响应头,响应体)
小结
- Response代表响应对象. 原型是HttpServletResponse, 服务器创建的, 以形参的形式存在doGet()/doPost()方法
- 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. 小结
- 设置的API: response.setStatus(int code);
- 一般不需要设置, 可能302 重定向需要设置
- 常见的响应状态码
- 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/
- 重定向会导致浏览器进行两次请求
- 重定向的地址栏路径改变
- 重定向的路径写绝对路径(带域名/ip地址的, 如果是同一个项目里面的,域名/ip地址可以省略)
- 重定向的路径可以是项目内部的,也可以是项目以外的(eg:百度)
- 重定向不能重定向到WEB-INF下的资源
- 把数据存到request里面, 重定向不可用
//方式一: 重定向
//1.设置状态码
//response.setStatus(302);
//2.设置重定向的路径(绝对路径,带域名/ip地址的,如果是同一个项目里面的,域名/ip地址可以省略)
//response.setHeader("Location","https://www.baidu.com");
//response.setHeader("Location","/index.html");
//方式二: 直接调用sendRedirect方法, 内部封装了上面两行
response.sendRedirect("/index.html");
- 重定向
response.sendRedirect("重定向的路径");
重定向和请求转发的对比
1. 重定向的特点:
- 重定向的跳转是由浏览器发起的,在这个过程中浏览器会发起两次请求
- 重定向跳转可以跳转到任意服务器的资源,但是无法跳转到WEB-INF中的资源
- 重定向跳转不能和request域对象一起使用
- 重定向跳转浏览器的地址栏中的地址会变成跳转到的路径
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 编码格式呢?可以在响应的时候设置如下:
- 解决字符流输出中文乱码问题
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的总结
- 设置响应状态码:setStatus()
- 设置响应头:setHeader(name,value)
- refresh响应头,用于隔几秒钟之后跳转到某个页面
- location响应头,用于重定向到某个页面
- 重定向的写法: sendRedirect(地址)
- 设置响应体的内容
- response.getOutputStream()获取字节输出流
- response.getWriter()获取字符输出流
- writer.write()/print()输出字符串
- 解决响应数据的中文乱码:response.setContentType("text/html;charset=UTF-8")
- 使用字符输出流输出文本内容
- 使用字节输出流输出文件
- 使用IO流的框架进行边读边写