`
周凡杨
  • 浏览: 230610 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

解读Servlet原理篇二---GenericServlet与HttpServlet

阅读更多

在上一篇解读Servlet原理篇一》中提到,要实现javax.servlet.Servlet接口(即写自己的Servlet应用),你可以写一个继承自javax.servlet.GenericServletr的generic Servlet ,也可以写一个继承自java.servlet.http.HttpServlet的HTTP Servlet(这就是为什么我们自定义的Servlet通常是extentds HttpServlet的)。

 

那GenericServlet和HttpServlet的区别是什么,如何使用这两个类呢?

 

一:大话GenericServlet

Servlet API中是这样描述GenericServlet的:

    Defines a generic, protocol-independent servlet. To write an HTTP servlet for use on the Web, extend HttpServlet instead.GenericServlet implements the Servlet and ServletConfig interfaces. GenericServlet may be directly extended by a servlet, although it's more common to extend a protocol-specific subclass such as HttpServlet.GenericServlet makes writing servlets easier. It provides simple versions of the lifecycle methods init and destroy and of the methods in the ServletConfig interface. GenericServlet also implements the log method, declared in the ServletContext interface.

To write a generic servlet, you need only override the abstract service method.

      

    简译之,GenericServlet定义了一个通用的,无关协议的的Servlet。如果要在Web应用中使用Http进行Servlet通信,请扩展HttpServlet(即继承HttpServlet)。

   

package javax.servlet;

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

public abstract class GenericServlet implements Servlet, ServletConfig,
		Serializable {
	private transient ServletConfig config;

	public void destroy() {
	}

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

	public Enumeration getInitParameterNames() {
		return getServletConfig().getInitParameterNames();
	}

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

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

	public String getServletInfo() {
		return "";
	}

	public void init(ServletConfig config) throws ServletException {
		this.config = config;
		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);
	}

	public abstract void service(ServletRequest paramServletRequest,
			ServletResponse paramServletResponse) throws ServletException,
			IOException;

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

 

     需要注意的点:

  •    GenericServlet是个抽象类,不能直接进行实例化,必须给出子类才能实例化。即:GenericServlet gs = new GenericServlet(); 编译会报错。GenericServlet gs = new MyServlet(); 这样是正确的(其中MyServlet是其子类)
  • 其service()方法是个抽象方法,即它把处理请求的任务交给了子类。子类必须实现该方法。
  • 总得来看,它给出了设计servlet的一些骨架,定义了servlet生命周期,还有一些得到名字、配置、初始化参数的方法,其设计的是和应用层协议无关的,也就是说你有可能用非http协议实现它(其实目前Java Servlet还是只有Http一种)。

  二:续说HttpServlet 

package javax.servlet.http;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
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
		Serializable {
	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 ResourceBundle lStrings = ResourceBundle
			.getBundle("javax.servlet.http.LocalStrings");

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

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

	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(405, msg);
		else
			resp.sendError(400, msg);
	}

	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(405, msg);
		else
			resp.sendError(400, 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(405, msg);
		else
			resp.sendError(400, 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(405, msg);
		else
			resp.sendError(400, msg);
	}

	private static Method[] getAllDeclaredMethods(Class c) {
		if (c.equals(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(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) && (allow == null))
			allow = "GET";
		if (ALLOW_HEAD)
			if (allow == null)
				allow = "HEAD";
			else
				allow = allow + ", HEAD";
		if (ALLOW_POST)
			if (allow == null)
				allow = "POST";
			else
				allow = allow + ", POST";
		if (ALLOW_PUT)
			if (allow == null)
				allow = "PUT";
			else
				allow = allow + ", PUT";
		if (ALLOW_DELETE)
			if (allow == null)
				allow = "DELETE";
			else
				allow = allow + ", DELETE";
		if (ALLOW_TRACE)
			if (allow == null)
				allow = "TRACE";
			else
				allow = allow + ", TRACE";
		if (ALLOW_OPTIONS) {
			if (allow == null)
				allow = "OPTIONS";
			else
				allow = allow + ", OPTIONS";
		}
		resp.setHeader("Allow", allow);
	}

	protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String CRLF = "\r\n";
		String responseString = "TRACE " + req.getRequestURI() + " "
				+ req.getProtocol();

		Enumeration reqHeaderEnum = req.getHeaderNames();

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

		responseString = responseString + CRLF;

		int responseLength = responseString.length();

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

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

		if (method.equals("GET")) {
			long lastModified = getLastModified(req);
			if (lastModified == -1L) {
				doGet(req, resp);
			} else {
				long ifModifiedSince = req.getDateHeader("If-Modified-Since");
				if (ifModifiedSince < lastModified / 1000L * 1000L) {
					maybeSetLastModified(resp, lastModified);
					doGet(req, resp);
				} else {
					resp.setStatus(304);
				}
			}
		} else if (method.equals("HEAD")) {
			long lastModified = getLastModified(req);
			maybeSetLastModified(resp, lastModified);
			doHead(req, resp);
		} else if (method.equals("POST")) {
			doPost(req, resp);
		} else if (method.equals("PUT")) {
			doPut(req, resp);
		} else if (method.equals("DELETE")) {
			doDelete(req, resp);
		} else if (method.equals("OPTIONS")) {
			doOptions(req, resp);
		} else if (method.equals("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(501, errMsg);
		}
	}

	private void maybeSetLastModified(HttpServletResponse resp,
			long lastModified) {
		if (resp.containsHeader("Last-Modified"))
			return;
		if (lastModified >= 0L)
			resp.setDateHeader("Last-Modified", 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也是个抽象类,不能直接进行实例化,必须给出子类才能实例化(即不能直接使用,只能继承它)。
  • HttpServlet是采用Http协议进行通信的,所以它也实现Http协议中的多种方法,每种方法可以处理相应类型的请求

    Http协议方法

 HttpServlet实现方法

    OPTIONS

    doOption()

     GET

    doGet()

     POST

    doPost()

     TRACE

    doTrace()

     PUT

    doPut()

     DELETE

    doDelete()

  • HttpServlet的service()方法比较特殊,带public关键字的service()方法明显是继承自父类,它只接收HTTP请求,这里把相应的request和response转换为了基于HTTP协议的相应对象,最终将请求转到带protected关键字的service()方法中。protected service()方法根据请求的类型将请求转发到相应的doDelete()、doGet()、doOptions()、doPost()、doPut()等方法中。所以开发自己的Servlet时,不需要覆盖HttpServlet的service()方法,因为该方法最终将请求转发相相应的doXXX方法中,只需要覆盖相应的doXXX方法进行请求处理即可。如果重写了该方法,那么就不会根据方法名调用其他具体的方法了。
  • 同上道理, doOptions和doTrace方法也不需要覆盖。
  • 查看doGet、doPost、doPut、doDelete四个方法代码,发现这些方法只是判断协议类型,然后抛出相应的异常,其他什么都没做,所以实现自己的Servlet时,需要重写这些方法,以符合自己的需要进行请求处理。
  •  

    参考资料:

       http://www.codejava.net/java-ee/servlet/servlet-api-overview

http://www.uml-diagrams.org/examples/java-servlet-25-api-package-diagram-example.html

https://tomcat.apache.org/tomcat-5.5-doc/servletapi/

https://tomcat.apache.org/tomcat-5.5-doc/servletapi/

http://jzinfo.iteye.com/blog/502581

http://mavforcezt1008.iteye.com/blog/1222966

http://www.itzhai.com/tomcat-source-code-analysis-httpservlet-source-code-analysis.html

 

 

 

 

 

0
2
分享到:
评论

相关推荐

    servlet-api-2.4.jar.zip

    javax.servlet.GenericServlet javax.servlet.ServletContext javax.servlet.ServletRequest javax.servlet.http.HttpUtils javax.servlet.ServletResponse javax.servlet.ServletException javax.servlet....

    Servlet&GenericServlet&HttpServlet源码分析.zip_GenericServle_httpser

    Servlet&amp;GenericServlet&amp;HttpServlet源码分析,源码分析对于学习很有用

    servlet2.4doc

    GenericServlet() - Constructor for class javax.servlet.GenericServlet Does nothing. getAttribute(String) - Method in interface javax.servlet.ServletContext Returns the servlet container attribute ...

    serlvet三种开发方式之(继承GenericServlet开发、继承HttpServlet开发)

    韩顺平.2011最新j2ee视频教程.细说servlet.第10讲.serlvet三种开发方式之(继承GenericServlet开发、继承HttpServlet开发).wmv

    javax.servlet.jar下载

    javax.servlet.GenericServlet.class javax.servlet.SingleThreadModel.class javax.servlet.ServletRequestWrapper.class javax.servlet.ServletResponseWrapper.class javax.servlet.ServletRequestListener.class...

    servlet-api.jar需要的拿走

    Servlet接口是Java Servlet API的核心抽象。所有Servlet类必须直接或间接的实现...目前有GenericServlet和HttpServlet这两个类实现了Servlet接口。大多数情况下,开发者只需要继承HttpServlet去实现自己的Servlet即可。

    JavaWeb开发技术-Servlet接口及其实现类.pptx

    Servlet接口及其实现类 Java Servlet Jsp XML HTML Servlet接口及其实现类 Servlet接口及其实现类 Servlet接口 GenericServlet类 HttpServlet类 实现Servlet接口 继承GenericServlet类 Servlet接口及其实现类 方法...

    java-servlet-api.doc

    在功能上,Servlet与CGI、NSAPI有点类似,但是,与他们不同的是:Servlet具有平台无关性。 JavaServlet概论 Servlet与其他普通的server扩展机制有以下进步: 因为它采用了不同的进程处理模式,所以它比CGI更快。 它...

    servlet temple

    要创建一个 HTTP Servlet,请扩展 HttpServlet 类, 该类是用专门的方法来处理 HTML 表格的 GenericServlet 的一个子类。 HTML 表单是由 &lt;FORM&gt; 和 &lt;/FORM&gt; 标记定义的。表单中典型地包含输入字段(如文本输入字段、...

    Java Web应用开发:servlet.ppt

    本章内容 知道什么是...Tomcat作为Servlet容器,其基本的功能如下图所示: Servlet API的主要类和接口 (1) javax.servlet.Servlet接口 (2) javax.servlet.GenericServlet类 (3) javax.servlet.http.HttpServlet类

    servlet资源

    要创建一个 HTTP Servlet,请扩展 HttpServlet 类, 该类是用专门的方法来处理 HTML 表格的 GenericServlet 的一个子类。 HTML 表单是由 &lt;FORM&gt; 和 &lt;/FORM&gt; 标记定义的。表单中典型地包含输入字段(如...

    Servlet学习

    提供了实现servlet接口的两种方法:子类化javax.servlet.GenericServlet(这种方法提供了读取servlet配置信息的例子)和子类化javax.servlet.http.HttpServlet类.还有用service方法完成的经典的Hello World程序

    学习servlet的实例和参考api

    类 ServletConfig ServletOutputStream ServletContext ServletInputStream ServletResponse GenericServlet ServletRequest Servlet &lt;br&gt;javax.servlet.http&lt;br&gt;接口 类 HttpSession Cookie...

    servlet继承图.jpg

    在servlet里,GenericServlet 继承servlet和Serializable和ServletConfig ,httpServlet继承GenaricServlet MyClass 继承HttpServlet (和HttpServletResponse ,HttpServletRequest 是依赖关系)

    servlet的三种方法的实现

    开发servlet有三种方法的实现: 1.实现servlet接口 2.继承GenericServlet 3.继承HttpServlet

    JSP/Servlet

    JSP網頁最後是轉譯為Servlet,從Java程式設計人員的角度來看,Servlet其實就是一個 Java類別,它實作Servlet介面,通常我們會繼承實作該介面的GenericServlet類別或HttpServlet類別。 基礎入門 如果您瞭解JSP中的...

    T2-Servlet.ppt

    public abstract class HttpServlet extends GenericServlet implements Serializable { …… protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException...

    JavaWeb的三大组件详细总结

    1、ServletConfig API:2、GenericServlet类2、HttpServlet类:(重点掌握)1、doGet和doPost的区别:2、Servlet细节:3、web.xml文件(了解)4、ServletContext(重要):3、网站访问量统计小案例:二、过滤器三、监听...

    基于UML的毕业设计管理系统的分析与设计.docx

    编写Servlet类通常继承GenericServlet或HttpServlet类。因此Java中有两种类型的 Servlet在Rose中分别是用版型《Http_Servlet》或《Generic_Servlet》来表示。 在Rose中,用Tools→Java/J2EE→NewServlet 来创建...

Global site tag (gtag.js) - Google Analytics