文章目录
提示:以下是本篇文章正文内容,Java系列学习将会持续更新
一、Servlet 是什么?
Servlet 是一种实现动态页面的技术。是一组 Tomcat 提供给程序猿的 API,帮助程序猿简单高效的开发一个 web app。
静态页面: 就是内容始终固定的页面。即使 用户不同/时间不同/输入的参数不同 , 页面内容也不会发生变化。
动态页面: 指的是 用户不同 / 时间不同 / 输入的参数不同,页面内容会发生变化。如个人中心页面。
大体的开发流程 —— 整个过程都需要遵守标准,否则Tomcat不认:
- 通过继承
HttpServlet
抽象类,完成我们自己类(每个都是一个独立的Web资源) HelloServlet - 重写其中的方法(get、 post …) ,就是输出资源内容的过程
- 把动态资源和路径建立绑定关系。/hello <=> HelloServlet
- 通过web.xml (演示,麻烦,少用)
- 使用Java中的注解语法完成
@WebServlet
对于Web资源类,我们只负责写:
- 不需要我们自己实例化HelloServlet对象 (Tomcat内部在实例化)
- 我们也不会调用我们写好的get、post 方法 (Tomcat 内部会在合适的时机去调用)
二、书写 Servlet 程序
2-1 书写Web资源类的流程
// 类名无所谓,但是尽量按照一定的规范去命名比较好
// 1. 声明这个类是一个 Web 资源,让类继承 HttpServlet 这个抽象类
public class FirstServlet extends HttpServlet {
@Override
// 2. 看我们的动态资源支持哪些 HTTP 方法(支持 get 方法,重写 doGet 方法)
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 3. 读取 req 对象中的信息(都是 来自 HTTP 请求中信息)
// 4. 根据我们当下的条件
// 5. 准备响应数据,通过填写 resp 对象来做到
// 这个例子中 201 text/plain "你好世界" charset=utf-8
resp.setStatus(201); // 状态码
resp.setContentType("text/plain; charset=utf-8"); // 输出的文本类型
PrintWriter writer = resp.getWriter(); // 调用响应对象的输出方法
writer.print("你好世界");
}
// 6. 把动态资源和一个资源路径建立绑定关系 /first
// 6.1 先使用 web.xml 的方式
}
2-2 通过web.xml动态绑定
<!-- 指明Web资源类 -->
<servlet>
<servlet-name>MyFirstServlet</servlet-name>
<servlet-class>servlet.FirstServlet</servlet-class>
</servlet>
<!-- 映射到具体的类 -->
<servlet-mapping>
<servlet-name>MyFirstServlet</servlet-name>
<!-- ServletPath -->
<url-pattern>/first</url-pattern>
</servlet-mapping>
2-3 通过@WebServlet注解动态绑定
// 6.2 通过用 @WebServlet 注解修饰类,来实现绑定
@WebServlet("/second")
public class SecondServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(202);
resp.setContentType("text/css; charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print("你好中国");
}
}
三、Servlet 运行原理
在 Servlet 的代码中我们并没有写 main 方法, 实际上我们写的代码是交给 Tomcat 服务器来运行。
当浏览器给服务器发送请求的时候, Tomcat 作为 HTTP 服务器, 就可以接收到这个请求。
HTTP 协议作为一个应用层协议, 需要底层协议栈来支持工作. 如下图所示:
更详细的交互过程如下:
3-1 Tomcat内部的过程
- Tomcat收到了一个HTTP请求
- Tomcat根据HTTP协议的规定,解析请求,得到诸如: 请求方法、资源路径、请求头们、请求体(POST请求才有)。
- Tomcat根据资源路径 (Path = Context Path + Servlet Path)
- 先根据Context Path,决定这个资源是交给哪个Webapp处理 (隐含: Tomcat支持多个webapp同时存在)
- 当确定是哪个webapp后,再根据Servlet Path,去找到对应的资源进行处理
- 如果是动态资源,根据路径得到一个类名
(servlet.FirstServlet
)
如果这个类还没有实例化对象,则实例化其对象,否则直接获取其对象 (单例模式
)
根据请求方法,调用该对象doGet
或者doPost
或者其他
方法
doGet方法执行结束之后,resp 对象被填充信息(203, text/css, 你好世界)
Tomcat根据这个对象,构造HTTP响应,发送给浏览器。 - 如果是静态资源,就根据对应的路径去查找对应的文件,并响应文件内容。
- 如果动态 or 静态资源都没有找到,就会404
- 如果是动态资源,根据路径得到一个类名
3-2 输入 URL 后,浏览器内部发生了什么?
只站在应用层的角度:
- 浏览器 : 解析URL,(如果是域名, 通过DNS服务器,将域名换成ip的过程)。构建HTTP请求(GET 请求)
- Tomcat收到了请求。根据路径,确定对应的Servlet哪个对象进行处理;根据请求方法,调用对象的对应方法。
- 执行Servlet业务代码(我们写的), 得到填充好的响应对象
- Tomcat根据响应对象,构建HTTP响应,发送给浏览器
- 浏览器读取响应,展示响应结果。
如果结果是 html 或 存在JS代码的话,可能还会触发产生新的HTTP请求 - 浏览器得到显示页面的所有的资源,构建DOM树(包含JS处理过的情况) +进行CSS渲染
产生最终的页面 - 用户看到最终的页面效果
结合网络知识:
- 站在发送端主机的角度: 应用层->传输层->网络层->数据链路层->物理层(网卡), 按照各种协议封装起来的。
- 站在接收端主机的角度 : 物理层(网卡) -> 数据链路层->网络层->传输层->应用层,照协议解包+分用。
- 只在TCP的角度讲述 : 要发送HTTP请求,收到HTTP响应,首先得有TCP连接(TCP三次握手、通信、四次挥手)
四、Servlet API
4-1 HttpServlet
我们写 Servlet 代码的时候, 首先第一步就是先创建类, 继承自 HttpServlet, 并重写其中的某些方法.
方法名称 | 调用时机 |
---|---|
init | 在 HttpServlet 实例化之后被调用一次 |
destory | 在 HttpServlet 实例不再使用的时候调用一次 |
service | 收到 HTTP 请求的时候调用 |
doGet | 收到 GET 请求的时候调用(由 service 方法调用) |
doPost | 收到 POST 请求的时候调用(由 service 方法调用) |
doPut/doDelete/doOptions/… | 收到其他请求的时候调用(由 service 方法调用) |
4-2 HttpServletRequest
当 Tomcat 通过 Socket API 读取 HTTP 请求(字符串), 并且按照 HTTP 协议的格式把字符串解析成
HttpServletRequest 对象.
方法 | 描述 |
---|---|
String getProtocol() | 返回请求协议的名称和版本。 |
String getMethod() | 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。 |
String getRequestURI() | 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。 |
String getContextPath() | 返回指示请求上下文的请求 URI 部分。 |
String getQueryString() | 返回包含在路径后的请求 URL 中的查询字符串。 |
Enumeration getParameterNames() | 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。 |
String getParameter(String name) | 以字符串形式返回请求参数的值,或者如果参数不存在则返回null。 |
String[] getParameterValues(String name) | 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。 |
Enumeration getHeaderNames() | 返回一个枚举,包含在该请求中包含的所有的头名。 |
String getHeader(String name) | 以字符串形式返回指定的请求头的值。 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码的名称。 |
String getContentType() | 返回请求主体的 MIME 类型,如果不知道类型则返回 null。 |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。 |
InputStream getInputStream() | 用于读取请求的 body 内容. 返回一个 InputStream 对象. |
4-3 HttpServletResponse
Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到
HttpServletResponse 对象中.
然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过
Socket 写回给浏览器.
方法 | 描述 |
---|---|
void setStatus(int sc) | 为该响应设置状态码。 |
void setHeader(String name, String value) | 设置一个带有给定的名称和值的 header. 如果 name 已经存在,则覆盖旧的值. |
void addHeader(String name, String value) | 添加一个带有给定的名称和值的 header. 如果 name 已经存在,不覆盖旧的值, 并列添加新的键值对 |
void setContentType(String type) | 设置被发送到客户端的响应的内容类型。 |
void setCharacterEncoding(String charset) | 设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。 |
void sendRedirect(String location) | 使用指定的重定向位置 URL 发送临时重定向响应到客户端。 |
PrintWriter getWriter() | 用于往 body 中写入文本格式数据. |
OutputStream getOutputStream() | 用于往 body 中写入二进制格式数据. |
总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是JavaWeb的学习,学习如何写Servlet程序,了解Servlet的运行原理,以及Servlet API中的常用方法。之后的学习内容将持续更新!!!