一、什么是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 结构图:
请注意:只要使用 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。
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; } }