JSP程序设计 第9章 Servlet简介
本章简介 什么是Servlet? Servlet相对于CGI的特性 Servlet的处理流程和生命周期 HttpServlet HttpServletRequest和HttpServletRepsonse ServletContext RequestDispatcher ServletConfig Servlet对象之间的关系
什么是Servlet Servlet是对支持java的服务器的一般扩充。最常见的用途是扩展Web服务器,提供安全、可移植、易于使用的CGI替代品。它是一种动态加载的模块,并为服务器接收的请求提供服务。 Servlet还可以看成是服务器端的Applet。它能被Web服务器加载和执行,它接收客户端发送的请求,执行需要的操作,然后返回结果给服务器。
Servlet执行的基本流程 客户端通过HTTP发送请求 服务器接收该请求发送给Servlet。如果处理请求的Servlet没有被加载,服务器就把它加载到JVM并执行它。 Servlet接收该HTTP请求并执行某种处理。 服务器接收Servlet处理的结果,并将其发送给客户端。
Servlet执行的基本流程 Web Server Browser (Client) Application Server servlet 3. Servlet引擎会调用Servlet的Service方法 Web Server Browser (Client) Application Server servlet instance 2. Server将请求信息发给Servlet 1. Client向 Server发出请求 4. Servlet构建一个响应,并将其传给Server 5. Server将响应返回给Client
Servlet和CGI的对比 相似点 -产生动态Web内容 Servlet替代CGI 在可移植性和平台无关性方面,因为Java Servlet API在Web服务器和Servlet之间定义了一个标准的接口,而且Servlet是用Java编写的,这使得Servlet能够跨平台,和不同的Web服务器交互,几乎所有的主流服务器都能够直接或间接地通过插件支持Servlet。 在持久性和性能方面,一个Servlet只要被Web服务器装载一次,就能够被每一个客户请求调用,这意味着,Servlet能够维护请求之间的系统资源,比如数据库连接,Servlet不会因为每一个请求而产生一个新的多余的实例,然而当CGI每一次被调用的时候,必须产生新的进程,所以Servlet比CGI性能更高。
Servlet的其它特性 Servlet功能更强大 Servlet可以解析HTML表单数据,读取和设置HTTP头,处理COOKIE,跟踪会话状态等。在Servlet中很多使用CGI程序很难完成的任务都可以轻松地完成,所以Servlet易于编写,功能更强大。 Servlet可以与其它的系统资源交互 比如它可以调用系统中其它的文件,访问数据库、Applet、Java应用程序等。从而以此产生响应给客户端的动态内容,如果需要的话,还可以保存请求响应过程中的信息,服务器可以完全授权Servlet对本地资源的访问,比如数据库,并且Servlet自身也会控制外部用户的访问数量以及访问性质。
Servlet的其它特性 Servlet可以是其它服务的客户端程序 比如它们可以用于分布式的应用系统中。可以通过本地硬盘或者是网络从远端激活Servlet。Servlet可以被链接,也就是一个Servlet可以调用一个或一系列Servlet。 Servlet API与协议无关的 Servlet能够被用于多种协议,比如HTTP、FTP等。主要介绍HttpServlet。
服务器为Servlet提供的服务 一个基于Servlet应用的客户,通常不直接和Servlet通信,而是由Web应用服务器通过Java Servlet API调用Servlet来实现请求服务。Web应用服务器的角色是管理、装载和初始化Servlet、处理服务请求,卸载或撤消Servlet,这通常是由Web应用服务器的Servlet管理服务功能实现的,也就是Web Container。
服务器为Servlet提供的服务 一般来说,在某一时刻,在Web服务器环境中只有一个特定的Servlet对象的实例,当Servlet第一次装进运行环境的时候,Web应用服务器负责实现Servlet实例的初始化,在Servlet整个生命周期内,Servlet保持激活状态或持久状态,每一个客户对这个Servlet的请求是通过在Servlet的初始对象实例上创建一个新的线程来处理的,Web应用服务器负责创建每个应用请求的新线程,另外它还负责卸载或重新安装Servlet。
服务器为Servlet提供的服务 Web应用服务器 的线程2 Servlet1 的线程1 的实例 首先Web应用服务器装载Servlet1,初始化Serlvet的实例变量,并且在Servlet生命周期内保持激活状态,也就是指持久状态,两个客户浏览器请求Servlet的应用服务,Web应用服务器为每个客户请求生成一个新的线程,每一个线程都能访问最初装载的实例变量,每个线程处理它自己的请求,并且把响应返回给请求客户.
Java Servlet API Servlet通过API接口来处理客户的请求,Serlvet API是一组Java类,它定义了Web客户端和Web Servlet之间的标准接口,客户的请求发给Web应用服务器,Web应用服务器通过这组API接口调用请求服务。 这组API有两个包组成 -javax.servlet -javax.servlet.http 第一个javax.servlet包中包含了通用的支持独立于协议的Servlet类。我们知道Servlet能够用于多种协议,比如HTTP、FTP。后面这个包javax.serlvet.http则包含了上述继承包的功能,并且它对HTTP协议提供特别的支持。
Java Servlet API javax.servlet.Servlet是一个接口类,它是Java Servlet 的抽象类,这个类定义了Servlet必须实现的方法,比如处理请求的Service方法。 javax.servlet.Servlet javax.servlet GenericServlet javax.servlet.http.HttpServlet implement
Java Servlet API GenericServlet类实现了javax.servlet.Servlet这个接口,而且它定义了一个通用的与协议无关的Servlet。 为了编写在Web上使用的HttpServlet,使用一个更特殊的类,javax.servlet.http.HttpServlet,它继承了GenericServlet。 javax.servlet.Servlet javax.servlet GenericServlet javax.servlet.http.HttpServlet implement
Servlet的生命周期 生命周期定义了一个Servlet如何被加载和被初始化,它怎样接收请求、响应请求、怎样提供服务。 Servlet的生命周期从把它装入到Web应用服务器的内存开始到终止或重新装入Servlet的时候结束。 生命周期的接口由javax.servlet.Servlet定义 -init() -service() -destroy() 上述方法会在特定的时间安装一定的顺序被调用。 我们刚才提到过Httpservlet实现的接口javax.servlet.Servlet。在代码当中,Servlet的生命周期就是由这个接口定义的,所有的Java Servlet必须直接或间接地实现这个接口,这样才能在Servlet引擎也就是Web Container中运行。这个接口定义了一些方法,比如init方法、service方法、destroy方法等等。在Servlet的生命周期中,这些方法会在特定的时间安装一定的顺序被调用。
Servlet的生命周期 创建 服务不可用 初始化 销毁 可用服务 卸载 请求服务 初始化失败 抛出 “unavailable” 异常 我们看这张图。首先我们创建Servlet,当请求SERVLET的服务的时候,Web Container能够动态地装载和实例化servlet,Container会创建Servlet的一个实例,并调用Servlet的init方法来初始化,一旦初始化了SERVLET,Servlet就能够随时地等候处理请求,这个时候Servlet处于可用服务状态,每当有一个客户请求SERVLET,Web Container都会为这个客户创建一个新的Servlet线程。用这种方法,Web Container能够处理对同一个Servlet的多个同时的请求,对每一个请求通常调用service 方法,当Web服务器卸载SERVLET的时候,调用destroy方法,Servlet会释放它所使用的任何资源。
生命周期中的各API方法(1/3) 1、Servlet的初始化 什么情况下初始化servlet -启动服务器时(配置了自动装入选项) 调用init()方法 init方法的形式是接收一个 ServletConfig对象参数,该参数描述有关Service环境的信息。 下面我们详细描述在Servlet生命周期中的一些重要的SERVLET API方法。首先初始化方法在下面这些情况发生,第一种情况是,如果已经配置了自动装入选项,那么在启动服务器的时候,会自动地装入Servlet并且初始化,第二种情况是,如果没有配置自动装入选项,那么在服务器启动后,当客户端首次向Servlet发出请求的时候,初始化Servlet,另外在重新装入Servlet的时候也会初始化Servlet。装入Servlet之后,服务器会创建一个Servlet的实例,并且调用Servlet的init方法,init方法在每个服务器会话中都会被调用,而且只被调用一次,初始化Servlet的时候,Servlet可以从数据库读取初始的数据,建立JDBC连接或者引用其它的资源。Servlet的init方法最初的形式是接收一个ServletConfig对象的参数。ServletConfig运行Servlet访问一组名称数值对来进行初始化。这个ServletConfig是特定与Servlet本身的,另外我们还可以提供ServletConfig对象来访问。这个对象描述了有关Service环境的信息。
生命周期中的各API方法(2/3) 2、Servlet如何处理请求 两个重要的参数对象 -HttpServletRequest对象封装客户的请求信息,包括客户的环境信息,和从客户端传到服务器端的任何的数据。 -HttpServletResponse对象封装了动态产生的响应,比如一个返回给客户的HTML页面,该页面通常是由来自HttpServletResponse对象的数据构成的。 service()、doGet()、doPost()方法 Servlet被初始化以后就能够处于响应请求的就绪状态,在Java Servlet API中,一个ServletRequest对象代表一个请求,相应的一个SERVLETResponse对象代表一个响应。在这章里我们主要介绍HttpServlet,因此相应的对象为HttpServletRequest和HttpServletResponse对象,HttpServletRequest对象封装客户的请求信息,这个信息包括客户的环境信息,和从客户端传到服务器端的任何的数据。HttpSerlvetResponse对象封装了动态产生的响应,比如说一个返回给客户的HTML页面,这个页面通常是由来自HttpServletResponse对象的数据构成的。我们刚才提到过,每当有一个客户请求,都会为这个请求生成一个新的Serlvet线程,用这种方式Servlet能够处理同一个Servlet的多个同时请求,对于每一个请求通常是调用它的service方法、doGet方法或者是doPost方法,这些方法都会以刚才我们说的HttpServletResponse和HttpServletRequest这两个对象作为参数 。
生命周期中的各API方法(3/3) 3、Servlet如何被释放 当Web服务器卸载SERVLET的时候会调用destroy()方法,通常在这个方法中执行一些清除资源的操作,比如释放数据库连接或者是关闭文件。 当Web服务器卸载SERVLET的时候会调用destroy方法,通常在这个方法中执行一些清除资源的操作,比如释放数据库连接或者是关闭文件。
Servlet示例 pachage simple.servlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class FirstSimpleServlet extends HttpServlet{ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException{ response.setContentType("text/html"); PrintWriter out=response.getWriter(); out.println("<HTML><TITLE>First servlet </TITLE><BODY>"); out.println("<H2>This is your first servlet. </H2><HR>"); out.println("</BODY></HTML>"); }
pachage simple.servlet; 自定义Java包 三个import语句是访问其它Java包的导入声明 pachage simple.servlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; 导入java.io包,在程序当中就可以访问一些标准的java IO操作。javax.servlet和javax.servlet.http的导入是非常重要的,这样才能在程序当中访问Servlet API的一些类和一些接口的方法。
示例分析-Service方法 public class FirstSimpleServlet extends HttpServlet{ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException.IOException{ response.setContentType("text/html"); PrintWriter out=response.getWriter(); out.println("<HTML><TITLE>First servlet </TITLE><BODY>"); out.println("<H2>This is your first servlet. </H2><HR>"); out.println("</BODY></HTML>"); } 在Service方法中定义了firstsimpleservlet类,它继承了HttpServlet,所以它是一个基于Http协议的一个Servlet。在这个类中实现了service方法,service方法处理请求和响应。该方法接收两个参数:HttpServletRequest和HttpServletResponse。 响应对象是返回一个HTML页面给客户端,首先通过setContentType方法把响应对象的内容类型设置为“text/html”类型,然后定义out为PrintWriter的响应对象,通过out的println语句把HTML文本写到响应中送回给客户端,客户端会显示相应的HTML页面。客户端可以通过HTML页面的Get或Post方法来调用这个页面。
HttpServlet Javax.servlet.http.HttpServlet支持HTTP协议 实现HTTP方法 -doGet()处理GET请求(URL) -doPost()处理POST请求(HTML表单) service()方法调用doGet()和doPost() 可能重载init()和destroy() Servlet是独立与协议的,它能够用于多组协议,比如HTT协议或者FTP协议,其中Javax.serlvet.http包当中的HttpServlet对HTTP协议提供了特别的支持。我们在第一章中曾经介绍过,当浏览器向服务器发送请求的时候,通常的请求类型为Get或Post方法,HttpServlet会根据HTTP不同的请求类型实现doGet方法或者是doPost方法。当一个客户提供HTML表单发送一个HTTP Get请求或者是直接请求一个RUL的时候,doGet方法会被调用,与 Get请求相关的参数会被添加到URL的后面,与这个请求一起发送给服务器,当用户通过HTML表单发送一个POST请求的时候,doPost方法会被调用,与POST相关的参数会作为一个单独的请求从浏览器发送给服务器,通常当需要修改服务器端的数据的时候,应当使用doPost方法, service方法会根据请求的类型的不同调用doGet方法或者是doPost方法。
Requests和Responses service(),doGet()和doPost()方法的参数 -HttpServletRequest提供访问请求信息 -HttpServletResponse动态产生的响应 大多数servlet读入一个请求,并产生一个动态的响应 Application Server servlet instance Browser (Client) Web Server 我们刚才介绍过service方法、doget方法和dopost方法都含义两个参数,一个是HttpServletRequest,另一个是HttpServletResponse,Request对象封装用户的请求信息,这些信息包括用户的环境信息和从客户端送到服务器端的数据。HttpServletRequest类包含从请求对象抽取信息的一系列方法。后面这个Response对象封装了动态产生的响应,比如说一个返回给客户的HTML页面,这个HTML页面一般是由HttpServletResponse的数据构成的,处理HTML页面以外,一个响应对象还可以是HTTP错误响应,或者是指向另一个URL的重定向,或者是一个Servlet。大多数Servlet读入一个请求并产生一个动态的响应。
HttpServletRequest 封装HTTP请求信息 -请求头信息:请求方法、浏览器类 型、正文长度等 -请求servlet的URL路径信息 -客户端安全类型 -参数 HttpServletRequest类定义了从请求对象中抽取信息的一系列方法 首先我们先来看HttpServletRequest参数,这个参数封装了HTTP请求信息,这些信息包括了HTTP请求头信息,这里有HTTP请求方法,是Get还是Post,客户端浏览器的类型是IE还是mozic或者是其它的浏览器类型,还有请求信息的类型和长度等。另外还包括了客户端请求Servlet的URL的路径信息,客户端的安全类型是否支持COOKIE,另外还有跟随在URL后面的参数。HttpServletRequest类定义了从请求对象中抽取信息的一系列的方法。 现在我们分别举几个例子。
HTTP请求信息 一段HTTP请求信息 POST /Music/SearchServlet HTTP/1.0 Referer:http://www.music.ibm.com/musicSearch.html Connection:Keep-Alive User-Agent:Mozilla/4.72[en](WinNT 5.0; U) Host:localhost:8080 Accept:image/gif,image/x-xbitmap,image/jpeg,*/* Accept-Language:en Accept-Charset:iso-8859-1,*,utf-8 Content-length:50 song_title=Hello&song_artist=Jones&limit_number=20 首先我们看如何从Request对象当中获取HTTP请求头信息。屏幕上显示的是一段HTTP请求信息,首先这个请求的方法是POST方法,请求的RUL是一个Servlet,HTTP版本号为1.0,referer包含一个URL,用户就是从这个URL代表的页面中发送请求信息的,Connection表示是否需要持久连接,如果Servlet看到这里的值是keep-alive或者看到请求的版本号是1.1的话,这个1.1版本默认进行持久连接。那么这个时候Servlet就会利用持久连接的优点,当页面包含多个页面的时候,可以显著地减少下载所需要的时间。User-Agent表示浏览器的类型,在这个例子中浏览器是Mozilla,Servlet可以工具浏览器类型的不同返回不同的内容。 Host是初始URL当中主机和端口号Accept表示浏览器可以接收的MIME类型,Accept-Language表示所希望的语言种类,当服务器能够支持一种以上语言版本的时候,可以根据浏览器语言设置的不同返回不同语言的HTML页面,这个例子中浏览器支持的是英文。Accept-Charset表示浏览器可以接受的字符集,Content-lenth表示请求信息正文的长度。 下面这个部分是跟随在URL地址后面的参数。
通过HttpServletRequest获取HTTP信息 getHeader("headername") 例如:getHeader("Accept-Language") 请求头:Content-type、Content-length 方法:getContentType()、 getContentLength 请求头:Cookie 方法:getCookies() 方法:getMethod()返回请求方法 如何获取这些HTTP头信息呢?在Servlet当中读取HTTP头是非常方便的,我们可以通过HttpServletRequest的getHeader方法指定一个header的名字,比如说Accept-Language,getHeader方法会返相应的回头信息。有些头信息是经常要用到的,所以它们会有自己专用的访问方法,比如说要获得Content-type或Content-lenth的信息可以通过getContentType或getContentLenth方法获取。getCookies方法会返回Cookie头的内容,把它解析后会存放在Cookie数组当中。getMethod方法会返回请求方法,通常是GET或Post。下面我们举一个例子。
示 例 private void processRequest(HttpServletRequest request, HttpServletResponse response) { ...... String method=request.getMethod(); if(method.equals("GET")) { //作相应的处理 } String lang=request.getHeader("Accept- Language"); //得到浏览器支持的语言 ...... } 在这个例子当中我们假设processRequest会被doGet或者doPost方法调用,但是我们现在还不知道是doGet还是doPost方法在调用这个方法,所以我们要从请求信息的请求方法中判断到底是那一个,所以我们通过request的getMethod方法得到请求信息中的请求方法,存储在Sting类型当中,然后根据If作判断,作不同的处理,另外我们想知道浏览器支持的语言,可以通过request.getHEADER方法将参数Accept-Lanuage参数传给它,得到浏览器支持的语言。
通过HttpServletRequest获取参数 名称数值对 两种 -跟随在URL地址后的参数数组 -POST提交的参数 获取参数的方法 -getParameterNames()返回参数名字 -getParameterValues(String name) -getParameter(String name) HTTP请求信息中的参数通常为名称数值对的形式,包括两种,一种是跟随在URL地址后的参数数组parastring,另一种是POST提交的参数,两者的顺序是这样的,跟随在URL地址后的参数数组会放在前面,POST提交的参数会放在后面,如果这两者有相同名字的参数的话,那么具有相同名字的参数会有多个值。HttpServletRequest有这样一些方法来获取这些参数,getParameterNames返回所以参数的名字,getParameterValues由参数name获取给定名字的参数,得到的可能不止一个值,我们刚才提到过同一名字的参数可能有多个值。getParameter(String name)是获取给定名字的参数,这个方法是只得到一个值。
获取参数示例 <song_title,value_entered> <song_artist,value_entered> <P>Please fill out this form with the song's name. <FORM METHOD="POST" ACTION="/Music/SearchServlet"> <P>Song Name: <INPUT NAME="song_title" TYPE="TEXT" SIZE="12" MAXLENGTH="20"> <P>Artist Name: <INPUT NAME="song_artist" TYPE="TEXT" SIZE="15" MAXLENGTH="25"> <P>Thank you! <INPUT TYPE="SUBMIT"> <INPUT TYPE="RESET"> </FORM> 举一个例子,在这个HTML表单当中METHOD方法是Post方法,用户输入的数据会作为Post参数传递给Web服务器,Action当中的Servlet URL表示当这个表单被提交的时候,也就是SUBMMIT的时候,会调用SearchServlet这个Servlet,在这个表单当中用户输入了歌曲的名字和歌曲作者的名字,分别作为song_title这个参数的数值和song_artist这个参数的数值,这两个名称数值对会作为参数在HTTP请求传给Servlet,我们可以通过HttpServletRequest对象来访问它们。
获取参数示例 public class SearchServlet extends HttpServlet{ public void doPost(HttpServletRequest req, HttpServletResonse res) throws ServletException,IOException{ ... Enumeration enum=req.getParameterName(); while(enum.hasMoreElements()){ String name=(String)enum.netElement(); String value=req.getParameter(name); //对每个参数作相应操作 } String title=req.getParameter("song_title"); SearchServlet这个Servlet当中,我们通过Request的getParameterNames方法得到所有的参数的名字,也就是这两个参数,一个是song_title,一个song_artist。然后通过enum的hasMoreElements方法一一读出这些参数,从而得到用户输入的数据。另外也可以通过getParameter方法直接给定。song_title参数的名字得到song_title的数值。
HttpServletResponse HttpServletResponse封装动态产生的响应 Servlet通过HttpServletResponse把所有的响应信息传递给客户 设置content type、状态码 设置content Header(cookies,caching) 响应对象还可以是指向另一个URL的重定向 HttpSerlvetResponse对象封装了动态产生的响应,Servlet通过HttpServletResponse把所有的响应信息传递给客户,通常来讲返回给客户端的是一个HTML页面,这个页面是由HttpServletResponse对象来设置的,可以设置HTTP响应的contenttype内容类型,也可以设置状态码,设置Content Header,象Cookies、缓存信息等等。另外响应对象还可以是一个HTTP错误响应或者是指向另外一个URL的重定向。通过HttpServletResponse,Servlet可以把动态的内容返回给客户。
HttpServletRepsonse的方法 HTTP响应信息 setContentType(String type) getWriter() -PrintWriter对象 getOutputStream() -ServletOutputStream HTTP/1.1 200 OK Content-Type;text/plain Hello World 通常web响应服务器响应浏览器或者是其它web客户应用程序的时候,响应的信息一般由下面这几个信息组成,一个状态行几个应答头,一个空行和返回的内容文档。屏幕上就是一个非常简单的响应信息,第一行是状态行,200表示成功OK,第二行是一个应答头Content-Type,它描述的是文档的MIME类型。空行之后是返回的内容文档。我们可以通过HttpServletResponse的setContentType方法来设置应答头ContentType,这个设置是必须的。getWriter方法得到PrintWriter对象,响应的信息就是通过PrintWriter对象返回给浏览器的。PrintWriter对象通常会生成一个HTML文档或者是XMl文档。getOutputStream方法返回一个ServletOutputStream对象,用来创建二进制文档
HTTP 1.1状态代码及其含义 HTTP 1.1中定义的状态码有以下几种 1**表示初始的请求已经接受,客户应当继续发送请求的其余部分 2**表示响应成功 - 200 OK 3**表示重定向 - 301 Moved Permanently 4**表示客户端错误 - 404 Not Found 5**表示服务器端错误 - 503 Service Unavailable 通常返回信息中必须包含状态码。HTTP1.1版本中定义的状态码有下面这几种。1开始的表示初始的请求已经被接受了,客户应当继续发送请求的其余的部分。2开头的表示响应成功,比如200 OK表示一切正常。对GET或POST的应答文档会跟在后面。3开头的状态码通常表示重定向,比如301 Moved Pernanently表示客户请求的文档是在其它地方,新的URL会在Location头中给出,浏览器应该自动重定向,访问新的URL。4开头的表示客户端错误,比如401 unauthorright表示客户未经授权试图访问受密码保护的页面,404 Not Found表示无法找到指定的资源。5开头的表示服务器端错误,比如503 Service Unavailable,服务器由于维护或者是负载过重不能回答。比如Servlet可能会在数据库连接池已满的情况下返回503。
HttpServletResponse设置状态码 HttpServletResponse.setStatus() -参数是一个整数,也就是状态代码 为使代码具有更好可读性,用常量替换整数 常量根据HTTP 1.1中的标准状态信息命名,加SC前缀 -状态码404对应常量名字为SC_NOT_FOUND 定制应答时应当在通过PrintWriter发送任何内容之前先调用response.setStatus()。 Servlet状态码的设置一般可以使用HttpServletResponse的setStatus方法,setStatus的参数是一个整数,也就是状态代码,不过为了使状态代码具有更好的可读性,一般用HttpServletResponse中定义的常量来避免直接使用整数。常量根据HTTP1.1中的标准状态信息命名,所有的名字都加上了大写的SC前缀,也就是Status Code的缩写,同时把空格换成了下划线。比如说,404对于的信息是Not Found,而HttpServletResponse中对应的常量是SC_NOT_FOUND。注意一点是在定制应答时应当在通过PrintWriter发送任何内容之前先调用response.setStatus方法设置状态码。
示例 public class MyServlet extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException,IOException{ res.setStatus(HttpServletResponse.SC_OK); res.setContentType("text/html"); PrintWriter out=res.getWriter(); out.println(" <HTML><BODY><H1>Today is " +(new Date())); out.println("</H1></BODY></HTML>"); } 这是一个很简单的例子。这个servlet返回的是一个HTML页面,页面上有当天的日期,doGet方法包括三大部分,首先调用HttpServletResponse的Setstatus和SetContentType函数设定返回的HTTP应答头,分别表示响应成功,返回的页面是HTML页面,然后得到一个PrintWriter对象out,然后将HTML代码写入out中返回给客户端。
Servlet示例 package simple.servlet import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletException; import javax.io.IOException; import javax.io.PrintWriter; public class AnotherSimpleServlet extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) throws SERVLETException,IOException{ String browser=request.getHeader("User-Agent"); response.setStatus(HttpServletResponse.SC_OK); response.setContentType("text/html"); PrintWriter out=response.getWriter(); out.println("<HTML><HEAD><TITLE>First servlet</TITLE></HEAD>"); out.println("<BODY>Browse details:"+browser+"</BODY></HTML>"); } 下面我们在看一个完整的例子,这个Serlvet也是实现了使用doGet方法向客户端发送一个HTML页面。Serlvet的名字定义为AnotherSimpleSerlvet放在java包simple.servlet当中。import方法引入了这段代码中可能会使用到的其它的java包。AntherSimpleServlet继承了HttpServlet。在doGet方法中通过HttpServletRequest的getHeader方法,给定User-Agent参数得到浏览器的类型,然后设置状态码和ContentType内容类型,然后通过PrintWriter对象out将HTML代码返回给客户端。
Web Containers和Servlet Context javax.servlet.ServletContext接口 -定义Servlet的环境对象,多个客户端共 享信息 www.hotel.ibm.com /HRApps/Personnel /Rooms /Hire /Retire /Log in /DisplayRooms Servlet Context /Room web container 下面我们来看Servlet Context对象。每个Web应用程序都有一个惟一的Servlet Context对象,它继承了javax.servlet.ServletContext接口,它供多个客户端共享信息,servlet Context对象可以看成是一个Web应用程序的程序级别的对象映射,我们可以利用它来共享和存储基于Web应用级别的数据。比如在这张图当中,Web应用服务器设的站点为www.hotel.ibm.com,这个站点的所有Web应用程序都会运行在同一个Web Container当中。图中显示了两个应用程序,一个是HRApps下的Personnel,它创建了自己的Servlet,Hire和Retire两个Servlet,另外一个应用程序是Rooms,它也有自己的Servlet,Log in和DisplayRooms,而这两个应用程序分别有它们各自的Servlet Context,互不影响,通过URL标识符来区分。应用程序中的Servlet可以通过这个Web Container共享和存储基于Web应用程序级别的数据。
Request Dispatcher java.servlet.RequestDispatcher对象实现流控制技术 forward(转发) -把处理用户请求的控制权转交给其它Web组件 include(包括) -执行include的组件维持对请求的控制权,只是简单地请求另一个组件的输出包括在本页面的某个特定的地方 大多数情况下,在Web应用程序我们要使用多个Servlet或JSP页面来完成一个请求,这就需要使用某种类型的流控制技术。Servlet提供两种这样的技术,一个是forward,转发,一个是include,包括。forward和include都是通过一个专门的对象java.servlet.ResponseDispatcher来完成的。forward会把处理用户请求的控制权转交给其它的Web组件,forward在有些时候比较有用,比如说需要用一个组件来设置多个JavaBean,打开或者是关闭资源,验证用户,或者是将控制权传递给下一个组件之前执行一些准备工作的时候。第二种流控制技术是include,在使用forward的时候要传递控制权,与之不同的是,执行include的组件维持对请求的控制权,只是简单地请求将另一个组件的输出包括在本页面的某个特定的地方。对于一些常见的设计元素,比如说页面,页脚,导航栏等等,使用include是一个非常好的方法。
forward和include Servlet A B forward Content returned to Browser 那么forward和include两者有什么区别呢?首先对于forward,要转发的组件不能设置响应头部信息,也不能有内容发送给输出缓冲区,所有与客户所发送的内容有直接相关的任务必须由被转发的组件完成,也就是Servlet A不能设置响应头信息,也不能由内容发送到输出缓冲区,这些工作由Servlet B来完成。对于include,Servlet B不能设置响应头信息,这些工作由SERVLET A来完成。
getRequestDispatcher() getServletContext() getRequestDispatcher("/pages/ showBalance.jsp").forward(req,res); navigation.html").include(req,res); 如何获得一个requestDispatcher对象呢?我们可以调用ServletContext对象的getRequestDispatcher方法,然后我们就可以调用这个Dispatcher的forward和include方法。
forward()示例 private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOExcption{ ... if(errorFound){ String errorPage="/ErrorFound.html"; getServletContext(). getRequestDispatcher(errorPage). forward(request,response); return; } 这是一个forward的例子,在方法processRequset当中我们作逻辑判断,如果重新错误的话就会把流程转向一个错误页面,也就是ErrorFound.html页面。在这里调用getServletContext方法得到ServletContext对象,然后调用getRequestDispatcher方法获得RequestDispatcher对象,紧接着调用forward,把流程转向错误页面ErrorFound.html。
共享数据 共享数据 有以下几种方式在Servlet或JSP页面之间 ServletContext -getServletContext().setAttribute ("objectName",anObject); ("objectName"); HttpServletRequest -request.setAttribute ("objectName",anObject) -request.getAttribute("objectName"); 应用程序的各个Servlet或JSP页面之间可以通过以下这几种方式来共享数据。我们刚才提到过对于一个Web应用程序它有一个独立的ServletContext对象,应用程序中的任何一个Servlet都可以访问这个ServletContext,通过它的getServletContext.setAttribute方法共享数据,当使用forward或include方法时,我们还可以使用HttpServletRequest的getAttribute和setAttribute方法来共享数据。
示例 //Servlet "A" private void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException,IOException{ Customer cust; ... req.setAttribute("CUSTOMER",cust); String nextServlet="/Internal/ServletB"; getServletContext().getRequestDispatcher(nextServlet). forward(req,res); return; } //Servlet "B" Customer aCust=(Customer)req.getAttribute("CUSTOMER"); ... } 我们再来看一个例子,这里有两个Serlvet,一个是Servlet A一个是Servlet B。Servlet A调用RequestDispatcher的forward方法把控制转交给Servlet B,在SERVLET A中定义的CUSTOMER类的实例是cust,然后把这个对象通过setAttribute方法放在HttpServletRequest当中。当控制权转交给Servlet B的时候,HttpServletRequest对象和HttpServletResponse对象也会转交给Serlvet B。在Servlet B当中可以通过getAtrribute方法得到这个实例cust。
ServletConfig和初始化参数 javax.servlet.ServletConfig接口 相关方法 -由于Container配置Servlet -每一个ServletConfig对象对应着一个唯一的Servlet -名称数值对形式 相关方法 -getServletConfig() -public String getInitParameter(String name) -public Enumeration getInitParameterNames() 下面我们再来看ServletConfig对象,ServletConfig对象继承了javax.servlet.ServletConfig接口,用于Container容器来配置一个Servlet,每一个ServletConfig对象对应一个唯一的Servlet,ServletConfig主要用于存取Servlet实例的初始化数,这些参数以名称数值对的形式存在与ServletConfig当中。我们可以通过getServletConfig方法得到ServletConfig,通过ServletConfig的getInitParameter方法得到特定名字的初始化参数的数值,也可以通过getInitParameterNames方法得到所有的初始化参数的名字,
Servlet对象 Thread 1 Client1 Thread 2 Client2 Servlet A ServletRequest ServletResponse ServletConfig ServletContext Client1 Client2 Servlet A 我们已经介绍了有关Servlet的多个对象,下面我们看各个Servlet对象之间的关系。在这里,两个客户端,Client1和Client2访问同一个Servlet A,Serlvet A 会为这两个不同的客户端创建两个不同的线程Thread1和Thread2,因为访问的是同一个Servlet,所以Thread1和Thread2共享一个SerlvetConfig对象,同样我们前面提到过,ServletContext是针对整个应用程序的对象,所以Thread1和Thread2也共享同一个SerlvetContext对象,而ServletRequest对象和ServletResponse对象是针对Servlet实例的,所以Thread1和Thread2各有各自的ServletRequest和ServletResponse对象。
Servlet对象 Servlet A Thread 1 Client1 Servlet B Thread 2 Client2 ServletRequest ServletResponse ServletConfig ServletContext Client1 Client2 我们再来看一种情况,在这里,两个客户端Client1和Client2访问同一个Web应用程序的两个不同的Servlet,servletA和SerlvetB,因为访问的是同一个Web应用程序,所以Thread1和Thread2共享同一个servletContext对象,但是因为访问的是不同的Servlet,所以SerlvetA和SerlvetB各自有各自的ServletConfig对象,所以Thread1和Thread2分别访问不同的ServletConfig对象。对应ServletRequest和ServletResponse它们是针对Servlet实例的,所以Thread1和Thread2各有各自的ServletRequest和ServletResponse对象。
总结 什么是Servlet Servlet相比于CGI的特性 Servlet的处理流程和生命周期 HttpServlet -HttpServletRequest和HttpServletResponse ServletContext -RequestDispatcher ServletConfig Servlet对象之间的关系
Servlet程序示例 启动Eclipse,创建一个项目。
并在该项目下创建新的HttpServlet类Info,将该类放入test包中。
在Info类的编辑区域中输入代码
编写项目的web.xml文件。在/WEB-INF目录下新建该文件。并输入代码。
启动Tomcat,在浏览器地址栏输入http://localhost:8080/chapter03/Info,可以看到结果页面。