Response 继承体系
前面说到,我们使用 Request 对象来获取请求数据,使用 Response 对象来设置响应数据。如图:
其实 Response 的继承体系和 Request 有很多相似的地方,如图:
Java 语言提供了响应对象根接口和封装了 HTTP 协议的响应对象接口,两者都是接口,并且两者属于继承关系。
Servlet 类中的 services() 方法,doGet() 方法,doPost() 等方法,都是由 Web 服务器 TomCat 来调用的,所以 TomCat 提供了方法参数接口的具体实现类,并完成了对象的创建,这个实现类就是 ResponseFacade 类。
学习 Response 对象,主要从以下几个方面入手:
- Response 设置响应数据
- Response 完成重定向
- Response 响应字符数据
- Response 响应字节数据
Response 设置响应数据
HTTP 响应数据总共分为三部分内容,分别是响应行,响应头和响应体。通过对应的 API 就可以简单的实现设置响应数据的功能。
设置响应行数据
对于响应行的数据的设置,主要是设置响应状态码,如下:
void setStatus(int sc);
设置响应头数据
响应头的数据格式为 key : value 。Response 提供了方法设置响应头的键值对数据,如下:
void setHeader(String name,String value);
设置响应体数据
对于响应体,是通过字符,字节输出流的方式往浏览器中写数据。
获取字符输出流:
PrintWriter getWriter();
获取字节输出流:
ServletOutputStream getOutputStream();
Response 重定向
Response 重定向也是一种资源的跳转方式,与请求转发不同的是,重定向时浏览器发送了两次请求,所以浏览器地址栏的路径会发生变化,并且我们可以重定向到任何位置的资源,不管是服务器内部的还是外部的。
浏览器发送请求给服务器,服务器中对应的资源 a 接收到了请求,如果资源 a 无法处理该请求,就会响应给浏览器一个 302 状态码和一个访问资源 b 的路径 location 。
浏览器接收到状态码 302 以后就会重新发送请求到 location 对应的访问地址其访问资源 b。资源 b 接收到了请求以后进行处理步最终给浏览器返回响应结果,这一个过程就叫做重定向。
重定向的实现方式:
response.setStatus(302); response.setHeader("location","资源b的访问路径");
下面练习 Response 重定向。
1.创建一个 ResponseDemo1 类,接收 /res1的请求,在 doGet() 方法中打印 resp1…
2.创建一个 ResponseDemo2 类,接收 /res2 的请求,在 doGet() 方法中打印 resp2…
3.在 ResponseDemo1 的方法中实现重定向
4.测试
第一步:创建 ResponseDemo1 类
@WebServlet("/resp1") public class ResponseDemo1 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("resp1..."); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
第二步:创建 ResponseDemo2 类
@WebServlet("/resp2") public class ResponseDemo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("resp2..."); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
第三步:在 ResponseDemo1 类方法中实现重定向
//重定向 //1.设置响应状态码302 response.setStatus(302); //2.设置响应头 location response.setHeader("location","/servlet-project/resp2");
第四步:测试
启动服务器,访问 http://location:8080/servlet-project/resp1,此时控制台输出:
这里 /resp1 和 /resp2 都被访问到了,表示重定向成功了。其实 Response 还提供了一种更加简便的方式来实现重定向,如下:
resposne.sendRedirect("/servlet-project/resp2")
Response 响应字符数据
服务器接收到浏览器发送的请求之后经过一系列的逻辑处理后就要发送响应给浏览器,而把数据写回浏览器是十分重要的一部分,我们一般使用输出流的方式将响应数据写回浏览器。
Response 对字符数据和字节数据的响应方式是不同的,要想将字符数据写到浏览器,需要完成下面两个步骤:
1.获取字符输出流
2.通过字符输出流写数据
下面练习将一个简单的字符串写到浏览器。
@WebServlet("/demo") public class ServletDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter writer = response.getWriter(); writer.write("helloWorld"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
下面练习将一个 html 字符串返回给浏览器,并且被浏览器解析。
PrintWriter writer = response.getWriter(); //content-type 告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签 response.setHeader("content-type","text/html"); writer.write("<h1>helloWorld</h1>");
注意:返回的中文字符数据时要把字符编码方式设置为 utf-8。在一次请求结束后,response 对象会被销毁,所以这里的流对象不需要手动释放。
Response 响应字节数据
要想将字节数据写到浏览器,只需要下面两个步骤:
1.获取字节输出流对象
2.通过字节输出流写数据
下面练习将一个图片文件写回到浏览器。
@WebServlet("/demo") public class ResponseDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 用于读取文件 FileInputStream fis = new FileInputStream("d://a.jpg"); //2. 获取response字节输出流 ServletOutputStream os = response.getOutputStream(); //3. 完成流的复制 byte[] buff = new byte[1024]; int len = 0; while ((len = fis.read(buff))!= -1){ os.write(buff,0,len); } fis.close(); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
Java 的 IO 流操作是开发中比较常用的技术,但是如果每次都使用原生的 IO 流来操作会显得比较繁琐。我们可以使用 commons-io 来简化操作,commons-io 是一个工具包,用来帮助 IO 功能的开发,感兴趣的朋友可以去了解一下。
使用前我们要先往 pom.xml 配置文件中添加对应的依赖坐标。
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
此时,将图片返回给浏览器的代码可以优化为:
@WebServlet("/demo") public class ServletDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { FileInputStream fis = new FileInputStream("C:\\Users\\24091\\Desktop\\46cfac1918ae3f7831e746684c0bd42.jpg"); ServletOutputStream os = response.getOutputStream(); IOUtils.copy(fis,os); fis.close(); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }