Servlet(二)

一、Servlet API

1、Servlet 接口

Servlet API 的核心是 javax.servlet.Servlet 接口,所有的 Servlet 类都必须实现这一接口。
Servlet接口的相关方法在 **Servlet(一)**中已经介绍过了,这里不再讲解。

在 Servlet API 中,javax.servlet.GenericServlet 抽象类实现了 Servlet 接口,而 javax.servlet.http.HttpServlet 抽象类是 GenericServlet 类的子类。当用户开发自己的 Servlet 类时,可以选择扩展 GenericServlet 类或者 HttpServlet 类(建议使用 HttpServlet 类)。

2、GenericServlet 抽象类

GenericServlet 类的主要源代码:

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 msg) {
        this.getServletContext().log(this.getServletName() + ": " + msg);
    }

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

分析:
(1)GenericServlet 类除了实现 Servlet 接口,还实现了 ServletConfig 接口和 Serializable 接口。
(2)从 GenericServlet 类的源代码可以看出,GenericServlet 类实现了 Servlet 接口中 init(ServletConfig config)初始化方法。GenericServlet 类有一个 ServletConfig 类型的的私有实例变量 config。当 Servlet 容器调用 GenericServlet 的init(ServletConfig config)方法时,该方法是的私有实例变量 config 引用由容器传入的 ServletConfig 对象,即使得 GenericServlet 对象与一个 ServletConfig 对象关联。
(3)GenericServlet 类还自定义了一个不带参数的 init() 方法,init(ServletConfig config)方法会调用此方法。对于 GenericServlet 类的子类,如果希望覆盖弗雷德初始化行为,有两种方法:

  1. 覆盖父类的不带参数的 init() 方法
public void init() {
	// 子类具体的初始化行为
	...
}
  1. 覆盖父类的带参数的 init(ServletConfig config)方法。如果希望当前 Servlet 对象与 ServletConfig 对象关联,应该在该方法中先调用 super.init(config)方法:
public void init(ServletConfig config){
	super.init(config); // 调用父类的 init(config) 方法
	// 子类具体的初始化行为
	...
}

(4)GenericServlet 类没有实现 Servlet 接口中的 service() 方法,service() 方法是 GenericServlet 类中唯一的抽象方法,GenericServlet 类的具体子类必须实现该方法,从而为特定的客户请求提供具体的服务。
(5)GenericServlet 类尽管实现了 Servlet 接口中的 destroy() 方法,实际上什么也没做。GenericServlet 类的具体子类可以覆盖该方法,从而为待销毁的当前 Servlet 对象释放所占用的各种资源(例如关闭文件输入流和输出流,关闭与数据库的连接等)。
(6)GenericServlet 实现了 ServletConfig 接口中的所有方法。因此,GenericServlet 类的子类可以直接调用在 ServletConfig 接口中定义的 getServletContext()、getInitParameter() 和 getInitParameterNames() 等方法。

3、HttpServlet 抽象类

HttpServlet 类是 GenericServlet 类的子类。 HttpServlet 类为 Servlet 接口提供了与 HTTP 协议相关的通用实现。也就是说, HttpServlet 对象适合运行在与客户端采用 HTTP 协议通信的 Servlet 容器或者 Web 服务器中。在开发 Java Web 应用时,自定义的 Servlet 类一般都扩展 HttpServlet 类。

HTTP 协议把客户端请求分为 GET、POST、PUT 和 DELETE 等多种方式。HttpServlet 类针对每一种请求方式都提供了相应的服务方法,如 doGet()、doPost()、doPut() 和 doDelete() 等方法。

源码:

public abstract class HttpServlet extends GenericServlet {
    private static final long serialVersionUID = 1L;
    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 final ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");

    public HttpServlet() {
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_get_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }

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

    protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (DispatcherType.INCLUDE.equals(req.getDispatcherType())) {
            this.doGet(req, resp);
        } else {
            HttpServlet.NoBodyResponse response = new HttpServlet.NoBodyResponse(resp);
            this.doGet(req, response);
            if (req.isAsyncStarted()) {
                req.getAsyncContext().addListener(new HttpServlet.NoBodyAsyncContextListener(response));
            } else {
                response.setContentLength();
            }
        }

    }
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_post_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }

    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_put_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }

    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_delete_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }


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

    }


    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }

        this.service(request, response);
    }
}

分析:
HttpServlet 类实现了 Servlet 接口中的 service(ServletRequest req,ServletResponse res) 方法,该方法实际上调用的是它的重载方法:

service(HttpServletRequest req, HttpServletResponse resp)

在以上重载 service() 方法中,首先调用 HttpServletRequest 类型的 req 参数的 getMethod() 方法,从而获得客户端的请求方式,然后依据该请求方式来调用匹配的服务方法。如果为 GET 方式,则调用 doGet() 方法;如果为 POST 方式,则调用 doPost() 方法,依此类推。
HttpServlet 类为所有针对特定请求方式的 doXXX() 方法提供了默认的实现。在 HttpServlet 类的默认实现中,doGet()、doPost()、doPut() 和 doDelete() 方法都向客户端返回一个错误:

  • 如果客户端与服务器之间采用 HTTP1.1 协议通信,那么返回的错误为 HttpServletResponse.SC_METHOD_NOT_ALLOWED(对应 HTTP 协议中响应状态代码为 405 的错误)
  • 如果客户端与服务器之间不是采用 HTTP1.1 协议通信,那么返回的错误为 HttpServletResponse.SC_BAD_REQUEST(对应 HTTP 协议中响应状态代码为 400 的错误)

对于 HttpServlet 类的具体子类,一般会针对客户端的特定请求方式,来覆盖 HttpServlet 父类中的相应 doXXX() 方法。为了使 doXXX() 方法能被 Servlet 容器访问,应该吧访问权限设为 public。假定 HelloServlet 类时 HttpServlet 类的子类,如果客户端只会按照 GET 方法请求访问 HelloServlet。那么就只需重新实现 doGet() 方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值