• JavaWeb——Servlet原理、生命周期、IDEA中实现一个Servlet(全过程)


    6、servlet

    6.1、什么是servlet

    JavaWeb中,Servlet是基于Java编写的服务器端组件,用于处理客户端(通常是Web浏览器)发送的HTTP请求并生成相应的HTTP响应。Servlet运行在Web服务器上,与Web容器(如Tomcat)进行交互,通过Web容器将请求分发给适当的Servlet进行处理。

    Servlet提供了一种动态生成和处理Web内容的方式,可以接收并解析HTTP请求,执行业务逻辑,生成HTML、XML或其他格式的响应结果,并将其返回给客户端。Servlet可以处理各种不同类型的请求,如GET请求、POST请求等,并可以访问请求的参数、请求头、会话信息等。

    在Java中,编写一个Servlet需要继承自javax.servlet.http.HttpServlet类,并重写其中的一些方法,如doGet()、doPost()等。在这些方法中,开发人员可以编写处理请求和生成响应的逻辑。另外,Servlet也可以实现一些接口(如javax.servlet.Servlet、javax.servlet.Filter等),以实现更灵活的功能。

    Servlet在JavaWeb开发中扮演着非常重要的角色,它可以与数据库进行交互、调用其他Java类库、生成动态内容等。通过Servlet,开发人员可以实现Web应用程序中的用户认证、数据查询、数据处理、页面跳转等功能。

    需要注意的是,使用Servlet开发时,通常还会配合使用Web框架(如Spring MVC、Struts等)来简化开发流程和提供更强大的功能。

    • Sun公司在这些API中提供一个接口,叫做Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:
      • 编写一个类,实现Servlet接口
      • 吧开发好的Java类部署到web服务器中

    总而言之:把实现了Servlet接口的Java程序叫做:Servlet

    6.2、HelloServlet

    1. 构建一个Maven项目,构建一个空的Maven项目,我们从头开始写

    2. 打开pom.xml即核心配置文件,先配置一些依赖(空的项目中,pom.xml文件中除非必要,并无其他东西,因此是没有任何一点依赖的)

          <dependencies>
              <dependency>
                  <groupId>javax.servletgroupId>
                  <artifactId>javax.servlet-apiartifactId>
                  <version>4.0.1version>
                  <scope>providedscope>
              dependency>
              <dependency>
                  <groupId>javax.servlet.jspgroupId>
                  <artifactId>javax.servlet.jsp-apiartifactId>
                  <version>2.2.1version>
              dependency>
          dependencies>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      我们在此配置了servlet的一些相关依赖以及jsp的一些相关依赖

      依赖本质上是jar包,配置相关依赖,即在仓库中找到相应的jar包,如果报错,即仓库中没有该jar包,IDEA可能会提醒你安装,如果没有,则在网上找到相关资源下载并把jar包丢入仓库中

    3. 关于Maven父子工程的理解:我们一开始创建了一个空的Maven项目(Project),在这个项目中,我们还可以创建一些Maven模块(Module),当我们创建了一个名为servlet-01的Maven模块(以下我们称之为子项目)

      父项目的pom.xml中会有:

          <modules>
              <module>servlet-01module>
          modules>
      
      • 1
      • 2
      • 3

      子项目的pom.xml中会有:

          <parent>
              <groupId>com.XugroupId>
              <artifactId>javaweb-02-servletartifactId>
              <version>1.0-SNAPSHOTversion>
          parent>
      
      • 1
      • 2
      • 3
      • 4
      • 5

      (如果没有,可以手动添加)

      父项目中的jar包子项目可以直接使用,子项目的父项目无法直接使用,即类似于继承

    4. 将子Maven项目的结构搭建完整(创建java包,resource包等)忘记的同学可以回头看上面Maven配置的博客

    5. 编写一个Servlet程序

      1. 编写一个普通类

      2. 实现Servlet接口,这里我们直接继承HttpServlet(HttpServlet是Sun公司写好的,直接继承,不必实现)

        public class HelloServlet extends HttpServlet
        
        • 1

        进入HttpServlet的源码发现:

        public abstract class HttpServlet extends GenericServlet 
        
        • 1

        其同样继承了另一个类GenericServlet,再进入源码发现:

        public abstract class GenericServlet implements Servlet, ServletConfig, Serializable
        
        • 1

        GenericServlet最终实现了 Servlet接口,所以,即使是继承HttpServlet,同样也是实现Servlet接口

        Servlet接口中,有几个方法:

            void init(ServletConfig var1) throws ServletException;
        
            ServletConfig getServletConfig();
        
            void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
        
            String getServletInfo();
        
            void destroy();
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9

        其中,最为重要的是service方法,查看源码可以发现,GenericServlet没有实现该方法,而是将其定义为抽象方法:

        public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
        
        • 1

        在HttpServlet才最终实现了它:

            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 = req.getDateHeader("If-Modified-Since");
                        if (ifModifiedSince < lastModified) {
                            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);
                }
        
            }
        
        • 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

        当然,这其中还有许多方法需要被重写才能完成我们想要的功能

      3. 重写doGet方法和doPost方法

        public class HelloServlet extends HttpServlet {
            // 由于get或者post只是请求实现的不同方式,可以相互调用,业务逻辑都一样
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                // ServletOutputStream outputStream = resp.getOutputStream();
                PrintWriter writer = resp.getWriter();
                writer.print("Hello, Servlet");
            }
        
            @Override
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                super.doPost(req, resp);
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
      4. 编写Servlet的映射

        为什么需要映射:我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需给他一个浏览器能够访问的路径

        在web.xml文件中配置:

          
          <servlet>
            <servlet-name>helloservlet-name>
            <servlet-class>com.xu.servlet.HelloServletservlet-class>
          servlet>
          
          <servlet-mapping>
            <servlet-name>helloservlet-name>
            <url-pattern>/hellourl-pattern>
          servlet-mapping>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
      5. 配置Tomcat

      6. 启动测试

        1. 首先进入localhost时,是index.jsp页面,想要跳转到Servlet页面,则需要在域名后补上servlet-mapping的url-name,比如,在测试中,笔者所用的url-name为hello,则需要将域名改为:localhost:8080/s1/hello

      如果最终测试过程中,遇到:跳转到servlet页面时出现404的页面,则有可能是application context出现了问题,请进入smart tomcat中修改:

      在这里插入图片描述

      用项目名称,即project的名称,本示例中为javaweb-02-servlet

      如果遇到:跳转到servlet页面时出现500的情况,则是因为找不到相应的servlet的jar包,因此检查是否环境中配置了servlet的依赖,如果有,则查看Tomcat的版本:

      • Tomcat 9.x.x版本时,依赖中添加servlet的jar包名称为javax.servlet-api
      • Tomcat 10.x.x版本后,javax变更为javarta,因此查看是否依赖正确,如果不会修改,则卸载Tomcat 10 ,安装Tomcat 9(到目前为止,笔者使用的时Tomcat 10,但是在修改依赖时,将javax修改为javarta,会报错,还在查找原因当中,如果实在没有办法,笔者也只能将Tomcat 10 卸载,重新安装Tomcat 9)

    6.3、Servlet原理

    配置servlet

    想要Tomcat创建servlet实现类,就必须让Tomcat知道它在哪,因此我们在web.xml中配置servlet时,必须给出实现类的全限定类名

    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>
      
      <servlet>
        <servlet-name>helloservlet-name>
        
        <servlet-class>com.xu.servlet.HelloServletservlet-class>
      servlet>
      
      <servlet-mapping>
        <servlet-name>helloservlet-name>
        <url-pattern>/hellourl-pattern>
      servlet-mapping>
    web-app>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Tomcat会将被配置好的servlet放入HashMap中以待日后使用,当浏览器发送相应的请求时,Tomcat会在HashMap寻找相应的servlet,调用它并完成响应。

    而且,Tomcat并不会一开始就创建servlet对象,而是当浏览器发送相应的请求时,才会调用无参构造函数(若只有有参构造函数而没有无参构造函数,服务器是无法调用的,请在写servlet应用类时注意添加无参构造函数)去创建servlet对象。

    初始化:

    Servlet中有一个方法:init(ServletConfig var),它将会完成本Servlet的初始化功能,Tomcat在创建完成Servlet的实例化对象后,将会立即执行初始化操作

    service:

    service是servlet中十分重要的方法,当我们发送多次请求时,并不会重复创建servlet对象servlet实例化对象只会创建一个,也就是说,当一个servlet类的实例化对象被创造出来,后续发送的请求,都是由这个实例化对象进行回应),而是会不断调用service方法进行响应,比如,我们在service方法中加入以下代码:

        @Override
        public void init() throws ServletException {
            System.out.println("servlet---->init");
        }    
    
    	@Override
        public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
            System.out.println("servlet -----> service");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在发送多次请求时,我们可以发现:

    在这里插入图片描述

    servlet初始化操作只执行了一次,而service方法则每请求一次,便调用一次。

    销毁:

    通过调用destroy方法来销毁一个servlet对象,一般而言,关闭浏览器并不会销毁该servlet实例化对象,而是当服务器关闭时才会销毁,即:一个servlet对象的销毁是tomcat服务器调用其destroy方法来完成的。

    servlet生命周期:

    第一次发送请求 → Tomcat创建servlet对象→调用初始化方法init→执行service方法

    非首次发送请求→执行service方法

    关闭服务器→调用destroy方法

  • 相关阅读:
    CFdiv2-Intersection and Union-(线段树+转化求贡献)
    tomcat下载安装及配置教程
    微计算机断层扫描的用途以及测试样品要求
    Vite+Vue3EventBus,provide数据共享
    我有一篇Java Stream使用手册,学了就是你的了!
    三、C语言存储类
    web需要从文件中读取内容,将内容进行加密上传
    视图解析器常见功能、处理静态资源、类型转换器
    ESP-IDF学习——1.环境安装与hello-world
    在深度迁移学习中,什么是源域,什么是目标域?
  • 原文地址:https://blog.csdn.net/whale_cat/article/details/134029967