一小伙为了学会HttpServlet,居然自己亲手写了一个山寨版!

8 篇文章 0 订阅
4 篇文章 0 订阅

一文精通Servlet

题记

Servlet是一种Web组件,他与平台无关,属于一种中间件。运行在Tomcat服务器/Java程序/Servlet容器之中。负责与客户端进行操作

Servlet本身就是一组接口。这里注意接口的特性:接口里面所有的方法都要进行重写。

Servlet有两大功能:

  • 创建并且返回动态的HTML页面,也就是说在Javaweb中我们能够在客户端看到的页面是通过Servlet从服务器发送到客户端的。
  • 与数据库进行通信。

本质上,Servlet就是Java包中的一组接口,也就是说想要实现Servlet的开发,只需要写出Servlet所对应每个页面的实现类即可。而这里需要注意的是传统的Servlet(也就是直接implements Servlet)是需要重写他的全部方法的,因为它本质上是一个接口,而接口里的所有方法都必须要被重写。我们一般所使用的doGet或者doPost方法,其实实现的是Servlet的另外一种封装——HttpServlet。

亲手仿写一个山寨版的HttpServlet

当一个类,实现Servlet接口之后,需要重写的方法如下:

public class DemoServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

其中,各个方法所对应的是:

  • public void init(ServletConfig servletConfig) throws ServletException:对应的是初始化的方法,不常用。

  • public ServletConfig getServletConfig():获得Servlet的配置,不常用。

  • public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException:这是Servlet中最重要的方法,这也是Servlet中的主方法。所有对于逻辑上的实现,都是在这个方法中写出来的。

  • public String getServletInfo():不常用。

  • public void destroy():销毁Servlet,不常用。

(从中便可以看出,Servlet是有他自己的生命周期的。而关于这点在之后的文章中会有讲到。)

众所周知,Servlet是一个JavaWeb中的基石,可以说每一个页面甚至是一个页面中的一个操作可能都会对应一个Servlet。但是从上述介绍中能够看出,每一个Servlet比较重要(需要重写的)方法都是他的主方法——service,其他的方法相对来讲并不是非常的重要。但是由于接口的特性,每一次都需要重写Serviet中的所有方法,这显然是不够程序员的。因此,Java提供了一套Servlet层次结构,由上至下分别是:

  • HttpServlet
  • GenericServlet
  • Servlet

这三者的关系是由上至下,上者分别是下者的进一步封装或者使用。其实我们在实际开发的过程中,我们只需要直接继承HTTP Servlet就可以。具体实现方式:

public class TestServlet extends HttpServlet(){}

但是理解里面具体的逻辑还是非常有必要地。现在就通过亲手仿写一个HTTP Servlet实现来理解这个层次结构:

GenericServlet

Servlet是最底层的实现,也就是上两种的基石,很明显,如果想要实现Servlet首先需要进行实现Servlet的所有方法。

所以GenericServlet他其实本质上就是一个中间层,用于实现其所有的接口,并且向上层HttpServlet去返回一系列的方法和接口。

因此GenericServlet源代码其实最核心的功能就是实现了Servlet接口的实现类

public class MyGenericServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

HttpServlet

HttpServlet是我们在实际开发中最常用的一个方法,一般我们在写Servlet的时候都是直接继承HttpServlet。

public class MyDemoServlet extends HttpServlet {
    @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);
    }

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

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

我们知道HTTP请求分为好几种,其中最常用的就是以下四种:

  • GET
  • POST
  • PUT
  • DELETE

这四种分别对应着数据库GRUD四种操作:读取、保存、修改、删除。

所以这也对应着HttpServlet的四种方法,同样,也对应了Servlet本身第二种功能:与数据库进行数据交互。

PUT和DELETE平时用的频率其实也并不高,最高的还是GET和POST两种。那么两种都有什么区别呢?

通俗的来讲:

  • GET请求:只要通过浏览器中的url发送的数据打开的页面都是属于GET请求。
  • POST请求:只有通过表单来进行跳转或者需要通过表单来发送数据的请求都是POST请求。对应前端。

所以也就是说:这两种请求在HttpServlet中是区分开的,但是Servlet中,都是进入service方法进行处理的。而HttpServlet的本质,其实就是拿到跳转的类型,并且进入Servlet的实现类GenericServlet中的Service中在进行一层业务逻辑区分。那么也就是说:GenericServlet和HttpServlet的本质区别就是:

  • GenericServlet就是实现了Servlet的实现类,自身屏蔽了Servlet其他的不常用的方法,比如init初始化等。

  • HttpServlet就是在GenericServlet对应的主要方法中对HTTP的几种请求进行了业务逻辑处理,使其进入不同的业务逻辑方法。

那么我们来自己写一个山寨版的HttpServlet:

/**
 * 继承了MyGenericServlet的所有方法,所以父类中的方法在这里都不需要再去实现,只需要去重写需要的代码就可以
 * 知识点:注意继承父类和实现接口两者的区别。
 */
public class MyHttpServlet extends MyGenericServlet {

    // 由于是继承父类,所以只重写对自己有用的方法。
    // 这样就把其中其他四个不需要的方法给屏蔽掉了,我们只需要重写这一个方法就可以了,实现了GenericServlet的本质。
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        // 通过强转将servletRequest类型转为HttpServletRequest类型。
        /*
        * 源代码中:public interface HttpServletRequest extends javax.servlet.ServletRequest
        * 也就是说,ServletRequest是HttpServletRequest的父类,所以可以直接强转。
        * 转类型的目的是因为父类中没有获取请求类型的方法,也就是说父类的方法具有局限性。
        * */
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;

        // 获取请求类型
        String method = httpServletRequest.getMethod();
        // 用switch语句来做分发
        switch (method){
            case "GET":
                // 这里有个基础知识点,为什么要用this?
                /*
                * this指代本类,也就是说用this就是调用的本类中的成员变量以及成员方法,而不是传入的形参或者是局部变量。
                * */
                this.doGet(httpServletRequest,httpServletResponse);
                break;
            case "POST":
                this.doPost(httpServletRequest,httpServletResponse);
                break;
        }
    }

    // 自身的方法写两个
    // 这里注意传入的方法是自己强转之后的HttpServlet类型的方法
    // 在这里抛出子类中的异常
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException{

    }
}

(注意我在代码中写的注释,里面有很多知识点)

然后我们再用我们自己写的来实现一下HttpServlet

public class HelloServlet extends MyHttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 在这里出现了报错,需要抛出异常,异常需要在父类上面也同样抛出异常
        response.getWriter().write("GET");
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException{
        response.getWriter().write("POST");
    }
}

复盘三种Servlet的层次关系

从中我们来复盘一下三个实现类的层次关系:

  • 顶层Servlet:是最基本的Servlet,属于一个接口。其实本质上Servlet就是一组接口。通过基础知识我们了解到接口所有的方法都需要进行重写和实现。而我们只需要实现其中一个service方法就可以,所以出现了GenericServlet。
  • 中间层GenericServlet:就是实现了Servlet接口的一个实现类,作用就是屏蔽掉了四个不常用的Servlet生命周期的方法。继承了该类之后我们只需要重写其中最常用的service方法即可。
  • 底层HttpServlet(最常用):将HTTP请求的类型进行了具体逻辑划分,使其进入不同的方法当中。也就是说我们在日常开发之中继承该方法,并且重写该方法的doGET或者doPOST等方法即可。

写在最后

如果该文章对大家有帮助的话,请大家点个赞或者留个评论。我是苏木,谢谢大家捧场哈~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值