第七章Servlet

news/2024/11/17 6:49:28/

文章目录

  • 什么是Servlet
      • 为什么需要Servlet
      • 从不同角度来看Servlet
      • 总过程
  • Servlet之间的继承关系
      • Servlet接口接口中方法
      • GenericServlet抽象方法
      • HttpServlet 抽象子类
      • 小结
  • Servlet生命周期
      • 从Servlet接口方法开始
      • 修改Servlet创建对象的时机
  • Servlet容器
  • Servlet相关的保存作用域
      • request:一次请求响应范围
      • session:一次会话范围有效
      • application: 一次应用程序范围有效

什么是Servlet

为什么需要Servlet

Servlet名字的含义

  • Servlet=Server+applet
  • Server:服务器
  • applet:小程序
  • Servlet含义是服务器端的小程序

我们需要将一次HTTP请求-响应(不限于HTTP),对应到Java的语句(Java的语句一定放在方法中)——将请求-响应的处理过程对应到某个类下的方法对应起来——Servelet容器的功能

生活中的例子

./images

对应的web应用

./images

  • 在整个Web应用中,Servlet主要负责处理请求、协调调度功能。我们可以把Servlet称为Web应用中的**『控制器』**

  • Servlet是Java提供的一门动态web资源开发的技术,如何称为动态,也就是不同的用户访问一个资源,所展现的页面是不一样的,比如张三访问是张三欢迎你,李四访问是李四欢迎你,我访问是你不能访问该页面,类似这种功能的实现

  • Servlet是JavaEE的规范之一,其实就是一个接口,将来我们需要具有Servlet功能的类型来实现Servlet接口,并由web服务器来运行Servlet

  • Tomcat是一个轻量级的web服务器,可以称为web容器,Servlet容器,web服务器封装了http协议,简化我们的开发,其次将web项目部署到服务器中,可以对外提供网上浏览服务

img

从不同角度来看Servlet

img

总过程

img

Servlet之间的继承关系

Servlet的继承关系 - 重点查看的是服务方法(service())

image-20221211145758047

  • javax.servlet.Servlet接口
    • javax.servlet.GenericServlet抽象类
      • javax.servlet.http.HttpServlet抽象子类

Servlet接口接口中方法

public interface Servlet {void init(ServletConfig var1) throws ServletException;ServletConfig getServletConfig();void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;String getServletInfo();void destroy();
}
  • 这是Servlet的源码,我们看到有

    • void init(config) - 初始化方法

    • void service(request,response) - 服务方法

    • ​ void destory() - 销毁方法

GenericServlet抽象方法

  public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
  • void service(request,response) - 我们仍然是抽象的

HttpServlet 抽象子类

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {HttpServletRequest request;HttpServletResponse response;try {request = (HttpServletRequest)req;response = (HttpServletResponse)res;} catch (ClassCastException var6) {throw new ServletException("non-HTTP request or response");}this.service(request, response);}
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getMethod();long lastModified;if (method.equals("GET")) {lastModified = this.getLastModified(req);if (lastModified == -1L) {this.doGet(req, resp);} else {long ifModifiedSince;try {ifModifiedSince = req.getDateHeader("If-Modified-Since");} catch (IllegalArgumentException var9) {ifModifiedSince = -1L;}if (ifModifiedSince < lastModified / 1000L * 1000L) {this.maybeSetLastModified(resp, lastModified);this.doGet(req, resp);} else {resp.setStatus(304);}}} else if (method.equals("HEAD")) {lastModified = this.getLastModified(req);this.maybeSetLastModified(resp, lastModified);this.doHead(req, resp);} else if (method.equals("POST")) {this.doPost(req, resp);} else if (method.equals("PUT")) {this.doPut(req, resp);} else if (method.equals("DELETE")) {this.doDelete(req, resp);} else if (method.equals("OPTIONS")) {this.doOptions(req, resp);} else if (method.equals("TRACE")) {this.doTrace(req, resp);} else {String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[]{method};errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(501, errMsg);}}
  • void service(HttpServletRequest req, HttpServletResponse resp) - 不是抽象的
  • String method = req.getMethod(); 这个方法是获取请求的方式
    • 然后通过后面的if和else if的结构来通过什么类型的方法去执行不同的逻辑
      • 决定调用的是哪个do开头的方法
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_post_not_supported");if (protocol.endsWith("1.1")) {resp.sendError(405, msg);} else {resp.sendError(400, msg);}}
  • 在HttpServlet这个抽象类中,do方法都差不多
  • 那么在HttpServlet中这些do方法默认都是405的实现风格-要我们子类去实现对应的方法,否则默认会报405错误

