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");
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/513547.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

wsl.conf在windows的什么路径

结论 全局的.wslconfig找不到。 局部的wsl.conf在ubuntu中的/etc/wsl.conf。 官网 https://learn.microsoft.com/zh-cn/windows/wsl/wsl-config .wslconfig 使用 .wslconfig 为 WSL 上运行的所有已安装的发行版配置全局设置。 默认情况下&#xff0c;.wslconfig 文件不存在。…

Hadoop MapReduce

MapReduce分为两个阶段&#xff0c;分为Map阶段和Reduce阶段&#xff0c;可以自定义map函数和reduce函数&#xff0c; map函数的输入是行在文件的字节偏移量&#xff0c;value是文件的一行数据。 reduce函数的输入是key和对应key的value组&#xff0c;然后reduce函数可以对这…

【Linux】SSH协议应用

SSH协议 SSH简介实现OpenSSH ssh中的四个文件~/.ssh文件路径实验解析 SSH 简介 SSH&#xff08;secure shell&#xff09;只是一种协议&#xff0c;存在多种实现&#xff0c;既有商业实现&#xff0c;也有开源实现。本文针对的实现是OpenSSH&#xff0c;它是自由软件&#xf…

面试题:RabbitMQ 消息队列中间件

1. 确保消息不丢失 生产者确认机制 确保生产者的消息能到达队列&#xff0c;如果报错可以先记录到日志中&#xff0c;再去修复数据持久化功能 确保消息未消费前在队列中不会丢失&#xff0c;其中的交换机、队列、和消息都要做持久化消费者确认机制 由spring确认消息处理成功后…

字符分类函数

字符分类函数 C语言中有⼀系列的函数是专门做字符分类的&#xff0c;也就是⼀个字符是属于什么类型的字符的。这些函数的使用都需要包含⼀个头文件是 ctype.h 这些函数的使用方法非常类似&#xff0c;我们就讲解⼀个函数的事情&#xff0c;其他的非常类似&#xff1a; int i…

蓝桥杯速成5-AD/DA模数转换

一、原理图 上图可知该芯片使用的是iic时序&#xff0c;而不是51单片机的xpt2046时序&#xff0c;iic我们都很熟悉了吧 并且大赛还提供了我们iic底层驱动代码 左上角有AIN0-4四个转换输入通道&#xff0c;和AOUT一个输出通道&#xff0c;由控制字节选择 地址字节&#xff1a;0x…

Linux性能分析工具-perf并生成火焰图

1 简介 perf 是一个非常实用且深入的性能分析工具&#xff0c;适用于从底层硬件交互到上层应用程序逻辑的全方位性能剖析。 perf 工具的设计目的是为了帮助开发者和系统管理员分析应用程序以及内核本身的性能&#xff0c;寻找潜在的性能瓶颈&#xff0c;并据此进行针对性的优…

向上转型与向下转型

首先&#xff0c;一个对象在new的时候创建是哪个类型的对象&#xff0c;它从头至尾都不会变。即这个对象的运行时类型&#xff0c;本质的类型用于不会变。但是&#xff0c;把这个对象赋值给不同类型的变量时&#xff0c;这些变量的编译时类型却不同。 7.6.1 为什么要类型转换 …

实景三维技术在推进城市全域数字化转型的作用

4月2日&#xff0c;国家数据局发布《深化智慧城市发展推进城市全域数字化转型的指导意见&#xff08;征求意见稿&#xff09;》&#xff08;下称&#xff1a;《指导意见》&#xff09;&#xff0c;向社会公开征求意见。 《指导意见》作为推进城市数字化转型的重要文件&#xf…

蓝桥杯刷题day09——霓虹【算法赛】

一、问题描述 晚上,小蓝正无聊的走在大路上,小蓝所在的街区是—个带有赛博朋克风格的街区。 他抬头—看,看到了很多霓虹灯牌。在其中的某一个店铺前,挂着一排的数字灯牌,每一个数字的显示都依靠7段LED管,亮着的灯管组成数字,具体来说如下图所示: 小蓝刚学过数字电路,他…

Makefile:调用shell脚本和嵌套调用多项目编译(九)

