第七章Servlet

news2024/10/6 14:15:55

文章目录

  • 什么是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("正在实例化....");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("正在初始化.....");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("正在服务.....");
    }

    @Override
    public 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 {
    @Override
    protected 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 {
    @Override
    protected 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 {
    @Override
    protected 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 {
    @Override
    protected 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 {
    @Override
    protected 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 {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取application保存作用域保存的数据,key为uname
        ServletContext 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.coloradmin.cn/o/102189.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零基础如何学好Python开发?

作为一个零基础小白想学好Python开发应该先确定明确目标、做好学习Python系统规划、选择适合的开发工具、进阶提升学习规划、多练多看加深对Python程序的理解&#xff0c;想入门一门编程语言就需要不断的进行练习。 一、明确目标 很多人在学习Python之前了解很少&#xff0c;很…

ShareSDK 安装教程

一、ShareSDK简介 ShareSDK是一种社会化分享组件&#xff0c;为iOS、Android、WP8 的APP提供社会化功能&#xff0c;集成了一些常用的类库和接口&#xff0c;缩短开发者的开发时间&#xff0c;还有社会化统计分析管理后台。ShareSDK移动开发者服务平台由广州掌淘网络科技有限公…

【C++进阶之路第一卷】预编译头加快编译速度

一、前言 最近在写项目的时候&#xff0c;发现随着项目越来越大&#xff0c;编译需要的时间也越来越长&#xff0c; 然后使用了预编译头&#xff0c;时间减少了很多&#xff01; 这个谁用谁知道&#xff0c;很 Nice&#xff01; 1. 预编译头的原理 简单来说就是将一些你认…

广域网简介、PE/CE/P基本概念理解、PPP协议详细介绍、PAP/CHAP认证介绍与配置、PPPOE会话建立详细介绍并配合实验抓包理解报文交互。

3.1.0 广域网&#xff08;简介、PPP、PAP、CHAP、PPPOE&#xff09; 观前温馨提示&#xff1a; 篇幅较大&#xff0c;本章主要有以下大点&#xff0c;可通过目录与右侧导航跳转观看&#xff1a; &#xff08;1&#xff09;广域网基本概念 &#xff08;2&#xff09;PPP协议介…

【Numpy基础知识】在ndarrays上索引

在ndarrays上索引 来源&#xff1a;Numpy官网&#xff1a;https://numpy.org/doc/stable/user/basics.html 文章目录在ndarrays上索引导包【1】基本索引【2】高级索引【3】结合高级索引和基本索引【3】现场访问【4】展开迭代器索引【5】为索引数组赋值【6】处理程序中可变数量的…

Python3 环境搭建

本章节我们将向大家介绍如何在本地搭建 Python3 开发环境。 Python3 可应用于多平台包括 Windows、Linux 和 Mac OS X。 Unix (Solaris, Linux, FreeBSD, AIX, HP/UX, SunOS, IRIX, 等等。)Win 9x/NT/2000Macintosh (Intel, PPC, 68K)OS/2DOS (多个DOS版本)PalmOSNokia 移动手…

浅谈转行Python的看法,分享我的学习方法

今天跟大家聊一下转行Python的看法和经验。本人之前是做Java开发的&#xff0c;后面因为公司需要Python技术&#xff0c;就接触到了Python&#xff0c;我发现Python比Java更加容易理解&#xff0c;简洁&#xff0c;后面随着Python项目的增多干脆就转行做Python开发了。 Python…

LaTeX教程(三)——文档格式排版

文章目录1. 章节目录1.1 生成章节1.2 生成目录2. 交叉引用和脚注2.1 交叉引用2.2 脚注3. 特殊环境3.1 列表3.2 文本对齐3.3 引用环境3.4 代码环境1. 章节目录 1.1 生成章节 写文章或者论文的时候&#xff0c;章节目录可谓是必不可少的&#xff0c;下面我们来聊聊LaTeX怎么处理…

Linux——安装和使用vmtools

实验1 Linux系统初识 一、安装和使用vmtools vmware tools是虚拟机VMware Workstation自带的一款工具&#xff0c;现在介绍ubuntu linux安装VMare tools。它的作用就是使用户可以从物理主机直接往虚拟机里面拖文件。如果不安装它&#xff0c;我们是无法进行虚拟机和物理…

【火电机组、风能、储能】高比例风电电力系统储能运行及配置分析附Matlab代码

​✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法…

第十三章ThreadLocal

文章目录什么是ThreadLocal基本使用常用方法使用ThreadLocal来解决使用sychronized解决ThreadLocal与synchronized的区别运用场景_事务案例场景构建引入事务JDBC中关于事务的操作的api常规解决方案常规方案的弊端ThreadLocal解决方案ThreadLocal方案的好处ThreaLocal的内部结构…

Java堆排序和代码实现详解

堆的定义 堆是计算机科学中一类特殊的数据结构的统称&#xff0c;堆通常可以被看做是一棵完全二叉树的数组对象。 堆的特性 1.它是完全二叉树&#xff0c;除了树的最后一层结点不需要是满的&#xff0c;其它的每一层从左到右都是满的&#xff0c;如果最后一层结点不是满的&…

Hadoop(入门)

一、Hadoop概述 1.1 Hadoop是什么 1&#xff09;Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 2&#xff09;主要解决&#xff0c;海量数据的存储和海量数据的分析计算问题。 3&#xff09;广义上来说&#xff0c;Hadoop通常是指一个更广泛的概念—Hadoop生态圈。…

[Vue3]自定义指令实现组件元素可拖拽移动

实现思路&#xff1a; 元素移动设计思路 1.在光标按下的时刻记录下光标的绝对位置坐标&#xff08;以视窗左上角为原点&#xff09;&#xff08;const {clientX, clientY} evt&#xff09; clientX / clientY 事件属性返回当事件被触发时光标指针相对于浏览器页面当前 body …

flutter系列之:移动端手势的具体使用

文章目录简介赋予widget可以点击的功能会动的组件可删除的组件总结简介 之前我们介绍了GestureDetector的定义和其提供的一些基本的方法&#xff0c;GestureDetector的好处就是可以把任何一个widget都赋予类似button的功能。 今天将会通过几个具体的例子来讲解一下GestureDet…

用ChatGPT写一段嵌入式代码

已剪辑自: https://mp.weixin.qq.com/s/uKkUwXx32LPkUYQK44z1lw 废话不多说&#xff0c;开整&#xff01; ChatGPT: Optimizing Language Models for Dialogue&#xff0c;即优化对话的语言模型&#xff0c;它以对话的方式进行交互。对话形式使ChatGPT能够回答后续问题&#…

性能测试---LoadRunner

目录 1.LoadRunner对比Jmeter的优势 2.LoadRunner三个组件之间的关系 3.学习VUG的使用 3.1创建性能测试脚本并进行录制 第一步:打开VUG,创建一个新的性能测试的脚本 第二步:对新建的脚本进行设置 第三步:启动WebTours服务 第四步:回到VUG中,点击录制按钮并设置录制选项…

学习编程的五个关键点!你需要get它,并运用!

总体来说&#xff0c;学习如何编程是一件较难的事情。我最近发现大学里的计算机课程和各种编程训练营错过了编程的一些重要因素&#xff0c;对新手的教学用了不太恰当的方法。于是&#xff0c;我准备分享一个成功的编程课程应该具备的五大基本支柱。 菜鸟的目标是掌握编程的基…

form表单发送put、delete、patch请求的实现过程

关于发送put、delete、patch请求底层实现过程 对于put这些请求&#xff0c;我们无法直接通过form表单发送&#xff0c;form表单仅支持get和post请求&#xff1b; 虽然我们无法直接通过form表单发送这些请求&#xff0c;但我们可以以form表单为载体做二次请求&#xff1a;使用f…

[附源码]计算机毕业设计Node.js宠物商店管理系统(程序+LW)

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…