Servlet原理&&Servlet API

目录

一、Servlet运行原理

1.1、问题

1.2、Servlet的具体执行过程

1.3、Tomcat初始化流程小结

1.4、Tomcat处理请求流程

二、Servlet API详解

2.1、HttpServlet类

2.1.1、处理Get请求

2.2、HttpServletRequest类

2.3、HttpServletResponse类

2.3.1、设置状态码

​2.3.2、自动刷新

2.3.3、重定向 


一、Servlet运行原理

1.1、问题

        在Servlet的代码中我们并没有写main方法,要知道一个程序的入口是main方法,那么没有main方式是如何被调用呢?响应又是如何返回给浏览器呢?

        当浏览器给服务器发送请求的时候,Tomcat作为HTTP服务器,就可以接收到这个请求

1.2、Servlet的具体执行过程

客户端发送请求->到Tomcat的webServer->Servlet管理器(多个)->Servlet实例

具体过程:

(1)接收请求

  1. 用户在浏览器输入一个URL,此时浏览器就会构造出一个HTTP请求;
  2. HTTP请求开始从应用层往下逐层封装数据(打包)得到一个二进制的bit流,最后通过物理层将数据传输给服务器端的物理层;
  3. 服务器端的物理层接收到数据之后,开始从物理层往上逐层分用,层层解析数据(解析),最终还原出HTTP请求,并交给Tomcat进程进行处理(根据端口号确定进程);
  4. Tomcat通过Socket读取到这个请求(一个字符串),并按照HTTP请求的格式来解析这个请求:根据请求中的Context Path确定一个webapp,再通过Servlet Path确定一个具体的类,再根据当前请求的方法(GET或者POST或其他)决定调用这个类的doGet或者doPost方法。此时我们的代码中的doGet或者doPost方法的第一个参数HttpServletRequest 就包含了这个 HTTP 请求的详细信息

(2)根据请求计算响应

        在我们的doGet或者doPost执行完毕之后,就执行到了我们自己的代码。我们的代码会根据请求中的一些信息,来给HttpServletResponse对象设置一些属性:比如状态码,header,body等。

(3)返回响应

  1. 等我们的doGet或者doPost执行结束之后,Tomcat就会自动将HttpServletResponse这个我们刚设置好的对象转化为一个符合HTTP协议的字符串,通过Socket将这个响应发送出去;
  2. 然后响应数据在服务器的主机上又通过网络协议栈层层封装,得到一个二进制的bit流,通过物理层将数据传输出去;
  3. 此时浏览器的物理层收到了响应数据,从下往上到应用层将数据进行分用,还原成HTTP响应,交给浏览器处理;
  4. 浏览器通过Socket读到这个响应(一个字符串),按照HTTP响应的格式来解析这个响应,并将body中的数据按照一定的格式显示在浏览器的界面上。

1.3、Tomcat初始化流程小结

  1. Tomcat的代码中内置了main方法,当我们启动Tomcat的时候,就是从Tomcat的main方法开始执行的;
  2. 被@webservlet注解修饰的类会在Tomcat启动的时候就会被获取到,并集中管理;
  3. Tomcat通过 反射 这样的语法机制来创建被 @WebServlet 注解修饰的类的实例;
  4. 这些实例被创建完了之后 , 会点调用其中的 init 方法进行初始化 . ( 这个方法是 HttpServlet 自带的 , 我们自己写的类可以重写 init);
  5. 这些实例被销毁之前 , 会调用其中的 destory 方法进行收尾工作 . ( 这个方法是 HttpServlet 自带的 , 我们自己写的类可以重写 destory);

1.4、Tomcat处理请求流程

  1. Tomcat Socket 中读到的 HTTP 请求是一个字符串, 然后会按照 HTTP 协议的格式解析成一个HttpServletRequest 对象;
  2. Tomcat 会根据 URL 中的 path 判定这个请求是请求一个静态资源还是动态资源. 如果是静态资源, 直接找到对应的文件把文件的内容通过 Socket 返回. 如果是动态资源, 才会执行到 Servlet 的相关逻辑.
  3. Tomcat 会根据 URL 中的 Context Path Servlet Path 确定要调用哪个 Servlet 实例的 service 方法.
  4. 通过 service 方法, 就会进一步调用到我们之前写的 doGet 或者 doPost

二、Servlet API详解

2.1、HttpServlet类

