JSP动态WEB技术与开发实例第七章Servlet技术Word文档格式.docx
《JSP动态WEB技术与开发实例第七章Servlet技术Word文档格式.docx》由会员分享,可在线阅读,更多相关《JSP动态WEB技术与开发实例第七章Servlet技术Word文档格式.docx(33页珍藏版)》请在冰豆网上搜索。
•响应:
Servlet模块接受请求后,调用相应的服务(service())对请求进行处理,然后将处理结果返回给Servlet引擎。
•HTTP响应:
Servlet引擎将结果发送给客户端。
Servlet看起来像是通常的Java程序。
Servlet导入特定的属于JavaServletAPI的包。
因为是对象字节码,可动态地从网络加载,可以说Servlet对Server就如同Applet对Client一样,但是,由于Servlet运行于Server中,它们并不需要一个图形用户界面。
从这个角度讲,Servlet也被称为FacelessObject。
一个servlet就是Java编程语言中的一个类,它被用来扩展服务器的性能,服务器上驻留着可以通过“请求-响应”编程模型来访问的应用程序。
虽然servlet可以对任何类型的请求产生响应,但通常只用来扩展Web服务器的应用程序。
7.1.3Servlet的特点
•高效
在传统的CGI中,每个请求都要启动一个新的进程,如果CGI程序本身的执行时间较短,启动进程所需要的开销很可能反而超过实际执行时间。
而在Servlet中,每个请求由一个轻量级的Java线程处理(而不是重量级的操作系统进程)。
在传统CGI中,如果有N个并发的对同一CGI程序的请求,则该CGI程序的代码在内存中重复装载了N次;
而对于Servlet,处理请求的是N个线程,只需要一份Servlet类代码。
在性能优化方面,Servlet也比CGI有着更多的选择,比如缓冲以前的计算结果,保持数据库连接的活动等。
•方便
Servlet提供了大量的实用工具例程,例如自动地解析和解码HTML表单数据、读取和设置HTTP头、处理Cookie、跟踪会话状态等。
•
功能强大
在Servlet中,许多使用传统CGI程序很难完成的任务都可以轻松地完成。
例如,Servlet能够直接和Web服务器交互,而普通的CGI程序不能。
Servlet还能够在各个程序之间共享数据,使得数据库连接池之类的功能很容易实现。
•可移植性好
Servlet用Java编写,ServletAPI具有完善的标准。
因此,为I-PlanetEnterpriseServer写的Servlet无需任何实质上的改动即可移植到Apache、MicrosoftIIS或者WebStar。
几乎所有的主流服务器都直接或通过插件支持Servlet。
节省投资
不仅有许多廉价甚至免费的Web服务器可供个人或小规模网站使用,而且对于现有的服务器,如果它不支持Servlet的话,要加上这部分功能也往往是免费的(或只需要极少的投资)。
7.2Servlet基本结构
Servlet模块是用ServletAPI编写的.ServletAPI包含两个包:
javax.servlet和javax.servlet.http。
javax.servlet包中的类与http协议无关;
javax.servlet.http包中的类与http协议相关,该包中的部分类继承了javax.servlet包中的部分类和接口.下面介绍编写Servlet类时要继承的超类和父类。
即GenericServlet和HttpServlet。
7.2.1GenericServlet类
GenericServlet类在javax.servlet包中,它提供了
servlet接口的基本实现,该类包含三个重要的方法,它们是init()、destroy()和service()方法。
service()是抽象方法,所有子类都应当实现这个方法。
7.2.2HttpServlet类
HttpServlet类在javax.servlet.http包中,它扩展了GenericServlet类。
HttpServlet类定义了两个service()方法和六个doXXX()方法。
(1)两个service()方法
publicvoidservice(ServletRequestrequest,ServletResponseresponse)throwsServletException,IOException
{
…//方法代码
}
本方法是公有方法。
该方法接收客户端请求包后,创建request对象和response对象,并分别转换为HttpServletRequest/HttpServletResponse类型的对象,然后调用下面的保护service()方法。
protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException
该方法接收HttpServletRequest/HttpServletResponse类型的对象后,根据http请求方法的类型,本方法调用下面6个doXXX()方法之一,进行逻辑处理并响应客户。
(2)doXXX()方法
doXXX()方法有6个:
doGet(),doPost(),doDelete(),doPut(),doTrace(),doOption()。
它门分别对应Form表单中的method属性。
get方法提交的数据量不能超过2kB,否则提交失败,post提交没有容量限制。
下面是doGet()方法和doPost()方法。
protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException
…//具体要处理的逻辑代码写在此处,或者在此处调用被覆盖的doPost()方法。
protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException
…//具体要处理的逻辑代码写在此处,或者在此处调用被覆盖的doGet()方法。
程序员自定义的Servlet类都必须扩展HttpServlet类.在扩展类中,覆盖service()、doPost()或doGet()方法实现逻辑处理。
7.2.3编写Servlet类的步骤
下面是程序员编写Servler类时的一般步骤:
(1)扩展HttpServlet类
(2)覆盖HttpServlet类中的三个方法service()、doPost()或doGet(),将要处理的逻辑代码写在以上三个方法的任一个中。
Servlet模块执行service()方法时,会自动调用doPost()或doGet()这两个方法,实现servlet逻辑处理功能。
7.2.4Servlet的基本结构
下面的代码显示了一个简单Servlet的基本结构。
该Servlet处理的是GET请求,所谓的GET请求,如果你不熟悉HTTP,可以把它看成是当用户在浏览器地址栏输入URL、点击Web页面中的链接、提交没有指定METHOD的表单时浏览器所发出的请求。
Servlet也可以很方便地处理POST请求。
POST请求是提交那些指定了METHOD=“POST”的表单时所发出的请求,具体请参见稍后几节的讨论。
importjava.io.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassSomeServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,IOException
//使用“request”读取和请求有关的信息(比如Cookies)和表单数据
//使用“response”指定HTTP应答状态代码和应答头(比如指定内容类型,设置Cookie)
PrintWriterout=response.getWriter();
//使用"
out"
把应答内容发送到浏览器
}
如果某个类要成为Servlet,则它应该从HttpServlet继承,根据数据是通过GET还是POST发送,覆盖doGet、doPost方法之一或全部。
doGet和doPost方法都有两个参数,分别为HttpServletRequest类型和HttpServletResponse类型。
HttpServletRequest提供访问有关请求的信息的方法,例如表单数据、HTTP请求头等等。
HttpServletResponse除了提供用于指定HTTP应答状态(200,404等)、应答头(Content-Type,Set-Cookie等)的方法之外,最重要的是它提供了一个用于向客户端发送数据的PrintWriter。
对于简单的Servlet来说,它的大部分工作是通过println语句生成向客户端发送的页面。
注意doGet和doPost抛出两个异常,因此你必须在声明中包含它们。
另外,你还必须导入java.io包(要用到PrintWriter等类)、javax.servlet包(要用到HttpServlet等类)以及javax.servlet.http包(要用到HttpServletRequest类和HttpServletResponse类)。
最后,doGet和doPost这两个方法是由service方法调用的,有时你可能需要直接覆盖service方法,比如Servlet要处理GET和POST两种请求时。
7.2.5简单Servlet应用示例
下面给出两个简单的Servlet应用示例,通过这两个例子,让读者来了解Servlet运行的整个流程。
下面是一个输出纯文本的简单Servlet。
例7-1Servlet示例。
FirstServlet.java
packagetest;
importjava.io.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassFirstServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException
{
PrintWriterout=response.getWriter();
out.println("
Thisismyfirstservlet!
"
);
在Tomcat7.0下,Servlet应该放到Web应用的\WEB-INF\classes\目录下的相应的包中,而调用Servlet的URL是http:
//host/servlet/ServletName。
在其他的服务器上,安装和调用Servlet的方法可能略有不同。
将编译后的FirstServlet.class文件部署到ch7\WEB-INF\classes\test目录中,并在WEB-INF目录下的web.xml配置文件中做如下配置:
<
servlet>
description>
ThisisthedescriptionofmyJ2EEcomponent<
/description>
display-name>
ThisisthedisplaynameofmyJ2EEcomponent<
/display-name>
servlet-name>
FirstServlet<
/servlet-name>
servlet-class>
test.FirstServlet<
/servlet-class>
/servlet>
servlet-mapping>
url-pattern>
/servlet/FirstServlet<
/url-pattern>
/servlet-mapping>
其中<
<
用来声明一个servlet的数据;
指定servlet的名称;
指定servlet的类名称;
用来定义servlet所对应的URL;
指定servlet所对应的URL。
在浏览器的地址栏中输入http:
//localhost:
8080/JSPB/servlet/FirstServlet,运行后如图7-2所示:
图7-2FirstServlet运行结果
大多数Servlet都输出HTML,而不象上例一样输出纯文本。
要输出HTML还有两个额外的步骤要做:
告诉浏览器接下来发送的是HTML;
修改println语句构造出合法的HTML页面。
第一步通过设置Content-Type(内容类型)应答头完成。
一般地,应答头可以通过HttpServletResponse的setHeader方法设置,但由于设置内容类型是一个很频繁的操作,因此ServletAPI提供了一个专用的方法setContentType。
注意设置应答头应该在通过PrintWriter发送内容之前进行。
下面是一个实例。
例7-2输出HTML的Servlet。
OutHtml.java
publicclassOutHtmlextendsHttpServlet{
response.setContentType("
text/html;
charset=gb2312"
PrintWriterout=response.getWriter();
out.println("
html>
\n"
head>
title>
用Servlet输出Html代码<
/title>
/head>
);
body>
h2>
欢迎来到Servlet世界!
/h2>
/body>
/html>
运行的结果如图7-3所示:
图7-3用Servlet输出Html代码
7.3处理表单数据
如果你曾经使用过Web搜索引擎,或者浏览过在线书店、股票价格、机票信息,或许会留意到一些古怪的URL,比如“http:
//host/path?
user=Marty+Test&
origin=bwi&
dest=lax”。
这个URL中位于问号后面的部分,即“user=Marty+Test&
origin=bwi&
dest=lax”,就是表单数据,这是将Web页面数据发送给服务器程序的最常用方法。
对于GET请求,表单数据附加到URL的问号后面(如上例所示);
对于POST请求,表单数据用一个单独的行发送给服务器。
以前,从这种形式的数据提取出所需要的表单变量是CGI编程中最麻烦的事情之一。
首先,GET请求和POST请求的数据提取方法不同:
对于GET请求,通常要通过QUERY_STRING环境变量提取数据;
对于POST请求,则一般通过标准输入提取数据。
第二,程序员必须负责在“&
”符号处截断变量名字-变量值对,再分离出变量名字(等号左边)和变量值(等号右边)。
第三,必须对变量值进行URL反编码操作。
因为发送数据的时候,字母和数字以原来的形式发送,但空格被转换成加号,其他字符被转换成“%XX”形式,其中XX是十六进制表示的字符ASCII(或者ISOLatin-1)编码值。
例如,如果HTML表单中名为“users”的域值为“~test,~gates,and~mcnealy”,则实际向服务器发送的数据为“users=%7Etest%2C+%7Egates%2C+and+%7Emcnealy”。
最后,即第四个导致解析表单数据非常困难的原因在于,变量值既可能被省略(如“param1=val1&param2=&param3=val3”),也有可能一个变量拥有一个以上的值,即同一个变量可能出现一次以上(如“param1=val1&param2=val2&param1=val3”)。
JavaServlet的好处之一就在于所有上述解析操作都能够自动完成。
只需要简单地调用一下HttpServletRequest的getParameter方法、在调用参数中提供表单变量的名字(大小写敏感)即可,而且GET请求和POST请求的处理方法完全相同。
getParameter方法的返回值是一个字符串,它是参数中指定的变量名字第一次出现所对应的值经反编码得到得字符串(可以直接使用)。
如果指定的表单变量存在,但没有值,getParameter返回空字符串;
如果指定的表单变量不存在,则返回null。
如果表单变量可能对应多个值,可以用getParameterValues来取代getParameter。
getParameterValues能够返回一个字符串数组。
最后,虽然在实际应用中Servlet很可能只会用到那些已知名字的表单变量,但在调试环境中,获得完整的表单变量名字列表往往是很有用的,利用getParamerterNames方法可以方便地实现这一点。
getParamerterNames返回的是一个Enumeration,其中的每一项都可以转换为调用getParameter的字符串。
下面是一个简单的例子,它读取三个表单变量param1、param2和param3,并以HTML列表的形式列出它们的值。
请注意,虽然在发送应答内容之前必须指定应答类型(包括内容类型、状态以及其他HTTP头信息),但Servlet对何时读取请求内容却没有什么要求。
另外,我们也可以很容易地把Servlet做成既能处理GET请求,也能够处理POST请求,这只需要在doPost方法中调用doGet方法,或者覆盖service方法(service方法调用doGet、doPost、doHead等方法)。
在实际编程中这是一种标准的方法,因为它只需要很少的额外工作,却能够增加客户端编码的灵活性。
如果你习惯用传统的CGI方法,通过标准输入读取POST数据,那么在Servlet中也有类似的方法,即在HttpServletRequest上调用getReader或者getInputStream,但这种方法对普通的表单变量来说太麻烦。
然而,如果是要上载文件,或者POST数据是通过专门的客户程序而不是HTML表单发送,那么就要用到这种方法。
注意用第二种方法读取POST数据时,不能再用getParameter来读取这些数据。
例7-3处理表单数据示例。
ThreeParams.java
packagetest;
importjava.util.*;
publicclassThreeParamsextendsHttpServlet{
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
response.setContentType("
text/html"
Stringtitle="
读取三个请求参数"
;
out.println(ServletUtilities.headWithTitle(title)+
"
BODY>
+
H1ALIGN=CENTER>
+title+"
/H1>
UL>
LI>
param1:
+request.getParameter("
param1"
)+"
param2:
param2"
param3:
param3"
/UL>
/BODY>
/HTML>
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponser