Technorati 标签: java, servlet

一、什么是Servlet

    servlet 是位于 web 服务器内部的服务器端的java应用程序,与传统的从命令行启动java 应用程序不同,servlet 有 web 服务器进行加载,该 web 服务器必须包含支持 servlet 的java 虚拟机(如Tomcat ,GlassFish)。

   servlet 是一种服务器端的java 应用程序,具有独立于平台和协议的特性,可以生成动态的 web 页面。它担当客户请求(浏览器)与服务器响应的中间层。

二、servlet的作用

    (1)扩展了 web 服务器(apache IIS)只处理静态资源的请求,用(perl、c++)来扩展服务器的功能,但是每一个请求都会产生一个新的进程

    (2)Tomcat 直接在web 服务器上运行,语言跨平台

    (3)web 服务器只能处理 http 连接请求,以及对静态资源的访问;扩展 web 服务器的功能是 servlet 可以处理http 请求数据(业务逻辑的处理),生成动态的资源

三、servlet 编程

    1、servlet 的基本结构

     每个 servlet(自定义) 本质上都是实现了 javax.servlet.Servlet 接口。而大多数的servlet 是间接完成了这一过程,它们继承了 javax.servlet.http.HttpServlet 和 javax.servlet.http.GenericServlet 这两个 Servlet 的标准实现。

    servlet API 在 javax.servlet 和 jvax.servlet.http 这两个Java扩展包中。其中javax.servlet 定义的类和接口独立于协议;而包javax.servlet.http中包含与 http 协议相关的类和接口。javax.servlet.http 包中的某些类或接口继承了 javax.servlet 包中的部分类或接口。如下图,servlet 核心类的 uml 结构图:

image

    请注意:只要使用 javax.servlet.http 包,web 容器就会自动维护所有这些关系;可如果是扩展 javax.servlet 包中的类而创建具体的servlet,就必须自己维护其中的关系。

    下表概述了Java Servlet API。

目的类/接口
Servlet 实现javax.servlet.Servlet
javax.servlet.SingleThreadModel(不推荐)
javax.servlet.GenericServlet
javax.servlet.HttpServlet
Servlet 配置javax.servlet.ServletConfig
Servlet 异常javax.servlet.ServletException
javax.servlet.UnavailableException
请求与相应javax.servlet.ServletRequest
javax.servlet.http.HttpServletRequest
javax.servlet.InputStream
javax.servlet.ServletResponse
javax.servlet.http.HttpServletResponse
javax.servlet.ServletOutputStream
会话跟踪javax.servlet.http.HttpSession
javax.servlet.http.HttpSessionBindingListener
javax.servlet.http.HttpSessionBindingEvent
Servlet 上下文javax.servlet.ServletContext
Servlet 写作javax.servlet.RequestDispatcher
其他javax.servlet.http.Cookie
javax.servlet.http.HttpUtil

 

    2、servlet 的生命周期

    与 servlet 生命周期有关的方法有init(),service()和destroy()(都在 servlet 里定义)。当web 容器调用 init() 方法时,servlet的生命周期就开始了,而调用 destroy() 方法后,此生命周期便结束。

    servlet 的生命周期描述如下:

    (1)实例化:web 容器创建 servlet 实例

    (2)初始化:web 容器调用 init() 方法

    (3)服务:如果web 容器有请求要传送给 servlet,它就调用servlet 实例的 service()方法。默认情况下,如果子类没有覆盖HttpServlet 的service()方法,会根据get 请求,还是post请求,分别调用doGet()方法,doPost()方法。

    (4)销毁:web 容器调用 servlet 实例的 destroy()方法终止 servlet。

servlet lifecycle

    3、1 servlet init() 方法

    在Web容器加载和实例化servlet类之后、servlet 实例接收来自客户端的请求之前,Web容器对servlet进行初始化。用户可以自定义这个初始化过程,以允许servlet读取配置数据、初始化资源(连接数据库等)。servlet必须使用UnavailableException来完成初始化过程。同时注意两点:

    (1)如果出现不能处理客户端请求的初始化错误,例如不能得到一个所需网络的连接,会抛出UnavailableException

    (2)不能调用 System.exit()方法,这样会退出整个程序。

    servlet 的init() 方法,有两种形式,一个没有参数,另外一个有一个 ServletConfig 对象参数。在不需要读取 servlet 配置数据时,选择无参的init(),如下:

public void init() throws ServletException {
   //初始化代码块
}

    如果需要操纵servlet 的配置参数,则使用带参的init() 方法,如下;

public void init(ServletConfig config) throws ServletException {
  super.init(config);
  // 初始化代码块
}

    其中,config 就是配置文件的对象,可以通过调用 getInitParameter(String name)方法获取指定指定参数的值。也可以调用 getParameterNames()方法得到需要的参数名称。同时注意的是,调用init(ServletConfig config)方法时,super.init(config)都是放在第一行。

    3.2servlet service()方法

    每当 servlet 实例接收到客户端的请求时,服务器会新开一个线程并调用service 方法。service()方法会根据 http 请求的类型(get, post, put, delete等),相对应的调用doGet, doPost, doPut, doDelete方法等。那现在,如果你希望某个 servlet 对同等处理get 和post 方法,你可能会直接重写 service()方法,而不是重写 doGet和 doPost方法,如下:

public void service(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
   // Servlet Code
}

    其实,这不是一个明智的做法。相反,你用该让doPost()方法来调用 doGet()方法(或doGet调用doPost),如下:

public void doGet(HttpServletRequest request,HttpServletResponse response)
 throws ServletException, IOException {
 // Servlet Code
}
public void doPost(HttpServletRequest request,HttpServletResponse response)
 throws ServletException, IOException {
 doGet(request, response);
}

    尽管这种方法增加了那么几行代码,不过,相对直接重写service()方法,它有以 优势:

    (1)此方法允许你以后继续添加其他业务方法(如doPut,doTrace)。直接重写service()方法,可能会被子类覆盖进而阻止同一地处理deGet和doPost方法。

    (2)可以通过添加 getLastModified() 方法来获取最新的修改时间。如果你使用deGet方法,那原始的service()方法可以通过使用 getLastModified()方法来设置头部字段Last-Modified,并正确的相应 get 请求。

    3.3 servlet destroy()方法

    销毁 servlet 实例,在此方法里,你需要断开数据库的连接,停止其对应的后台进程,写cookie 列表等。

    3.4Demo

下面给出一个使用config对象的init()Demo,用来循环输出“hello world”

@WebServlet(
		urlPatterns = { "/ShowMessage" }, 
		initParams = { 
				@WebInitParam(name = "message", value = "hello world"), 
				@WebInitParam(name = "repeatedTimes", value = "3")
		})
public class ShowMessage extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private String message;
    private String defauleMessage = "No message!";
    private int repeatedTimes = 1;

    public ShowMessage() {
        super();
    }
    public void init(ServletConfig config) throws ServletException {
		super.init(config);
		message = config.getInitParameter("message");
		if (message == null) {
			message = defauleMessage;
		}
		try {
			String repeatedTimeString = config.getInitParameter("repeatedTimes");
			repeatedTimes = Integer.parseInt(repeatedTimeString);
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
	}
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                  throws ServletException, IOException {
		PrintWriter out = response.getWriter();
		String title = "the showMessage servlet";
		out.println("<html>"+
				"<body bgcolor=\"#FDF5E6\">\n" +
				"<h1 align=center>" + title + "</H1>");
		for (int i = 0; i < repeatedTimes; i++) {
			out.println(message + "
"); } out.println("</body></html>"); } }

    Demo2,幸运号码,使用 getLastModified(),如下:

@WebServlet("/LotteryNumber")
public class LotteryNumber extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private long modTime;
	private int[] numbers;

    public LotteryNumber() {
        super();
        modTime = System.currentTimeMillis();
        numbers = new int[10];
        for(int i = 0; i < numbers.length;i++){
        	numbers[i] = randNum();
        }
    }

	private int randNum() {
		return (int)(Math.random()*100);
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		PrintWriter out = response.getWriter();
		String title = "your lottery numbers";
		out.print("<html><body>"
				+"<h1>" + title + "</h1>");
		for (int i = 0; i < numbers.length; i++) {
			out.print("<li>" + numbers[i]);
		}
		out.print("</li>"
				+"</body></html>");
	}

	//原始的service()方法会将这个时间与If-Modified-Since指定的时间相对比,
	//如果modTime稍新或者不存在If-Modified-Since指定时间不存在,
	//那就可以正常的执行doGet()方法,可当modTime与之相同或者稍后时,
	//service()方法会回复304(没有更新),注意这个情况下没有doGet()方法。
	@Override
	protected long getLastModified(HttpServletRequest req) {
		return modTime;
	}
}
 

Blogger Labels: java, Servlet