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