JavaWeb之组件Servlet详解

目录

一.Servlet简介:

二.Servlet接口:

三.Servlet的抽象实现类:


一.Servlet简介:

 1.1 什么是Servlet:

Servlet全称Java Servlet 是用Java编写在服务端程序,主要是动态生成Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。

    Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

   它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

        下图:

1.2.Servlet的主要任务:

  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
  • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

二.Servlet接口:

  2.1 Servlet简介:

我们讲的Servlet就是一个所有的Servlet类直接或者间接必须实现的接口。而实现Servlet有三种方式:

  • 实现javax.servlet.Servlet接口;

  • 继承javax.servlet.GenericServlet类;

  • 继承javax.servlet.http.HttpServlet类;(这个是我们主要用的)

当我们实现Servlet时,Servlet容器(服务器,现阶段Tomcat)会将Servlet类加载,并且产生一个Servlet实例以及调用具体的方法,Servlet实现类不需要程序员自己创建对象,在Servlet容器就已经创建好对象了。

  注意点:

           1.每一个Servlet类只能有一个实例对象(由容器创建)。 

 2.2 Servlet的工作流程:

当客户端发送请求到服务端时,服务器都会创建一个request对象,response对象,并把请求数据封装到request中,response对象用来对客户端进行响应,然后在调用Servlet.service()方法时传递给service()方法 ,调用sevice()方法之后把进行数据处理,形成动态数据,之后通过response对象对客户端进行响应。          

   request的主要功能:

  • 封装了请求头数据;

  • 封装了请求正文数据,如果是GET请求,那么就没有正文;

  • request是一个域对象,可以把它当成Map来添加获取数据;

  • request提供了请求转发和请求包含功能。

 response的主要功能:

  • 设置响应头信息;

  • 发送状态码;

  • 设置响应正文;

  • 重定向;

2.3 Servlet接口的方法:

Servlet接口定义了五种方法:

 * 实现Servlet的第一种方式
 *   实现javax.servlet.Servlet接口
 
public class AServlet implements Servlet {
    private ServletConfig servletConfig; //默认null

    /**
     * 初始化方法    生命周期方法, 由Tomcat调用    做初始化操作
     *   在Servlet创建之后调用, 调用一次
     * @param servletConfig
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("555~~555,我出生了...");
        this.servletConfig = servletConfig;
    }

    /**
     * 得到ServletConfig对象 (Servlet的配置)
     *
     * @return
     */
    @Override
    public ServletConfig getServletConfig() {
        return servletConfig;
    }

    /**
     * 最重要的方法, 接收用户请求,处理用户请求, 响应结果
     * Tomcat调用:  生命周期方法   , 每请求一次,执行一次
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("AServlet 正在服务...");
        //获取Servlet配置
        //System.out.println("Servlet的名字:"+servletConfig.getServletName());
        //获取初始化参数
        //根据初始化参数名获取值
        String name = servletConfig.getInitParameter("name");
        System.out.println("name:"+name);
        //获取所有的初始化参数名
        Enumeration<String> names = servletConfig.getInitParameterNames();
        //遍历
        while(names.hasMoreElements()){
            String key = names.nextElement(); //参数名
            String value = servletConfig.getInitParameter(key);
            System.out.println("key:"+key+"--value:"+value);
        }

    }

    /**
     * 没什么意义
     *   得到Servlet的描述
     * @return
     */
    @Override
    public String getServletInfo() {
        return null;
    }

    /**
     * 销毁方法,    释放资源
     *  生命周期方法, Tomcat调用,
     *   在Servlet销毁之前调用, 只执行一次
     */
    @Override
    public void destroy() {
        System.out.println("555~555~我走了...");
    }
}

 这五个方法描述了Servlet的生命周期,从生到死的过程:

  出生:默认情况下,第一次请求时,由Tomcat创建。

            调用init方法。

   运行:用户每请求一次这个Servlet, tomcat调用一次service()方法。

   死亡:当Tomcat服务器关闭之前, 销毁它创建的所有对象,包含创建Servlet, 在Servlet销毁之前, 调用destroy()

2.4 ServletConfig接口:

当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init( )方式传入一个ServletConfig对象。 ServletConfig对象,由服务器创建。

  主要方法:

  • String getServletName():获取Servlet在web.xml文件中的配置名称,即<servlet-name>指定的名称;

  • ServletContext getServletContext():用来获取ServletContext对象,

  • String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;

  • Enumeration getInitParameterNames():用来获取在web.xml中配置的所有初始化参数名称;

 