小结

  1. 继承关系: HttpServlet -> GenericServlet -> Servlet
    2) Servlet中的核心方法: init() , service() , destroy()
    3) 服务方法: 当有请求过来时,service方法会自动响应(其实是tomcat容器调用的)
    在HttpServlet中我们会去分析请求的方式:到底是get、post、head还是delete等等
    然后再决定调用的是哪个do开头的方法
    那么在HttpServlet中这些do方法默认都是405的实现风格-要我们子类去实现对应的方法,否则默认会报405错误
    4) 因此,我们在新建Servlet时,我们才会去考虑请求方法,从而决定重写哪个do方法

Servlet生命周期

从Servlet接口方法开始

image-20221211172758372

我们所谓Servlert 生命周期:从出生到死亡的过程就是生命周期。对应Servlet中的三个方法:init(),service(),destroy()

例子

//演示Servlet的生命周期
public class Demo2 extends HttpServlet {public Demo2(){System.out.println("正在实例化....");}@Overridepublic void init() throws ServletException {System.out.println("正在初始化.....");}@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("正在服务.....");}@Overridepublic void destroy() {System.out.println("正在销毁......");}
}

执行结果

//第一次访问Demo2
正在实例化....
正在初始化.....
正在服务.....
//第二次访问Demo2
正在服务.....
//第三次访问Demo3
正在服务.....

结论

默认情况下:

  • 第一次接收请求时,这个Servlet会进行实例化(调用构造方法)、初始化(调用init())、然后服务(调用service())

  • 从第二次请求开始,每一次都是服务

  • 当容器关闭时,其中的所有的servlet实例会被销毁,调用销毁方法 destroy()

  • 从调用构造方法可以看出 Servlet实例tomcat只会创建一个,所有的请求都是这个实例去响应。

    • 一般情况下,第一次请求时,tomcat才会去实例化,初始化,然后再服务.这样的好处是什么? 提高系统的启动速度 。 这样的缺点是什么? 第一次请求时,耗时较长。

      • 因此得出结论: 如果需要提高系统的启动速度,当前默认情况就是这样。如果需要提高响应速度,我们应该设置Servlet的初始化时机。

Servlet在容器中是:单例的、线程不安全的
- 单例:所有的请求都是同一个实例去响应
- 线程不安全:一个线程需要根据这个实例中的某个成员变量值去做逻辑判断。但是在中间某个时机,另一个线程改变了这个成员变量的值,从而导致第一个线程的执行路径发生了变化
- 我们已经知道了servlet是线程不安全的,给我们的启发是: 尽量的不要在servlet中定义成员变量。如果不得不定义成员变量,那么不要去:
- ①不要去修改成员变量的值
- ②不要去根据成员变量的值做一些逻辑判断

修改Servlet创建对象的时机

<!-- 配置Servlet本身 -->
<servlet><!-- 全类名太长,给Servlet设置一个简短名称 --><servlet-name>HelloServlet</servlet-name><!-- 配置Servlet的全类名 --><servlet-class>com.atguigu.servlet.HelloServlet</servlet-class><!-- 配置Servlet启动顺序 --><load-on-startup>1</load-on-startup>
</servlet>
  • 我们可以通过来设置servlet启动的先后顺序,数字越小,启动越靠前,最小值0,
  • 修改启动顺序后:创建就在Web应用启动过程中

小结

名称时机次数
创建对象默认情况:接收到第一次请求 修改启动顺序后:Web应用启动过程中一次
初始化操作创建对象之后一次
处理请求接收到请求多次
销毁操作Web应用卸载之前一次

Servlet容器

容器

在开发使用的各种技术中,经常会有很多对象会放在容器中。

容器提供的功能

容器会管理内部对象的整个生命周期。对象在容器中才能够正常的工作,得到来自容器的全方位的支持。

  • 创建对象
  • 初始化
  • 工作
  • 清理

容器本身也是对象

  • 特点1:往往是非常大的对象
  • 特点2:通常的单例的

典型Servlet容器产品举例

  • Tomcat
  • jetty
  • jboss
  • Weblogic
  • WebSphere
  • glassfish

Servlet相关的保存作用域

  • 原始情况下,保存作用域我们可以认为有四个: page(页面级别,现在几乎不用) , request(一次请求响应范围) , session(一次会话范围) ,application(整个应用程序范围)

request:一次请求响应范围

@WebServlet("/demo1")
public class Demo1 extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1向request保存作用域保存数据request.setAttribute("uname","lili");//向demo2进行客户端重定向response.sendRedirect("demo2");//向demo2进行服务器端转发request.getRequestDispatcher("demo2").forward(request,response);}
}
@WebServlet("/demo2")
public class Demo2  extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Object uname = request.getAttribute("uname");System.out.println("uname="+uname);}
}
  • 根据打印结果 :
    • 进行客户端重定向 我们的Demo2输出null,说明获取不到name这个属性的数据
    • 进行服务器转发 我们的Demo2输出了lsc,说明获得到了name这个属性的数据

image-20221213133006129

session:一次会话范围有效

@WebServlet("/demo3")
public class Demo3 extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {HttpSession session=request.getSession();session.setAttribute("uname","lili");//向demo2进行客户端重定向
//        response.sendRedirect("demo2");//3.服务器端转发request.getRequestDispatcher("demo2").forward(request,response);}
@WebServlet("dem04")
public class Demo4 extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {HttpSession session = request.getSession();System.out.println("uname"+session.getAttribute("uname"));}
}

根据打印结果 :

  • 我们使用同一个客户端(打开浏览器不关闭),不管是客户端重定向还是服务器转发都能获取到name的属性值
  • 如果使用的不是同一个客户端,不管是客户端重定向还是服务器转发都获取不到name的属性值

image-20221213141919228

application: 一次应用程序范围有效

@WebServlet("/demo5")
public class Demo5 extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.向application保存作用域保存数据//ServletContext : Servlet上下文ServletContext application = request.getServletContext();application.setAttribute("uname","lili");//2.客户端重定向response.sendRedirect("demo06");//3.服务器端转发//request.getRequestDispatcher("demo04").forward(request,response);}
}
@WebServlet("/demo6")
public class Demo6 extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.获取application保存作用域保存的数据,key为unameServletContext application = request.getServletContext();Object unameObj = application.getAttribute("uname");System.out.println("unameObj = " + unameObj);}
}
  • 不管是不是同一个客户端,不管是转发还是重定向都能获取到数据

image-20221213142758379

ServletContext : Servlet上下文

  • 什么叫上下文:

    • 拿生活中的例子,比如张三和李四在聊天,聊一个关于小明的八卦,他两已经聊了一会,突然王五来了说你们在聊啥,我想一起聊,王五想聊,就必须要知道张三和李四之前聊天的内容,才能加入他们一起聊小明的八卦,王五听张三和李四之前聊天的内容就是所谓的上下文
    • 我们的Servlet容器是Tomcat,我们可以不严谨的称为Servlet应用程序(因为有大量的Servlet),也就是我们的Servlet上下文,我们TomCat这次启动,也就是上下文开始
  • 代表:整个Web应用

  • 是否单例:是

  • xxxxxxxxxx1 1request.getContextPath()java

    • 获取某个资源的真实路径:getRealPath()
    • 获取整个Web应用级别的初始化参数:getInitParameter()
    • 作为Web应用范围的域对象
      • 存入数据:setAttribute()
      • 取出数据:getAttribute()

http://www.ppmy.cn/news/4982.html

相关文章

vue使用

目录 路由History模式打包页面空白 项目放根目录 -- 配置 项目放二级目录 -- 配置 路由History模式打包页面空白 项目放根目录 -- 配置 router > index.js 修改 base const router new VueRouter({mode: history,// base: process.env.BASE_URL,base: /,routes, }) ngi…

[ 渗透测试面试篇 ] 渗透测试面试题大集合(详解)(九)XXE 相关面试题

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

高级网络应用复习——三层热备生成树速端口OSPF实验(带命令)

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.知识点总结 路由器热备份技术HSRP &#xff08;思科私有 HS…

从云到「链」,京东云成为中国第四朵云背后

在产业加速到数实融合加速的今年&#xff0c;云计算不再是云厂商的唯一考校指标。 作者|叶子 出品|产业家 京东云再次破圈。 信号来自接连发布的几份报告。在国际权威研究机构Forrester发布的名为《The Forrester Wave&#xff1a;Public Cloud Development And Infrast…

如何多台OAK设备同时RTSP推流?

编辑&#xff1a;OAK中国 首发&#xff1a;oakchina.cn 喜欢的话&#xff0c;请多多&#x1f44d;⭐️✍ 内容可能会不定期更新&#xff0c;官网内容都是最新的&#xff0c;请查看首发地址链接。 ▌前言 Hello&#xff0c;大家好&#xff0c;这里是OAK中国&#xff0c;我是助手…

1557:祖孙询问——倍增求LCA

【题目描述】 已知一棵 n 个节点的有根树。有 m 个询问&#xff0c;每个询问给出了一对节点的编号 x 和 y&#xff0c;询问 x 与 y 的祖孙关系。 【输入】 输入第一行包括一个整数 n 表示节点个数&#xff1b; 接下来 n 行每行一对整数对 a 和 b 表示 a 和 b 之间有连边。如果…

代码随想录训练营第十二天

专题&#xff1a;栈和队列 题目&#xff1a;滑动窗口最大值 给定一个数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回滑动窗口中的最大值。 题目解析&#xff1a;…

Python如何调整数组的形状

文章目录更改维度调整坐标轴牛刀小试Numpy函数调整形状调整形状reshape, resize, flatten, ravel, squeeze调整坐标轴transpose, swapaxes 更改维度 数组中的数据在内存里是固定的&#xff0c;但计算时的排列方式却可以随时更改&#xff0c;这也是数组的强大之处。其中&#x…