2、GenericServlet
GenericServlet实现了Serializable, Servlet, ServletConfig这三个接口,还有一个不带参数的init方法和两个参数不同的log方法。
实现了Serializable接口,表示其实可以被序列化的,也就是说可以在特定的情况下被写到磁盘或者通过网络传输。
Servelt接口中的方法已经在上面介绍过了。
那我们来看看ServletConfig这个接口
String getInitParameter(String name)
Enumeration getInitParameterNames()
这两个方法是用来获取初始化参数的,初始参数在web.xml中的<servlet></servlet>块中田间添加。
ServletContext getServletContext()这个方法返回一个实现了ServletContext的类的对象,ServletContext对象就是Servlet运行时候的上下文(简单说就是这个对象提供了与Servlet容器交互的几个方法)
String getServletName()返回此Servlet的名字。
接下来看新添加的3个方法
void init() throws ServletException
这个方法是在void init(ServletConfig config)中被调用的,所以我们以后如果想在servlet初始化的时候做一些事情的话,可以直接覆盖这个方法就可以了。而且覆盖这个方法时,我们不需要先调用super.init();这个也很好解释为什么我们一般不应该在void init(ServletConfig config)中做一些初始化动作,为了证实这点我们可以看一下GenericServlet的源码,GenericServlet中没关系的代码已经去掉。
public
abstract
class
GenericServlet
implements
Servlet, ServletConfig,

Serializable


...
{


private transient ServletConfig config;


public ServletConfig getServletConfig()


...{

return config;

}


public void init(ServletConfig config) throws ServletException


...{

this.config = config;

init();

}


public void init() throws ServletException


...{

}

}

可以很清楚的看到void init(ServletConfig config)唯一做的两件事情:
a) 用一个成员变量private transient ServletConfig config;来保存了参数中config的值(这样我们以后需要ServletConfig对象的时候就可以使用ServletConfig getServletConfig()来取回)。
b) 调用了init()方法实际上init()方法就是一个空方法。
假如我们直接去覆盖void init(ServletConfig config)的话,我们直接写我们需要初始化的东西。那么会产生的后果就是:当我们需要ServletConfig对象的时候方法的时候,我们去调用ServletConfig getServletConfig()返回的就是null。而且GenericServlet提供的其他方法中很多方法都是通过调用private transient ServletConfig config;而实现的,所以假如直接覆盖void init(ServletConfig config)可能Servlet容器的log中会出现大量的java.lang.NullPointerException。所以我们初始化的动作记得是覆盖public void init()去做而不是覆盖void init(ServletConfig config)。
GenericServlet的另外两个log方法
void log(String msg)
void log(String message, Throwable t)
顾名思义是用来记录日志的,这里就不多说了,tomcat中记录的日志存在tomcat的logs子文件夹中。
让我们用一个例子来结束GenericServlet的讲解
package
squall.servlet.basic;


import
java.io.IOException;

import
java.io.PrintWriter;


import
javax.servlet.GenericServlet;

import
javax.servlet.ServletException;

import
javax.servlet.ServletRequest;

import
javax.servlet.ServletResponse;


public
class
GenericServletTest
extends
GenericServlet


...
{


public void service(ServletRequest request, ServletResponse response)

throws ServletException, IOException


...{

response.setContentType("text/html");

PrintWriter out = response.getWriter();

String docType = "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> ";

out.println(docType +

"<HTML> " +

"<HEAD><TITLE>Hello from GenericServlet!</TITLE></HEAD> " +

"<BODY BGCOLOR="#FDF5E6"> " +

"<H1>Hello World from GenericServlet!</H1> " +

"</BODY> " +

"</HTML>");

}


}

编译完以后部署到tomcat后,mapping到/GenericServlet。访问http://127.0.0.1:8080/train/GenericServlet就可以看到
Hello World from GenericServlet!
3、HttpServlet
HttpServlet类的出现使得我们写一个Web端的Servlet程序更加简单,HttpServlet中的do开头的方法分别对应于http的各种请求,比如doGet方法用来响应浏览器的GET请求。绝大多数情况下,我们只需要考虑GeT和Post这两种请求,所以绝大多数情况下我们只需要实现doGet和doPost方法。(直接在浏览器中输入一个url,然后回车默认为get请求)。
写一个例子来看下使用继承HttpServlet来完成一个Servlet是怎样的。
package
squall.servlet.basic;


import
java.io.IOException;

import
java.io.PrintWriter;


import
javax.servlet.ServletException;

import
javax.servlet.http.HttpServlet;

import
javax.servlet.http.HttpServletRequest;

import
javax.servlet.http.HttpServletResponse;


public
class
HelloServlet
extends
HttpServlet


...
{

private int times = 0;


protected void doGet(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException


...{

++times;

response.setContentType("text/html");

PrintWriter out = response.getWriter();

String docType = "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> ";

out.println(docType + "<HTML> "

+ "<HEAD><TITLE>Hello</TITLE></HEAD> "

+ "<BODY BGCOLOR="#FDF5E6"> " + "<H1>Hello World! " + times

+ " times from GET</H1> " + "</BODY> " + "</HTML>");

}


protected void doPost(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException


...{

response.setContentType("text/html");

PrintWriter out = response.getWriter();

String docType = "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> ";

out.println(docType + "<HTML> "

+ "<HEAD><TITLE>Hello</TITLE></HEAD> "

+ "<BODY BGCOLOR="#FDF5E6"> " + "<H1>Hello World! " + times

+ " times from POST</H1> " + "</BODY> " + "</HTML>");

}


}

编译完成以后部署到tomcat,mapping至HelloServlet。
会看到
Hello World! 1 times from GET
可以看到直接输入url对应于get请求。刷新后可以看到times前面的数字在增加。其原因doGet方法每次会将servlet对象的成员变量times加1。当然这里只是举了一个例子。一般我们的项目很少是真的需要为一个servlet对象添加一个成员变量来实现某种需求(一般是设计上的问题引起的)。
Servlet的成员变量被这个运行在Servlet对象上所有的线程所共享,假如想一个Servlet对象上只运行一个线程的话。需要让让servlet实现SingleThreadModel,但注意这个接口没有任何方法,并且是不推荐的。