2.5 ServletContext对象:

ServletContext对象表示Servlet应用程序。每个Web应用程序都只有一个ServletContext对象。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。

 ServletContext对象的作用是在整个Web应用的动态资源之间共享数据!例如在AServlet中向ServletContext对象中保存一个值,然后在BServlet中就可以获取这个值,这就是共享数据了。

                通过在ServletConfig中调用getServletContext方法,也可以获得ServletContext对象。

在HttpServlet中可以直接调用 getServletConfig()方法,因为HttpServlet继承了GenericServlet,而GenericServlet实现了ServletConfig,并且GenericServlet有 getServletConfig(),所以在HttpServlet中可以直接调用得到ServletContext对象。

    ServletContext servletContext = getServletConfig().getServletContext();

三.Servlet的抽象实现类:

3.1 GenericServlet抽象类 :

我们编写Servlet一直是通过实现Servlet接口来编写的,但是,使用这种方法,则必须要实现Servlet接口中定义的所有的方法,即使有一些方法中没有任何东西也要去实现,并且还需要自己手动的维护ServletConfig这个对象的引用。因此,这样去实现Servlet是比较麻烦的。
   而GenericServlet抽象类则有三个好处:

1.为Servlet接口中的所有方法提供了默认的实现,则程序员需要什么就直接改什么,不再需要把所有的方法都自己实现了。

2.并且提供方法,包围ServletConfig对象中的方法。

3.将init( )方法中的ServletConfig参数赋给了一个内部的ServletConfig引用从而来保存ServletConfig对象,不需要程序员自己去维护ServletConfig了。

注:但是我们很少用 GenericServlet抽象类,因为主要使用HttpServlet

以下是 GenericServlet抽象类代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package javax.servlet;

import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    private static final long serialVersionUID = 1L;
    private transient ServletConfig config;

    public GenericServlet() {
    }

    public void destroy() {
    }

    public String getInitParameter(String name) {
        return this.getServletConfig().getInitParameter(name);
    }

    public Enumeration<String> getInitParameterNames() {
        return this.getServletConfig().getInitParameterNames();
    }

    public ServletConfig getServletConfig() {
        return this.config;
    }

    public ServletContext getServletContext() {
        return this.getServletConfig().getServletContext();
    }

    public String getServletInfo() {
        return "";
    }

    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    public void init() throws ServletException {
    }

    public void log(String message) {
        this.getServletContext().log(this.getServletName() + ": " + message);
    }

    public void log(String message, Throwable t) {
        this.getServletContext().log(this.getServletName() + ": " + message, t);
    }

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

    public String getServletName() {
        return this.config.getServletName();
    }
}

 3.2  HttpServlet抽象类:

HttpServlet类是GenericServlet的子类,它提供了对HTTP请求的特殊支持,所以HttpServlet抽象类覆盖了GenericServlet抽象类中的Service( )方法,并且添加了一个自己独有的Service(HttpServletRequest request,HttpServletResponse方法。

 

HttpServlet中的service方法把接收到的ServletRequsest类型的对象转换成了HttpServletRequest类型的对象,把ServletResponse类型的对象转换成了HttpServletResponse类型的对象。之所以能够这样强制的转换,是因为在调用Servlet的Service方法时,Servlet容器总会传入一个HttpServletRequest对象和HttpServletResponse对象,预备使用HTTP。因此,转换类型当然不会出错了。

    转换之后,service方法把两个转换后的对象传入了另一个service方法,那么我们再来看看这个方法是如何实现的:
 

 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;
                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")) {
            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方法的参数是HttpServletRequest对象和HttpServletResponse对象,刚好接收了上一个service方法传过来的两个对象。我们会发现在service方法中还是没有任何的服务逻辑,但是却在解析HttpServletRequest中的方法参数,并调用以下方法doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。这7种方法中,每一种方法都表示一个Http方法。doGet和doPost是最常用的。所以,如果我们需要实现具体的服务逻辑,不再需要覆盖service方法了,只需要覆盖doGet或者doPost就好了。所以我们只需要写doget和doPost方法了。这样使代码更加简洁。

public class aServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

猜你喜欢

转载自blog.csdn.net/qq_50692350/article/details/127417513
今日推荐