Servlet接口实现类开发步骤及对象生命周期

23 篇文章 0 订阅

servlet接口实现类的开发步骤:

  • 创建一个类,让其继承HttpServlet类,使之成为servlet接口实现类
  • 重写HttpServlet中的doPost和doGet方法,以编写处理这两种请求的逻辑
  • 将servlet接口实现类的信息注册到Tomcat服务器

我们先来看第一步,创建一个类,让其继承HttpServlet类,使之成为servlet接口实现类:

一个类需要实现servlet的接口才能被服务器操作,如创建这个servlet实现类的对象,之后根据此实例对象调用service方法处理当前请求(如post或get)。

但直接继承servlet不太好,因为你需要实现这个接口的所有方法,事实上你要用的只是接口中的service方法,因此让你这个类继承HttpServlet更好,因为后者实现了那些你不需要的方法,所以继承了HttpServlet之后你可以专心的操作service方法。

HttpServlet是一个抽象类,其作用就是:降低接口实现类对接口实现过程的难度。https://www.bilibili.com/video/BV1y5411p7kb?p=2,16min左右。

下图是servlet接口中定义的方法,我们用不到前四个,只能用到service:
在这里插入图片描述

在这里插入图片描述
追根溯源,查看我们继承的HttpServlet类,发现里面并没有实现servlet中我们用不到的方法,于是继续查看GenericServlet类,发现其实现了Servlet接口:
在这里插入图片描述
在GenericServlet类中,destroy方法的实现:
在这里插入图片描述
getServletInfo的实现:
在这里插入图片描述
init实现:
在这里插入图片描述
getServletConfig实现:
在这里插入图片描述
可以看到,即便是直接实现Servlet接口的类,对这几个用不到的方法也没做啥事,然后:
在这里插入图片描述
我们发现在GenericServlet类中,把service方法给留出来了,他没有对其进行实现,而是在HttpServlet中对其进行了实现:

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();  // 获取请求的方法,即浏览器是以何种方式进行请求的:get或post
        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);
        }

    }

上面是说,我们要继承HttpServlet才方便做一些开发, 下面说一下继承此类之后要做啥

第二步,重写HttpServlet中的doPost和doGet方法,以编写处理这两种请求的逻辑:

问题来了,为啥要重写这俩方法呢?你刚刚不是说一个类实现了Servlet接口,然后Tomcat就能创建这个类的对象,在然后通过这个对象调用service方法吗?你现在又重写了这俩方法,那他俩是咋被调用的?我们先查看一下HttpServlet类可重写的方法:
在这里插入图片描述
发现有7个带do的方法,浏览器之前发送请求的时候有7种方式,但目前只考虑get和post两种了。

我们现在来看post和get方法是咋被调用的,继续看上面的service代码,解释在注释中:

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();  // 获取请求的方法,即浏览器是以何种方式进行请求的:get或post
        long lastModified;
        if (method.equals("GET")) {  // 如果是get方法
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);  // 如果是子类调用service,那么这个this就指向子类对象,此时如果重写doGet方法,即可编写我们想要的逻辑,doGet方法在此时即被调用,下方的doPost同理
            } 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")) {  // 和doGet同理
            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);
        }

    }

我们不必调用service、doGet和doPost方法,因为父类已经为我们做好了,这种由父类决定在何种情况下调用子类中的方法,在设计模式中称为–模板设计模式

上述逻辑为:
在这里插入图片描述
我们已经说了两步:1. 创建一个类,让其继承HttpServlet,以便Tomcat能创建这个类的对象;2. 实现doPost和doGet方法,以便我们写的类的对象能调用父类service方法进而处理post或get请求,下面是第三步:

第三步,将servlet接口实现类的信息注册到Tomcat服务器:

在这里插入图片描述
上图的全路径如图所示,如果想访问OneServlet.class,这么访问就太麻烦了:
在这里插入图片描述
因此用/one和全路径做映射,访问时更方便:
在这里插入图片描述

Servlet对象的生命周期

在这里插入图片描述
我们用代码来验证一下:
第一个servlet实现类,OneServlet:

public class OneServlet extends HttpServlet {
    public OneServlet() {
        System.out.println("OneServlet 实例对象被创建!");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

第二个servlet实现类,TwoServlet:

public class TwoServlet extends HttpServlet {
    public TwoServlet() {
        System.out.println("TwoServlet 实例对象被创建!");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    <servlet>
        <servlet-name>OneServlet</servlet-name>
        <servlet-class>com.atjx.controller.OneServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>TwoServlet</servlet-name>
        <servlet-class>com.atjx.controller.TwoServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    
    <servlet-mapping>
        <servlet-name>OneServlet</servlet-name>
        <url-pattern>/one</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>TwoServlet</servlet-name>
        <url-pattern>/two</url-pattern>
    </servlet-mapping>
</web-app>

可以看到,我们对TwoServlet配置了:<load-on-startup>1</load-on-startup>,这意味着TwoServlet的对象在Tomcat启动时就被创建,而OneServlet的对象会在第一次被访问时被创建。

现在运行上面程序:
在这里插入图片描述
我们发现TwoServlet实例被创建了,这是因为我们配置了相应设置,现在我们访问OneServlet:
在这里插入图片描述
在这里插入图片描述
OneServlet被创建,因为默认设置就是第一次访问servlet实现类的时候创建其对象。

现在我们再次访问:
在这里插入图片描述
在这里插入图片描述
发现doGet又执行了一次,但构造函数并没有执行第二次,这也是前面提到的,一个servlet实现类的对象只会被创建一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值