在写Servlet代码的时候,第一步是创建一个类,继承HttpServlet,并重写其中的方法

方法调用时机
init在HttpServlet实例化之后被调用一次
destroy在HttpServelet实例不再使用时调用一次
service收到HTTP请求时调用 (由service调用)
doGet收到GET请求时调用 (由service调用)
doPost收到POST请求时调用 (由service调用)
doPut / doDelete…收到对应请求时调用 (由service调用)

init方法:该方法是在tomcat首次收到了该类相关联的请求时,就会调用到HelloServlet,就需要先对HelloServlet进行实例化,后续在收到请求时,不必再实例化了,直接复用之前的HelloServlet实例即可,只执行一次

destroy方法:当HttpServlet实例不再使用时调用该方法,啥时候该实例就不再使用了?服务器只要不停止,该实例就一直被使用,只有当服务器停止后了,才会调用该方法,只执行一次

Tomcat有两种方式结束:

  1. 通过8005端口,给Tomcat发起特殊的请求,Tomcat就关闭了,这就能执行destory
  2. 直接杀死Tomcat进程,比如使用任务管理器关闭Tomcat服务器,才是就不能执行desstory方法

service方法:service中根据请求的类型不同,调用不同的方法,doGet,doPost方法等等,会执行多次,每收到一次HTTP请求就执行一次

面试题:谈谈Servlet的生命周期

  1. webapp刚被加载的时候,调用servlet的init方法
  2. 每次收到请求的时候,调用service方法
  3. webapp要结束的时候,调用destory方法

注意:HttpServlet的实例只是在程序启动时创建一次,而不是每次收到HTTP请求都重新创建实例

2.1.1、处理Get请求

1、直接在浏览器中,通过URL就能构造(GET请求最常用法)

2、通过postman构造Get请求

3、通过ajax构造Get请求

2.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 对象

注意:请求对象是服务器收到的内容, 不应该修改。因此上面的方法也都只是 "读" 方法, 而不是 "写"方法。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/request")
public class RequestServlet extends HelloServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //显示告诉浏览器,你拿到的数据是html
        resp.setContentType("text/html");
        //调用req的各个方法,把得到的结果汇总到一个字符串中,统一返回到页面上
        StringBuilder respBody = new StringBuilder();

        //下列内容是在浏览器上按照html方式来展示的,此时\n在html中并不是换行
        //而我们需要使用<br>标签进行换行
        respBody.append(req.getProtocol()); //HTTP版本号
        respBody.append("<br>");
        respBody.append(req.getMethod()); //返回HTTP方法的名称
        respBody.append("<br>");
        respBody.append(req.getRequestURI()); //请求路径
        respBody.append("<br>");
        respBody.append(req.getContextPath()); //上下文路径
        respBody.append("<br>");
        respBody.append(req.getQueryString()); //QuertString
        respBody.append("<br>");

        //拼接header
        //获取请求的header头
        Enumeration<String> headers = req.getHeaderNames();
        while (headers.hasMoreElements()) {
            String headerName = headers.nextElement();
            respBody.append(headerName);
            respBody.append(": ");
            respBody.append(req.getHeader(headerName));
            respBody.append("<br>");
        }
        //统一返回结果
        resp.getWriter().write(respBody.toString());
    }
}

浏览器响应结果如下: 

2.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 中写入二进制格式数据

注意:响应对象是服务器要返回给浏览器的内容,这里的重要信息都是程序员设置的。因此上面的方法都是"写"方法。

注意:对于状态码/响应头的设置要放到getWriter/GetOutputStream之前,否则可能设置失效。

2.3.1、设置状态码

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/status")
public class StatusServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        //resp.setStatus(404);
        resp.setStatus(200);
        //返回Tomcat自带的错误页面
        resp.sendError(500);
    }
}

 2.3.2、自动刷新

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //告诉浏览器每隔2秒刷新一次
        resp.setHeader("refresh", "2");
        //返回系统时间
        resp.getWriter().write("time: " + System.currentTimeMillis());
    }
}

2.3.3、重定向 

实现一个程序,返回一个重定向HTTP响应,自动跳转到另一个页面

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/redirect")
public class Redirect extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //实现重定向,让浏览器自动跳转到百度浏览器
        resp.setStatus(302);
        //设置重定向,让浏览器自动跳转到百度
        resp.setHeader("Location", "https://www.baidu.com");
    }
}

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值