JavaWeb-03-Servlet-02-Servlet接口实现类

JavaWeb-03-Servlet-02-Servlet接口实现类

1.什么是Servlet接口,有什么用?

Servlet接口来自于Servlet规范中的一个接口,这个接口存在于Http服务器所提供的jar包中。

Servlet接口的具体位置:位于Tomcat服务器下的lib文件中的servlet-api.jar,在jar包中的位置:【javax.servlet.Servlet】。

在Servlet规范中,Http服务器能调用的【动态资源文件】必须是一个实现了Servlet接口的java类。

如:

class MyClass01 {
    //非Servlet接口实现类,不是动态资源文件,Tomcat服务器无权调用
}
class MyClass02 implements Servlet{
    //是Servlet接口实现类,是合法的动态资源文件,Tomcat服务器有权调用
}

2.Servlet接口实现类开发步骤(如何创建一个动态资源文件)

2.1第一步:创建一个java类继承HttpServlet

当一个java类继承抽象类HttpServlet后,这个java类就成为了一个Servlet接口实现类。

HttpServlet抽象类是GenericServlet抽象类的子类,而GenericServlet实现了Servlet接口,所以GenericServlet的子类HttpServlet以及HttpServlet的子类都是Servlet接口实现类。

                          (抽象类)		     (抽象类)			     (接口)
自己写的类----【继承】---->HttpServlet----【继承】---->GenericServlet----【实现】------>Servlet
[Servlet接口实现类]	 [Servlet接口实现类]	     [Servlet接口实现类]
                        - service()【实现】           - init()【实现】              - init()【抽象方法】
                                                     - getServletConfig()【实现】   - getServletConfig()【抽象方法】
                                                     - getServletInfo()【实现】     - getServletInfo()【抽象方法】
                                                     - destroy()【实现】            - destroy()【抽象方法】
                                                     - service()【仍是抽象方法】     - service()【抽象方法】

为什么不直接让自己写的类直接实现Servlet接口呢?

理由是:

  1. 当实现一个接口后必须实现该接口中所有的方法。
  2. 而在Servlet接口的所有方法中,我们只需要使用其中一个方法service,其他方法不需要实现。
  3. 为了降低接口实现类实现接口过程的难度,就将接口中实现类所不需要的抽象方法交给抽象类来完成。这样接口实现类只需要对接口中需要的方法进行重写。

Servlet接口:

接口实现类不需要的抽象方法:

  • init()
  • getServletConfig()
  • getServletInfo()
  • destroy()

接口实现类需要的抽象方法:

  • service()

Tomcat根据规范调用Servlet接口实现类规则:

  1. Tomcat有权创建Servlet接口实现类实例对象

    • Servlet sltDemo = new ServletDemo01();
      
  2. Tomcat根据实例对象调用service方法处理当前请求:

    • sltDemo.service();
      

2.2第二步:重写HttpServlet中的两个方法【doGet、doPost】

package com.tsccg.controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author: TSCCG
 * @Date: 2021/08/12 11:35
 */
public class ServletDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ServletDemo01类对浏览器发送的GET请求作出处理");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ServletDemo01类对浏览器发送的POST请求作出处理");
    }
}

浏览器发送请求的方式有两种:GET和POST

在浏览器发送请求时,将请求方式信息放入Http请求协议包里的【请求行】中。

请求行:[
    URL:请求地址
    Method:【GET/POST】
]
请求头:[...]
空白行:[...]
请求体:[...]
  • 当为GET时,Tomcat服务器通过动态资源文件实例对象调用doGet()方法对请求进行处理
  • 当为POST时,Tomcat服务器通过动态资源文件实例对象调用doPost()方法对请求进行处理
		GET
浏览器--------->sltDemo.doGet()//1.第一种:GET
		POST
浏览器--------->sltDemo.doPost()//2.第二种:POST

但在前面不是说过,处理当前请求是通过service方法吗?

  • Servlet sltDemo = new ServletDemo01();
    sltDemo.service();
    

底层抽象类HttpServlet实现了service方法,我们可以看看是如何实现的:

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String method = req.getMethod();//获取请求方式【GET/POST】
    long lastModified;
    if (method.equals("GET")) {//如果请求方式是GET,那么就执行this.doGet(req, resp);
        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")) {//如果请求方式是POST,那么就执行this.doPost(req, resp);
        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抽象类实现的service()方法中,

根据请求方式信息执行【this.doGet(req, resp)】或【this.doPost(req, resp)】

其中,this指的是当前实例对象。

当子类ServletDemo继承父类HttpServlet后,子类也继承了父类实现的service()方法,

在子类重写父类中的doGet()和doPost()方法后,如果用子类的实例对象去调用service()方法:

Servlet sltDemo = new ServletDemo01();
sltDemo.service();

那么在service()方法中执行的【this.doGet(req, resp)】或【this.doPost(req, resp)】中的this,就是当前子类的实例对象【sltDemo】,调用的doGet()或doPost()方法就是子类重写的方法。

这种通过父类来决定在什么情况下调用子类中方法的模式,在设计模式中被称为【模板设计模式】。

2.3将Servlet接口实现类信息"注册"到Tomcat服务器

"注册",在这里是通知的意思。

在一个网站中,会有很多的java类,其中有普通java类和动态资源文件,而Tomcat服务器无法区分哪些是动态资源文件。

所以,我们就需要通知Tomcat服务器哪些是可以操作的动态资源文件。

如何通知呢?我们可以通过配置web目录下的WEB-INF文件夹中存储的web.xml文件来实现。

[网站]--->[web]--->[WEB-INF]--->[web.xml]

在web-app标签栏内写入如下配置信息:

<!-- 将Servlet接口实现类的类路径地址交给Tomcat服务器 -->
<servlet>
    <servlet-name>demo01Path</servlet-name><!-- 声明一个变量,用于存储Servlet接口实现类的类路径地址 -->
    <servlet-class>com.tsccg.controller.ServletDemo01</servlet-class><!-- Servlet接口实现类的类路径 -->
</servlet>
<!-- 以上语句作用:Tomcat:String demo01 = "com.tsccg.controller.ServletDemo01"; -->
<!-- 由于java类的类路径一般都很长,用户在浏览器中请求时非常不便。
【http://localhost:8080/MyWeb/com/tsccg/controller/ServletDemo01】
为了降低用户访问Sevlet接口实现类的难度,我们需要设置一个简短的别名 -->
<servlet-mapping>
	<servlet-name>demo01Path</servlet-name><!-- 上面的变量名 -->
    <url-pattern>/demo01</url-pattern><!-- 别名【一定要在开头加一个斜杠/】 -->
</servlet-mapping>
<!-- 
现在通过浏览器索要ServletDemo01时需要写的地址:
【http://localhost:8080/MyWeb/demo01】 
-->

然后发布网站:

开启服务器并通过浏览器访问ServletDemo01:

我们通过浏览器地址栏发送的请求,都是【GET】方式。

当Tomcat服务器接收到【GET】请求后,创建ServletDemo01的实例对象,并调用service方法处理当前请求。

在service()方法里,根据【GET】请求方式,执行【this.doGet(req, resp);】。即用当前实例对象调用实例对象中重写的doGet方法。

posted @ 2021-08-12 20:10  TSCCG  阅读(96)  评论(0编辑  收藏  举报