https://blog.csdn.net/initphp/article/details/38171219

Servlet是什么

  1. Servlet是服务器端运行的一个程序,是一个被编译好的Java类。它不是框架等。
  2. Web容器的启动,需要依赖Servlet。当web服务器开始执行时,servlet类就被初始化
  3. 当用户通过浏览器访问的时候,会输入URI,这个时候,web服务器就通过Servlet来分发请求执行不同的内容。

一般我们会使用Tomcat来运行Java的web项目。通常我们可以在web项目的目录中可以看到 _**WEB-INF **_这样的文件夹。这个文件夹是受保护的,外部无法通过url来访问的。文件夹里面包含了 _**web.xml **_以及 _**class **_和 _**libs **_目录。我们要将web项目运行起来,就得在web.xml中定义一个Servlet,因为定义了Servlet,web容器才能知道需要如何去分发请求进行业务处理的。

Servlet是有一个Jar包,里面包含了一些Servlet的相关设计和细节。

一个使用Spring的Servlet的web.xml配置例子:

    <servlet>
        <servlet-name>apiServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-common.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>apiServlet</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

HttpServlet

HttpServlet是一个抽象类,具体的实现自己需要的Servlet需要通过继承该类来实现 。

HttpServlet中主要的几个方法:

方法 用途
doGet 处理HTTP GET请求
doPost 处理HTTP POST请求
doPut 处理HTTP PUT请求
doDelete 处理HTTP DELETE请求

Servlet 最终调用的是 service 方法,这个方法中会根据 reques t的 Method 来判断具体是执行doGet还是doPost

可以看下 HttpServlet 类:

package javax.servlet.http;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public abstract class HttpServlet extends GenericServlet
    implements java.io.Serializable
{
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";

    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";

    private static final String LSTRING_FILE =
    "javax.servlet.http.LocalStrings";
    private static ResourceBundle lStrings =
    ResourceBundle.getBundle(LSTRING_FILE);

    public HttpServlet() { }

    //处理HTTP的GET请求,你需要实现一个Servlet,然后实现该方法
    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);
    }
    }

    protected long getLastModified(HttpServletRequest req) {
    return -1;
    }

    protected void doHead(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
    {
    NoBodyResponse response = new NoBodyResponse(resp);

    doGet(req, response);
    response.setContentLength();
    }

    //实现HTTP POST请求
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
    {
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_post_not_supported");
    if (protocol.endsWith("1.1")) {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
    }

    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
    {
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_put_not_supported");
    if (protocol.endsWith("1.1")) {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
    }

    protected void doDelete(HttpServletRequest req,
                HttpServletResponse resp)
    throws ServletException, IOException
    {
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_delete_not_supported");
    if (protocol.endsWith("1.1")) {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
    }

    private Method[] getAllDeclaredMethods(Class c) {

        if (c.equals(javax.servlet.http.HttpServlet.class)) {
            return null;
        }

        Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
        Method[] thisMethods = c.getDeclaredMethods();

        if ((parentMethods != null) && (parentMethods.length > 0)) {
            Method[] allMethods =
                new Method[parentMethods.length + thisMethods.length];
        System.arraycopy(parentMethods, 0, allMethods, 0,
                             parentMethods.length);
        System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
                             thisMethods.length);

        thisMethods = allMethods;
    }

    return thisMethods;
    }

    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
    {
    Method[] methods = getAllDeclaredMethods(this.getClass());

    boolean ALLOW_GET = false;
    boolean ALLOW_HEAD = false;
    boolean ALLOW_POST = false;
    boolean ALLOW_PUT = false;
    boolean ALLOW_DELETE = false;
    boolean ALLOW_TRACE = true;
    boolean ALLOW_OPTIONS = true;

    for (int i=0; i<methods.length; i++) {
        Method m = methods[i];

        if (m.getName().equals("doGet")) {
        ALLOW_GET = true;
        ALLOW_HEAD = true;
        }
        if (m.getName().equals("doPost"))
        ALLOW_POST = true;
        if (m.getName().equals("doPut"))
        ALLOW_PUT = true;
        if (m.getName().equals("doDelete"))
        ALLOW_DELETE = true;

    }

    String allow = null;
    if (ALLOW_GET)
        if (allow==null) allow=METHOD_GET;
    if (ALLOW_HEAD)
        if (allow==null) allow=METHOD_HEAD;
        else allow += ", " + METHOD_HEAD;
    if (ALLOW_POST)
        if (allow==null) allow=METHOD_POST;
        else allow += ", " + METHOD_POST;
    if (ALLOW_PUT)
        if (allow==null) allow=METHOD_PUT;
        else allow += ", " + METHOD_PUT;
    if (ALLOW_DELETE)
        if (allow==null) allow=METHOD_DELETE;
        else allow += ", " + METHOD_DELETE;
    if (ALLOW_TRACE)
        if (allow==null) allow=METHOD_TRACE;
        else allow += ", " + METHOD_TRACE;
    if (ALLOW_OPTIONS)
        if (allow==null) allow=METHOD_OPTIONS;
        else allow += ", " + METHOD_OPTIONS;

    resp.setHeader("Allow", allow);
    }

    protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
    {

    int responseLength;

    String CRLF = "\\\\r\\\\n";
    String responseString = "TRACE "+ req.getRequestURI()+
        " " + req.getProtocol();

    Enumeration reqHeaderEnum = req.getHeaderNames();

    while( reqHeaderEnum.hasMoreElements() ) {
        String headerName = (String)reqHeaderEnum.nextElement();
        responseString += CRLF + headerName + ": " +
        req.getHeader(headerName);
    }

    responseString += CRLF;

    responseLength = responseString.length();

    resp.setContentType("message/http");
    resp.setContentLength(responseLength);
    ServletOutputStream out = resp.getOutputStream();
    out.print(responseString);
    out.close();
    return;
    }

    //最终所有的具体实现都是需要实现Service方法.容器最终调用的就是该方法
    protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
    {
    String method = req.getMethod();
        //这边通过HTTP的方法来判断,具体的HTTP METHOD,然后决定需要执行的方法名称。
    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
        // servlet doesn't support if-modified-since, no reason
        // to go through further expensive logic
        doGet(req, resp);
        } else {
        long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
        if (ifModifiedSince < (lastModified / 1000 * 1000)) {
            // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
            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 {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        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);
    }
    }

    private void maybeSetLastModified(HttpServletResponse resp,
                      long lastModified) {
    if (resp.containsHeader(HEADER_LASTMOD))
        return;
    if (lastModified >= 0)
        resp.setDateHeader(HEADER_LASTMOD, lastModified);
    }

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

    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException("non-HTTP request or response");
    }
    service(request, response);
    }
}

HttpServlet最上层是继承Servlet这个接口类。Servlet这个接口类非常简单,只定义了5个方法。