前 言
人总是要有梦想的,也许哪天就实现了呢!
如果有不正确之处,还望指正,毕竟我还是一个菜鸟!
一、HTTP 协议
在之前的一篇文章中,提到了HTTP 协议的请求部分,这次我们讲解HTTP 的响应部分。
- 响应行:
- 组成:协议/版本 响应状态码 状态码描述
- 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态,状态码都是3位数字组成。状态码分类如下:
1xx:服务器接收客户端消息,但是接收没有完成,等待了一段时间后,向客户端发送1xx状态码
2xx:成功。代表的是200
3xx:重定向。代表:302(重定向),304(访问缓存)
4xx:客户端错误。代表:404(请求路径没有对应的资源),405(请求方式没有对应的doXxx方法)
5xx:服务器错误。代表:500(服务器内部出现异常)
- 响应头:
- 格式:
头名称:值
- 常见的响应头:
Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
Content-disposition:服务器告诉客户端以什么格式打开响应体数据
- 响应空行:
- 响应体:传输的数据
响应信息
二、Response 对象
1、设置响应消息
当客户从浏览器发起请求时,在访问成功的情况下,服务器就需要作出响应,所以我们就需要设置响应消息,来传给客户端浏览器。
- 设置响应行:
- 格式:
HTTP/1.1 200 ok
- 设置状态码:
setStatus(int sc)
- 设置响应头:
setHeader(String name, String value)
- 设置响应体:具体步骤如下:
- 获取输出流:
1. PrintWriter getWriter() - 字符输出流
2. ServletOutputStream getOutputStream() - 字节输出流
- 使用输出流,将数据输出到客户端浏览器
2、重定向(Redirect)
- 概述:重定向就是不对本次请求进行业务处理,而是跳转到指定的URL进行处理业务,在这期间,浏览器发起了两次请求。举例:这就相当于你去1号窗口办理事务,但是1号窗口不能办理并且告诉你3号窗口能够办理你的业务,这时候你就自己去了3号窗口,找3号窗口的业务员替你办理业务。在这个过程中,你去了两个窗口,向不同的业务员发起请求。这里的业务员就相当于URL。
- 特点:
- 重定向是两次请求,地址栏发生改变。并且不能使用request对象来共享数据。
- 重定向可以访问其他站点的资源,即可以跳转到网络资源中。
- 重定向的路径需要加入虚拟目录。
- 方法:
sendRedirect(String URL)
- 路径写法:
- 相对路径:通过相对路径的方式,不能够确定唯一资源,如:
../index.html
- 绝对路径:通过绝对路径可以确定唯一资源,如:
http://localhost/servlet/responseDemo
3、Redirect 与 Forward 区别
- 重定向是两次请求,都是从浏览器出发;请求转发是一次请求,转发在服务器内部进行。
- 重定向浏览器地址栏发生改变;请求转发浏览器地址栏不发生改变;
- 重定向可以访问网络资源;请求转发只能访问本服务器中的资源;
- 重定向的路径中需要加虚拟目录;请求转发的路径不需要加入虚拟目录,只需要资源路径即可。
4、响应乱码问题
- 为什么会出现响应乱码?
服务器给浏览器发送响应信息,需要借助输出流,如果不对流的字符编码进行设置,就会出现乱码。其中,字节流如果不指定编码默认就是平台编码,即编辑器的默认的编码,如果浏览器与之字符编码不同就会出现乱码情况,而字符流如果不指定编码默认是ISO8859-1,该编码集不包括中文,所以如果使用中文一定会出现乱码情况。 - 解决:在服务器做出响应之前,设置响应编码
/**
* setContentType()
*/
@WebServlet(value = "/forward.do")
public class ServletDemo9 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 防止请求乱码
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
// 设置响应编码,防止中文乱码
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write(username + ",欢迎你!");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}
三、ServletContext 对象
- 概述:ServletContext对象称为Servlet上下文对象,服务器会为每个web程序创建一个上下文对象,上下文对象在项目中只有一个。该对象代表整个web应用程序,它可以和web容器(Tomcat)进行通信。该对象包含所有用户请求的数据, 一般用来获取MIME类型的文件数据、共享数据以及获取服务器中的文件资源。
- 获取对象的两种方式:
/**
* 1. 通过HttpServletRequest对象来获取
* 2. 通过HttpServlet对象来获取
*/
@WebServlet(value = "/servletContextDemo1")
public class ServletContextDemo1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 1. 通过request对象来获取
ServletContext context1 = req.getServletContext();
// 2. 通过HttpServlet对象来获取
ServletContext context2 = this.getServletContext();
System.out.println(context1 == context2);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}
运行结果:true
ServletContext 功能
- 获取MIME类型:
- MIME类型:在互联网通信过程中的一种文件数据类型,用来标志是什么类型的文件,我们之前setContentType方法中的text/html,就是MIME类型的一种,用来指明是html文件类型。
- 获取方式:
String getMimeType(String file)
- 域对象,共享数据:
- 概述:这里的域对象,与Request域对象不是一种,request域对象不能在不同的用户请求中共享数据,而ServletContext域对象可以做到在所有的servlet中共享数据,它的域范围是最大的。
- 方法介绍:
1. void setAttribute(String name,Object obj) - 存储数据
2. Object getAttitude(String name) - 通过键获取值
3. void removeAttribute(String name) - 通过键移除键值对
- 获取文件的真实路径:服务器中的路径
- 概述:通过文件的相对路径来获取文件的绝对路径,这里的相对路径,相对的是项目发布在tomcat中的资源路径
- 方法:
String getRealPath(String path)
- 代码示例:
@WebServlet(value = "/servletContextDemo2")
public class ServletContextDemo2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获取域对象
ServletContext context = req.getServletContext();
// 创建文件对象
File file = new File("a.txt");
// 获取file的MIME类型
String mimeType = context.getMimeType(String.valueOf(file));
// 设置域对象
context.setAttribute("msg", "这里是ServletContext域对象");
// 获取默认的绝对路径
System.out.println(context.getRealPath("/"));
// 获取web目录下的文件路径
System.out.println(context.getRealPath("/index.html"));
// 获取WEB-INF目录下的文件路径
System.out.println(context.getRealPath("/WEB-INF/web.xml"));
// 获取src目录下文件的路径
System.out.println(context.getRealPath("/WEB-INF/classes/a.txt"));
System.out.println(ServletContextDemo2.class.getClassLoader().getResource("a.txt").getPath());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}
@WebServlet(value = "/servletContextDemo3")
public class ServletContextDemo3 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = req.getServletContext();
// 获取域对象
System.out.println(context.getAttribute("msg"));
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}
运行结果:
F:\JetBrains\javacode\javaweb2\out\artifacts\servlet_war_exploded\
F:\JetBrains\javacode\javaweb2\out\artifacts\servlet_war_exploded\index.html
F:\JetBrains\javacode\javaweb2\out\artifacts\servlet_war_exploded\WEB-INF\web.xml
F:\JetBrains\javacode\javaweb2\out\artifacts\servlet_war_exploded\WEB-INF\classes\a.txt
/F:/JetBrains/javacode/javaweb2/out/artifacts/servlet_war_exploded/WEB-INF/classes/a.txt
这里是ServletContext域对象