• 带你着手「Servlet」


    在这里插入图片描述

    请添加图片描述

    ⭐️前言⭐️

    有了前边文章为我们奠定下的网络基础,我们就可以开始学习Servlet的知识了,在部署一个Java的Servlet程序时,必须要有的开发工具是Tomcat,需要自行完成Tomcat的配置,并掌握maven仓库的配置方法,下边我们也会进行演示,这些具体的流程该如何来进行。

    🍉博客主页: 🍁【如风暖阳】🍁
    🍉精品Java专栏【JavaSE】【备战蓝桥】、【JavaEE初阶】【MySQL】【数据结构】
    🍉欢迎点赞 👍 收藏留言评论 📝私信必回哟😁

    🍉本文由 【如风暖阳】 原创,首发于 CSDN🙉

    🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

    🍉博客中涉及源码及博主日常练习代码均已上传码云(gitee)GitHub


    请添加图片描述

    请添加图片描述

    🍅1.第一个Servlet程序

    我们首先通过idea来完成一个最简单的Servlet程序,共需要以下七步来完成,在该部分最后也会介绍较为简单的插件配置方法。

    1.1 操作流程

    第一步
    创建一个maven项目。

    1)新建项目
    2ae400de2.png)

    2)选择maven项目
    在这里插入图片描述

    3)编辑信息
    在这里插入图片描述
    第二步
    引入依赖

    1)在maven中央仓库找到Servlet的依赖
    在这里插入图片描述
    2)找到3.1版本,复制maven依赖
    在这里插入图片描述
    在这里插入图片描述
    3)将依赖引入pom.xml文件中
    在这里插入图片描述
    第三步
    创建目录结构

    1)在main目录创建webapp目录
    在这里插入图片描述
    2)在webapp目录创建WEB-INF目录
    在这里插入图片描述
    3)在WEB-INF目录新建web.xml文件
    在这里插入图片描述
    4)在web.xml文件中写入下面的代码段:

    <!DOCTYPE web-app PUBLIC
            "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
            "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
        <display-name>Archetype Created Web Application</display-name>
    </web-app>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    第四步
    编写Servlet代码

    main-java目录下新建类,开始编写servlet代码
    在这里插入图片描述

    • 继承HttpServlet
    • 重写doGet方法
    • 在方法里写执行的代码
    • 加上WebServlet注解+路径,将该类与http请求中的URL关联起来

    在这里插入图片描述

    第五步
    打包

    当前的代码是不能单独运行的(没有main方法),需要把当前的代码打包,然后部署到Tomcat上,由Tomcat来进行调用。

    1)先进行准备工作,修改pom.xml
    在这里插入图片描述
    2)双击package,进行打包
    在这里插入图片描述
    打包完成
    在这里插入图片描述
    第六步
    部署

    1)打开war包所在路径
    在这里插入图片描述
    2)把war包拷贝到tomcatwebapps目录里
    在这里插入图片描述

    在这里插入图片描述
    3)启动tomcat

    在这里插入图片描述
    在这里插入图片描述

    第七步
    验证程序

    在网页访问路径127.0.0.1:8080/hello/test
    在这里插入图片描述
    此处的路径共有三部分组成
    在这里插入图片描述

    1.2 插件简化

    在我们每次修改Servlet类代码后,都需要重复进行1.1中5-6步操作,较为繁琐,可以利用idea中内嵌的smart tomcat插件来简化开发流程。
    在这里插入图片描述
    完成上图插件的安装后,按下图流程操作。
    在这里插入图片描述
    注意,利用插件时,五六步操作完全不再需要手动进行了,不需要再进行第五步的准备工作——在pom.xml文件中加代码,直接在下图中定义Context Path即可。
    在这里插入图片描述
    点击小三角一次性完成打包、部署工作:在这里插入图片描述

    🍅2.常见的访问出错

    初学Servlet,肯定会遇到很多的问题,我们不仅要学习Servlet代码的基本写法,还需要认识常见的错误,在出现错误时能够解决。

    2.1 出现404

    404表示用户访问的资源不存在,大概率是URL路径写的不正确。
    在这里插入图片描述
    还有可能是因为web.xml文件写错了,需要写正确web.xml中内容,并重新启动tomact

    web.xml文件代码片段:

    DOCTYPE web-app PUBLIC
            "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
            "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
        <display-name>Archetype Created Web Applicationdisplay-name>
    web-app>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.2 出现405

    405表示对应的HTTP请求方法没有实现
    在这里插入图片描述
    在地址栏输入URL路径进行访问,浏览器默认构造的是GET请求,如果在服务器中的代码没有实现doGet方法,就会报这个错误。
    在这里插入图片描述

    在什么时候浏览器发的是GET请求呢?
    1.直接在地址栏里输入URL
    2.通过a标签跳转
    3.通过img/link/script...
    4.通过form表单,method指定为GET
    5.通过ajax,type指定为GET

    那在什么时候浏览器发的是POST请求呢?
    1.通过form表单,method指定为POST
    2.通过ajax,type指定为POST

    2.3 出现500

    500意味着服务器代码抛出异常了,并且代码没有处理异常,异常向上传递到了Tomcat这里了。
    在这里插入图片描述
    在这里插入图片描述
    这种错误是最好解决的,因为异常的调用栈,会直接打印在页面上,可以直接找到问题的所在。

    2.4 出现空白页面

    没有resp.getWritter().write() 操作。
    在这里插入图片描述

    2.5 出现“无法访问此网站”

    最大可能性是因为Tomcat没有正确启动(比如Tomcat的8080端口被占用,启动失败)
    在这里插入图片描述

    🍅3.Servlet运行原理

    3.1 Servlet运行原理

    Servlet是位于应用层的上层建筑,下面的传输层、网络层、和数据链路层属于经济基础,经济基础决定上层建筑。

    Tomcat其实就是一个运行在用户态的应用程序(普通的Java进程)。
    在这里插入图片描述
    当用户操作浏览器,发送请求给服务器的时候,Tomcat作为HTTP Servlet会调用Servlet API,然后执行我们所写的Servlet程序来处理请求。
    在这里插入图片描述
    更详细的交互过程见下图:
    在这里插入图片描述
    用户浏览器发出请求后,客户端主机会将请求数据包一层层封装,最后到物理层转换成光电信号传输给服务器;到达服务器后再将数据包进行一层层分用,最后到服务器的应用层处理请求并计算响应

    3.2 Tomcat的执行逻辑

    我们通过用伪代码的方式来演示Tomcat在Servlet程序运行中起到的作用。

    1)Tomcat初始化流程

    class Tomcat {
        // 用来存储所有的 Servlet 对象
        private List<Servlet> instanceList = new ArrayList<>();
        public void start() {
            // 根据约定,读取 WEB-INF/web.xml 配置文件;
            // 并解析被 @WebServlet 注解修饰的类
    
            // 假定这个数组里就包含了我们解析到的所有被 @WebServlet 注解修饰的类. 
            Class<Servlet>[] allServletClasses = ...;
    
            // 这里要做的的是实例化出所有的 Servlet 对象出来;
            for (Class<Servlet> cls : allServletClasses) {
                // 这里是利用 java 中的反射特性做的
                // 实际上还得涉及一个类的加载问题,因为我们的类字节码文件,是按照约定的
                // 方式(全部在 WEB-INF/classes 文件夹下)存放的,所以 tomcat 内部是
                // 实现了一个自定义的类加载器(ClassLoader)用来负责这部分工作。
    
                Servlet ins = cls.newInstance();
                instanceList.add(ins);
            }
    
            // 调用每个 Servlet 对象的 init() 方法,这个方法在对象的生命中只会被调用这一次;
            for (Servlet ins : instanceList) {
                ins.init();
            }
    
            // 利用我们之前学过的知识,启动一个 HTTP 服务器
            // 并用线程池的方式分别处理每一个 Request
            ServerSocket serverSocket = new ServerSocket(8080);
            // 实际上 tomcat 不是用的固定线程池,这里只是为了说明情况
            ExecuteService pool = Executors.newFixedThreadPool(100);
    
            while (true) {
                Socket socket = ServerSocket.accept();
                // 每个请求都是用一个线程独立支持,这里体现了我们 Servlet 是运行在多线程环境下的
                pool.execute(new Runnable() {
                    doHttpRequest(socket);//处理请求
                });
            }
            // 调用每个 Servlet 对象的 destroy() 方法,这个方法在对象的生命中只会被调用这一次;
            for (Servlet ins : instanceList) {
                ins.destroy();
            }
        }
    
        public static void main(String[] args) {
            new Tomcat().start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    小结:

    • Tomcat的代码中内置了main方法。当我们启动Tomcat的时候,就是从Tomcat的main方法开始执行的。
    • @WebServlet注解修饰的类会在Tomcat启动的时候被获取到,并集中管理。
    • Tomcat通过反射机制来创建被@WebServlet注解修饰的类的实例。
    • 这些实例被创建完了之后,会调用其中的init方法进行初始化(该方法是HttpServlet自带的,我们自己写的类可以重写init)
    • 这些实例被销毁之前,会调用其中的destory方法进行收尾工作(只有正常退出Tomcat才会触发该方法,而通过直接杀死进程的方法是来不及调用该方法的)
    • Tomcat内部也是通过Socket API进行网络通信
    • Tomcat为了能同时响应多个HTTP请求,采取了多线程的方式实现。因此Servlet是运行在多线程环境下的

    2)Tomcat处理请求流程

    class Tomcat {
        void doHttpRequest(Socket socket) {
            // 参照我们之前学习的 HTTP 服务器类似的原理,进行 HTTP 协议的请求解析,和响应构建
            HttpServletRequest req = HttpServletRequest.parse(socket);
            HttpServletRequest resp = HttpServletRequest.build(socket);
            
            // 判断 URL 对应的文件是否可以直接在我们的根路径上找到对应的文件,如果找到,就是静态
            // 直接使用我们学习过的 IO 进行内容输出
            if (file.exists()) {
                // 返回静态内容
                return;
           }
            
            // 走到这里的逻辑都是动态内容了
            
            // 根据我们在配置中说的,按照 URL -> servlet-name -> Servlet 对象的链条
            // 最终找到要处理本次请求的 Servlet 对象
            Servlet ins = findInstance(req.getURL());
            
            // 调用 Servlet 对象的 service 方法
            // 这里就会最终调用到我们自己写的 HttpServlet 的子类里的方法了
            try {
           		ins.service(req, resp); 
           } catch (Exception e) {
                // 返回 500 页面,表示服务器内部错误
           }
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    小结:

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

    3)Servlet的service方法的实现

    class Servlet {
        public void service(HttpServletRequest req, HttpServletResponse resp) {
            String method = req.getMethod();
            if (method.equals("GET")) {
                doGet(req, resp);
           } else if (method.equals("POST")) {
                doPost(req, resp);
           } else if (method.equals("PUT")) {
                doPut(req, resp);
           } else if (method.equals("DELETE")) {
                doDelete(req, resp);
           } 
           ......
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    小结:

    • Servlet的service方法内部会根据当前请求的方法,决定调用其中的某个doXXX方法。

    在整个流程中,有三个关键的方法

    • init方法:在初始化阶段执行,用来初始化每一个Servlet对象,对象创建好之后就会执行到。用户可以重写这个方法,来执行一些初始化逻辑。
    • service方法:在处理请求阶段来调用,每个请求都要调用一次service
    • destory方法:退出主循环,tomcat结束之前会调用,用来释放资源。

    ⭐️最后的话⭐️
    总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁

    请添加图片描述

  • 相关阅读:
    抖音视频评论数据提取软件|抖音数据抓取工具
    论文阅读《Sylph: A Hypernetwork Framework for Incremental Few-shot Object Detection》
    LeetCode 89 格雷编码
    键盘方向键移动当前选中的table单元格,并可以输入内容
    TDengine 如何进行 SQL 写入?官方最全教程来了
    Aspose.cells帮助能源企业轻松实现经营分析
    CentOS下安装Mysql 8.0步骤详解
    高性能MySQL实战第12讲:海量数据MySQL项目实战
    2024年Q1季度冰箱行业线上市场销售数据分析
    [Asp.Net Core]C#解析Markdown文档
  • 原文地址:https://blog.csdn.net/qq_60856948/article/details/127601667