在前面的篇章中我们已经认识了 resquest 请求的相关作用,那么下面来继续认识一下 response 响应。
image-20210108214841273
在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法
当 Servlet 返回响应信息给浏览器的时候,可以设置返回浏览器的响应状态码。
例如:
HTTP/1.1 200
可以使用 setStatus(int sc) 方法来设置响应状态码:
img/
其中常用的状态码:
200:成功
302:重定向
304:访问缓存
404:客户端错误
500:服务器错误
下面我们来写一个Demo来演示一下。
image-20210108220708037
@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);
}
}
image-20210108220811810
上面已经学会了如何使用 Response 来设置响应状态码,那么下面来操作一下响应头。
响应头: 是服务器指示浏览器去做什么
一个key对应一个value
一个key对应多个value
关注的方法: setHeader(String name,String value);
常用的响应头
Refresh:定时跳转 (eg:服务器告诉浏览器5s之后跳转到百度)
Location:重定向地址(eg: 服务器告诉浏览器跳转到xxx)
Content-Disposition: 告诉浏览器下载
Content-Type:设置响应内容的MIME类型(服务器告诉浏览器内容的类型)
下面来演示一下 Refresh 进行定时跳转。
image-20210108223112151
@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");
}
}
image-20210108224213961
等待3秒之后,自动跳转至百度,如下:
image-20210108224233411
上面我们已经通过设置响应头的方式实现了定时跳转,那么下面我们再来看看重定向。
首先创建一个Servlet程序来演示重定向,如下:
image-20210108225507845
@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");
}
}
访问 http://localhost:8080/ResponseDemo3
image-20210108225751120
在这是测试中,我们可以确定重定向可以转发至项目外的资源。那么下面我们来转发至项目内的资源看看。
image-20210108230052784
image-20210108231529080
@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 中的资源呢?
image-20210108231939579
可以看到浏览器是无法访问 WEB-INF 下的资源的,也就导致无法重定向到。
在上面我们重定向既然设置响应码,还是设置请求头,那么有没有简写的方法呢?当然有,下面来看看。
image-20210108232209845
// 重定向的简写方法
response.sendRedirect("/index.html");
在浏览器测试一下,如下:
image-20210108232249318
可以看到一样可以达到重定向的效果的,那么我们只要记住这种写法就好了。
img/
//方式一: 重定向
//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. 请求转发的跳转是由服务器发起的,在这个过程中浏览器只会发起一次请求
2. 请求转发只能跳转到本项目的资源,但是可以跳转到WEB-INF中的资源
3. 请求转发可以和request域对象一起使用
页面输出只能使用其中的一个流实现,两个流是互斥的.
一般用法:
getWriter()
getOutputStream()
下面我们首先演示一下输出文本内容的情况。
image-20210109085839072
@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()
方法。
image-20210109092911409
//2. print()方法,可以输出数字、字符串
writer.print(123456);
可以看到使用 print()
方法的确可以输出数字了,但是我们一般都是只要记住使用 writer()
方法输出字符串即可。
上面我们输出英文字符串、数字的情况都是可以的,那么当我们尝试输出中文内容,则会出现乱码,如下:
image-20210109093255116
那么为什么出现乱码呢,当然就是因为编码格式不一致导致的。那么下面我们来看看如何解决乱码问题。
中文乱码的问题是因为服务端的编码格式 与 浏览器的编码格式不一致导致。那么我们只要将其服务端的编码格式设置为 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解码
*/
image-20210109094414469
@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);
}
}
虽然说解决响应中文乱码就一行代码,但是每次都要去记住还是挺麻烦的。所以我们可以将其设置为一个快捷方式来输入。
File | Settings | Editor | Live Templates
image-20210109094658303
image-20210109094926227
//解决响应中文乱码
response.setContentType("text/html;charset=utf-8");
测试效果如下:
image-20210109094950444
image-20210109095004275
在上面我们已经实现了将字符串内容输出到了浏览器,那么当然我们还要考虑如何将图片内容输出到浏览器。
首先我们来看看默认的DefaultServlet如何处理静态资源。
image-20210109101643743
image-20210109101820588
那么如果自己写一个Servlet程序,该如何实现这个功能呢?
image-20210109102247476
@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 拷贝到另一个输出流的操作,比较繁琐:
//2.2 读取文件输入流 拷贝到 响应输出字节流
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1){
os.write(buffer,0,len);
}
有没有比较简便的方法呢?这个当然有,就是可以将其封装为一个公共方法,而这个公共方法已经有第三方提供了,我们可以直接使用。
访问 https://mvnrepository.com 搜索 commons-io 如下:
image-20210109102853302
image-20210109103030512
image-20210109103057156
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
image-20210109103247691
<!-- 导入 commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
image-20210109103429361
image-20210109103529178
import org.apache.commons.io.IOUtils;
//2.2 使用 commons-io 中的 IOUtils.copy(is,os); 方法来拷贝流
IOUtils.copy(is, os);
image-20210109103717733
image-20210109103730824
可以看到,其实这个 copy 方法也是同样拷贝字节流,只不过封装比较好,方便我们大家的使用。