1、Makefile中调用shell脚本 Makefile中可以通过使用$(shell 指令)的方式调用shell脚本a指令&#xff1a;输出当前文件夹下的所有文件b指令&#xff1a;输出当前路径c指令&#xff1a;如果当前目录下不存在abc文件那么创建一个abc的文件 a$(shell ls ./) b$(shell pwd) filen…

神经网络与深度学习(二)

一、深度学习平台 张量&#xff08;Tensor&#xff09; 是一个物理量&#xff0c;对高维(维数 ≥ 2) 的物理量进行“量纲分析” 的一种工具。简单的可以理解为&#xff1a;一维数组称为矢量&#xff0c;二维数组为二阶张量&#xff0c;三维数组为三阶张量 计算图 用“结点”…

Transformer模型-用jupyter演示逐步计算attention

学习transformer模型-用jupyter演示如何计算attention&#xff0c;不含multi-head attention&#xff0c;但包括权重矩阵W。 input embedding&#xff1a;文本嵌入 每个字符用长度为5的向量表示&#xff1a; 注意力公式&#xff1a; 1&#xff0c;准备Q K V&#xff1a; 先 生…

官宣!一文掌握2024百度CreateAI开发者大会最新议程

4月16日上午9:00&#xff0c;以“创造未来”为主题的2024百度Create AI开发者大会将在深圳国际会展中心&#xff08;宝安&#xff09;开幕。此次大会将是近十年来&#xff0c;粤港澳大湾区规格最高的AI大会&#xff0c;将聚焦炙手可热的AI话题&#xff0c;在大会主论坛、分论坛…

【JVM】如何定位、解决内存泄漏和溢出

目录 1.概述 2.堆溢出、内存泄定位及解决办法 2.1.示例代码 2.2.抓堆快照 2.3.分析堆快照 1.概述 常见的几种JVM内存溢出的场景如下&#xff1a; Java堆溢出&#xff1a; 错误信息: java.lang.OutOfMemoryError: Java heap space 原因&#xff1a;Java对象实例在运行时持…

Python快速入门系列-10(Python进阶与扩展)

第十章:Python进阶与扩展 10.1 Python与其他语言的整合10.1.1 使用Python的C API示例:使用C API创建一个简单的Python扩展10.1.2 使用Cython加速Python代码示例:使用Cython编写一个快速的矩阵乘法函数10.1.3 使用SWIG创建接口示例:使用SWIG为C++类生成Python接口10.2 Pytho…

【项目实战经验】DataKit迁移MySQL到openGauss(上)

前言 本文将分享DataKit迁移MySQL到openGauss的项目实战&#xff0c;供广大openGauss爱好者参考。 1. 下载操作系统 https://www.openeuler.org/zh/download https://support.huawei.com/enterprise/zh/doc/EDOC1100332931/1a643956 https://support.huawei.com/enterprise…

深入浅出 PyTorch

深入浅出Pytorch 目录&#xff1a; 为什么要学习pyTorch学哪类知识如何学习和掌握PyTorchPyTorch学习路径注意事项 PyTorch 优点 上手快&#xff1a;掌握Numpy和基本深度学习概念即可上手代码简洁灵活&#xff1a;用nn.module封装使网络搭建更方便&#xff1b;基于动态图机…

芒果YOLOv8旋转检测改进《旋转检测必看》提升篇149:从零开始训练 YOLOv8旋转检测教程说明,芒果改进推荐教程

芒果YOLOv8旋转检测改进《旋转检测必看》提升篇149&#xff1a;从零开始训练 YOLOv8旋转检测教程说明&#xff0c;芒果改进推荐教程 本文适用Windows/Linux/Mac&#xff1a;从零开始使用Windows/Linux/Mac训练 YOLOv8 算法项目 - 《旋转检测任务》 专栏完整目录链接&#xf…

编译 amd gpu 核心态驱动 rocm kmd linux kernel

AMD 开源了专门的 ROCm 的kmd Linux Kernel&#xff0c; 1,下载源代码 git clone --recursive https://github.com/ROCm/ROCK-Kernel-Driver.gitcd ROCK-Kernel-Driver/git checkout rocm-6.0.22,配置kernel cp -v /boot/config-$(uname -r) .config make menuconfig Graph…