---第六章 Servlet

Servlet是Server + Applet的缩写,表示一个服务器应用.Servlet其实就是一套规范,我们按照这套规范写的代码就可以直接在Java的服务器上面运行.如下图所示的是Servlet3.1中Servlet的结构图

一,Servlet接口

public interface Servlet {
 /*
      init方法在容器启动时被容器调用(注:load-on-startup可以指定Servlet被创建的时机,若为负数或者不设置,
    则在第一次请求时[即第一次调用该Servlet才被创建],若为0或者正数,则在当前WEB应用被Servlet容器加载时创建实例,
    且数越小越早被创建),只会被调用一次;
*/
    public void init(ServletConfig config) throws ServletException;
    /*
     用于获取ServletConfig,ServletConfig顾名思义指的是Servlet的配置,比如我们在web.xml中定义Servlet时通过init-param
    标签配置的参数就是通过ServletConfig来保存的.
    */
    public ServletConfig getServletConfig();
   /*
      service方法用于具体处理一个请求
   */
   public void service(ServletRequest req, ServletResponse res) 
  throws ServletException, IOException;
   /*
    getServletInfo方法可以获取一些Servlet相关的信息,若作者,版权等,这个方法需要自己实现,默认返回空字符串;
   */
   public String getServletInfo();   
    /*
      主要用于在Servlet销毁(一般指关闭服务器)时释放一些资源,也只会调用一次
    */    
   public void destroy(){}

二,ServletConfig


package javax.servlet;

import java.util.Enumeration;

 public interface ServletConfig {
    /*
   用于获取Servlet的名字,也就是我们在web.xml中定义的servlet-name
    */
    public String getServletName();
  /*
   返回值ServletContext代表的是我们这个应用的本身,那么ServletContext里边设置的参数就可以被当前应用的所有Servlet共享了[注:做项目时,参数可以保存在Session中,也可以在Application中,而后者很多时候就是保存在ServletContext中];
   我们可以这么理解,ServletConfig是Servlet级的,而ServletContext是Context(也就是Application)级的,另外我们可以获取更高一层的站点级也就是Tomcat中的Host级的相应操作:在Servlet的标准中有这么一个方法:public ServletContext getContext(String uripath),它可以根据路径获取到同一站点下的别的应用的ServletContext!由于安全原因,一般返回null,如果想使用需要进行一些设置.
  */
    public ServletContext getServletContext();
   //用于获取init-param配置的参数
    public String getInitParameter(String name);
//用于获取配置的所有init-param的名字的集合
    public Enumeration getInitParameterNames();

}

三 GenericServlet
GenericServlet是Servlet的默认实现,主要做了三件事:
①实现了ServletConfig接口,可以直接调用ServletConfig中的方法;
②提供了无参的init方法;
③提供了log方法;

  /*
   GenericServlet实现了ServletConfig接口,当需要调用ServletConfig中方法的时候,可以直接调用.比如获取ServletContext的时候可以直接调用getServletContext,而无须调用getServletConfig().getServletContext(),不过底层实现其实是内部调用,源码如下:
  */
   public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletContext();
    }
/*
 GenericServlet实现了Servlet的init(ServletConfig config)方法,在里面将参数config设置给了内部变量config,然后调用了无参的init()方法;
 这种做法有三个作用:
 ①将参数config设置给了内部属性config,这样就可以在ServletConfig的接口方法中直接调用config相应的方法来执行;
 ②当我们在写Servlet的时候就可以只处理自己的初始化逻辑,而不需要关心config了;
 ③在重写init()方法时不需要在调用super.init(config)了,如果在自己的Servlet中重写了带参的init方法,一定记着调用super.init(config),否则会报空指针异常
*/
 //GenericServlet提供了两个log方法,一个记录日志,一个记录异常
    public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
    }
    public void init() throws ServletException {
    }

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

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

四 HttpServlet
HttpServlet是用HTTP协议实现的Servlet的基类,SpringMVC中的DispatchServlet就是继承该类,HttpServlet主要重写了service方法.在service方法中首先将ServletRequest和ServletResponse转换为了HttpServletRequest和HttpServletResponse ,然后根据HTTP请求的类型不同将请求路由到了不同的处理方法

    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest  request;
        HttpServletResponse response;

        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }

        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;

        service(request, response);
    }

  protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {

                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    doGet()

                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);

        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);

        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);

        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);

        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);

        } else {

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);

            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
    /*
    具体处理方法时doXXX的结构,.doGet,doPost,doPut和doDelete方法都是模板方法,而且子类如果没有实现将抛出异常,在调用doGet方法之前还对是否过期做了检查,如果没有过期则直接返回304状态码使用缓存;doHead调用了doGet的请求,然后返回空body的Response;doOption和doTrace主要用来做一些调试工作,doOtion返回所有支持的处理类型的集合,正常情况下可以禁用,doTrace是用来远程诊断服务器的,它会将接收到的header原封不动地返回
    */
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

你可能感兴趣的:(SpringMVC,spring,mvc)