第6章servlet基础.docx
《第6章servlet基础.docx》由会员分享,可在线阅读,更多相关《第6章servlet基础.docx(24页珍藏版)》请在冰豆网上搜索。
第6章servlet基础
第6章Servlet基础
本章向读者展示了JavaWeb中重要的应用组件:
servlet。
首先介绍了servlet的基本概念、特点、生命周期等基础知识,然后通过例子告诉读者如何编写和部署自己的servlet,最后介绍了servlet体系中的常用类和接口及其应用。
6.1servlet技术简介
6.1.1servlet的历史及技术特点
正如第一章所述,servlet是先于JSP的一种服务器端技术,实际上JSP也是最终被服务器转换为一个servlet。
在该技术出现以前,服务器端技术采用CGI技术,CGI全称是“公共网关界面”(CommonGatewayInterface),实际上是HTTP服务器与计算机其它程序进行“交谈”的一种工具,程序需运行在网络服务器上,是最早的动态网页技术之一。
绝大多数的CGI程序被用来解释处理来自表单的输入信息,并在服务器产生相应的处理,或将相应的信息反馈给浏览器。
CGI程序使网页具有交互功能。
主要用Perl、ShellScript或C编写。
CGI程序最初在UNIX操作系统上CERN或NCSA格式的服务器上运行。
在其它操作系统(如:
windowsNT等)的服务器上也广泛地使用CGI程序,同时它也适用于各种类型机器。
CGI处理步骤:
1、通过Internet把用户请求送到服务器。
2、服务器接收用户请求并交给CGI程序处理。
3、CGI程序把处理结果传送给服务器。
4、服务器把结果送回到用户。
CGI技术开启了动态Web应用的时代,给了这种技术无限的可能性。
但CGI技术存在很多缺点,主要有:
1:
CGI应用开发比较困难,因为它要求程序员有处理参数传递的知识,这不是一种通用的技能。
2:
CGI不可移植,为某一特定平台编写的CGI应用只能运行于这一环境中。
3:
每一个CGI应用存在于一个由客户端请求激活的进程中,并且在请求被服务后被卸载。
这种模式将引起很高的内存、CPU开销,而且在同一进程中不能服务多个客户。
到1997年时,随着Java语言的广泛使用,servlet技术迅速成为动态Web应用的主要开发技术。
servlet是一种独立于平台和协议的服务器端的Java小应用程序,一个基于Java技术的Web组件,运行在服务器端,本身没有main()方法,不是由用户或程序员调用,而是由另外一个应用程序(容器,如Tomcat)所调用和管理,用于生成动态的内容。
实际上就是按照servlet规范编写一个Java类。
servlet被编译为平台中立的字节码,可以被动态地加载到支持Java技术的Web服务器中运行。
简单的来说,servlet是在服务器上运行的小应用程序。
servlet可以完成和CGI相同的功能。
其工件原理也类似,但具有下列优点:
1、由于内置对象(request,reponse,session,application及out等)的支持,servletAPI的应用,不需要处理参数传递及解析,使开发过程变得容易。
2、servlet提供了Java应用程序的所有优势——可移植、稳健、易开发。
使用servletTag技术,servlet能够生成嵌于静态HTML页面中的动态内容。
3、servlet对CGI的最主要优势在于一个servlet被客户端发送的第一个请求激活,然后它将继续运行于后台,等待以后的请求。
每个请求将生成一个新的线程,而不是一个完整的进程。
多个客户能够在同一个进程中同时得到服务。
一般来说,servlet进程只是在WebServer卸载时被卸载。
综上所述,由于其开发简单、跨平台、功能强大、多线程、安全性好等特点,自从该技术出现以来,以渐渐成为WEB开发的主流技术之一,也成为电子商务系统开发的标准技术。
6.1.2servlet的主要功能、运行过程及生命周期
1、servlet的主要功能及方法
正如前节所述,servlet开发容易且功能强大。
实际上,servlet拥有JSP所具有的所有功能,JSP能实现的,servlet也能做到,只不过在实现的方法和手段上有所区别。
下面对二种技术进行比较及说明。
静态页面其它客户端技术
JavaBean或其它Java组件
内置对象
JSP
用Html等脚本语言,可借助第三方软件(网页制作),支持JS等客户端技术。
功能强大。
用指令标签useBean>支持JavaBean,可在页面内通过<%%>和<%!
%>定义和使用Java组件。
支持
servlet
用编程方式实现,得不到第三方软件支持,不支持JS等客户端技术。
不如JSP。
由于servlet本身就是一个Java类,因此,它与其它Java组件的集成是无缝的。
比JSP功能强。
支持
表6-1
读者也许会问,从上表不难得出,JSP可以完全替换servlet,在某些方面,还比servlet要强大,是不是无须再介绍servlet技术?
关于这个问题,这里不作探讨,在后面的章节中会详细讨论的。
实际上,在JSP技术出现之前,servlet完成了JSP的工作,它在某些方面(如界面生成)的表现的确不尽人意。
在目前主流的Web开发模式中,这二种技术,谁也代替不了谁,各自发挥自己的作用。
servlet技术体系中,用户创建的servlet是通过HttpServlet派生的,一般情况下,由于HttpServlet类拥有了B/S服务的功能,所以在没有特殊要求情况下,用户的servlet不必扩展自己的其它方法,只要对父类的某些方法(doGet和doPost方法等)进行重写以满足每个servlet特定的请求/响应要求即可。
对于HttpServlet,它的主要方法作以下所述。
其主要方法:
init()、destroy()、service()、doGet()、doPost()等。
init()方法:
在servlet的生命期中,仅执行一次init()方法。
它是在服务器装入servlet时执行的。
缺省的init()方法通常是符合要求的,但也可以用定制init()方法来覆盖它,典型的是管理服务器端资源。
例如,编写一个定制的init(),来完成只用于一次GIF图像装入。
destroy()方法:
destroy()方法仅执行一次,即在服务器卸装servlet时,执行该方法。
缺省的destroy()方法通常是符合要求的,但也可以覆盖它,典型的是管理服务器端资源。
例如,如果要servlet在运行时,统计累计数据;或者释放系统资源(如数据库连接资源等),则可以重写destroy()方法。
service()方法:
该方法是servlet的核心。
每当一个客户请求一个HttpServlet对象,该对象的service()方法就要被调用,而且系统把二个参数传递给这个方法,一个是请求(ServletRequest)对象,另一个是响应(ServletResponse)对象。
该方法的结构如下:
publicvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsjava.io.IOException,ServletException{
。
。
。
。
if(是get请求)doGet(request,response);
elseif(是post请求)doPost(request,response);
elseif(其它请求){…}
…..}
需要注意的是:
request和response内置对象是由容器自动生成。
以上三个方法,用户直接继承,不必重写(有特殊情况例外)。
而对于do方法(doGet()、doPost()等),用户必须重写的,以便于处理get或post等类型请求。
这是用户编写servlet程序的核心。
2、servlet的运行过程与生命周期
servlet没有main()方法,它们受控于另一个被称为容器的java应用程序。
Tomcat就是一个常用的servlet容器。
当Web服务器应用得到一个指向servlet的请求时,服务器不是把这个请求交给servlet本身,而是交给部署该servlet的容器,由容器向servlet提供Http请求和响应,而且要由容器调用servlet的方法。
所以要理解servlet的运行过程与生命周期,必须首先有理解容器的作用。
一般情况下,servlet容器具有以下功能(详细可以参照各容器的技术参考文档)。
●容器提供了各种方法,可以轻松地让servlet与Web服务器对话。
用户不用自己建立ServletSocket,监听某个端口,创建流等等。
只需要考虑如何在servlet中实现业务逻辑。
●容器控制着servlet的生命周期,它会负责加载、实例化和初始化servlet、调用servlet方法、以及销毁servlet实例。
●容器会自动地为它接受的每个servlet请求创建一个新的java线程,如果servlet已经运行完相应的Http服务方法,由容器结束该线程。
因此,容器支持多线程的管理。
●利用容器,可以使用XML部署描述文件来配置和修改安全性,而不必将其硬编码写到servlet类代码中。
●容器负责将一个JSP文件转译成一个servlet。
以上分析,不难发现,servlet的运行过程与生命周期实际上是容器来控制的。
假设容器为Tomcat,发生一个Http请求,这个请求可以是用户表单提交、点击一个链接等,以下详细描述其运行过程。
●Tomcat主线程对转发来用户的请求做出响应,并创建两个对象:
HttpServletRequest类的实例request和HttpServletResponse类的实例response。
●根据请求中的URL找到正确servlet(这个工作依据系统的配置文件),Tomcat为其创建或者分配一个线程(如果是第一次请求该servlet,或为创建,第二次及以后,则为分配),同时把创建的两个对象传递给该线程。
●Tomcat调用servlet的servic()方法,该方法根据请求参数的不同(请求类型的不同)调用doGet()、doPost()或者其它方法。
●执行do方法,生成静态页面,并把信息组合到响应对象里。
●servlet线程运行结束,Tomcat将响应对象转换为Http响应发回给客户,同时删除请求和响应对象。
由此可见,servlet的生命周期,包括加载和实例化、初始化、服务和销毁过程。
其中加载和实例化过程,只有一次(调用init()方法),这个过程,可能是Tomcat容器启动时执行,也可能是第一次访问该servlet执行,这主要取决于容器的配置文件。
服务过程(对每一次请求调用service()方法)是不受限的,每次服务过程就是一个servlet线程的运行过程。
当容器(Tomcat)关闭时,执行destroy()方法,销毁servlet实例。
但也可能由于servlet本身的变化,而提前执行,但servlet的生命周期不长于容器的生命周期。
6.1.3开发部署一个简单的servlet
开发部署一个servlet,并不难。
它主要由设计开发及部署二部分构成。
下面是名为SimpleServlet的servlet源代码。
它只有一个功能,在网页上显示“一个简单的servlet”。
SimpleServlet.java
packageservlet;
importjava.io.*;
importjavax.servlet.ServletException;
importjavax.servlet.http.*;
publicclassSimpleServletextendsHttpServlet{
publicSimpleServlet(){super();}
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
response.setContentType("text/html;charset=GB2312");
PrintWriterout=response.getWriter();
out.println("");
out.println("
ASimpleServlet");
out.println("
");
out.print("一个简单的servlet");
out.println("");
out.flush();
out.close();
}
publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{doGet(request,response);
}
}
正如上面代码所示,用户开发的servlet一般直接继承HttpServlet,构造函数是直接调用父类构造函数,也并不重写其它方法,一般只重写doGet()和doPost()方法。
如果这二种请求的响应一致,则doPost()方法的内容也很简单。
从上例,你会发现,在servlet完成客户端的静态部分(Html内容),采用out.println()方法直接输出而实现,这是servlet最糟糕的方面之一,这种做法很原始。
如果Html再复杂一点,不难想象其代码有多复杂。
用任意一个JavaIDE都可以完成一个servlet的编写和编译,当然本教材推荐eclipse或者MyEclipse。
用户编写完后,还需要部署到servlet容器(Tomcat)中,以便容器能管理用户的servlet,实现B/S服务。
一个JSP文件其实也同样,也需要部署到Tomcat的相应目录下。
部署过程有二种方法,如果用户使用Web集成开发环境IDE(如eclipse或MyEclipse)等,则在编写servlet过程中,IDE会自动帮助用户完成部署过程,这个过程实际上完成了二件事,即把servlet放到Tomcat指定的目录,并自动完成对web.xml文件的修改。
用户也可以自己动手,完成这二项工作。
部署工作的最关键部分是修改web.xml文件,该文件的主要作用是确定用户请求和特定的servlet的对应关系。
每个工程项目都有一个该文件,该文件的路径为:
Tomcat安装目录\webapps\工程项目名\WEB-INF下。
它缺省情形下,如下所示(以Tomcat6.X为例)。
xmlversion="1.0"encoding="UTF-8"?
>
xmlns:
xsi="http:
//www.w3.org/2001/XMLSchema-instance"
xsi:
schemaLocation="
index.jsp
若以手动为例,用户先把编译好的SimpleServlet.class文件放到Tomcat安装目录(如C:
\)\webapps\工程项目名\WEB-INF下\classes\servlet(包名)\下,然后,修改文件,代码如下。
xmlversion="1.0"encoding="UTF-8"?
>
xmlns:
xsi="http:
//www.w3.org/2001/XMLSchema-instance"
xsi:
schemaLocation="
index.jsp
SimpleServlet
servlet.SimpleServlet
SimpleServlet
/hello
缺省的web.xml有一个标签,用于欢迎页面设置(如果没有用到集成IDE,连这个元素也没有)。
需要用户增加的内容共有二个部分,第一个是元素,主要用来配置用户servlet与具体的servlet对象的关系;第二元素是,主要用来配置客户请求的URL与servlet对象的映射关系。
通过这样配置,当客户端浏览器发来/hello的请求时,Tomcat自动交由SimpleServlet进行处理,通过SimpleServlet就能找到相对应的serlet对象servlet.SimpleServlet,这也就是配置文件的意义所在。
启动Tomcat,启动浏览器,输入http:
//localhost:
8080/工程项目名/hello,页面显示:
“一个简单的servlet”。
6.2servlet体系的常用类和接口介绍
上一节,我们介绍了servlet技术特点。
为了全面了解servlet技术体系,本节将介绍该体系中的常用类和接口。
6.2.1常用类和接口
1、servlet实现相关
publicinterfaceServlet,这个接口是所有Servlet必须直接或间接实现的接口。
它定义了以下方法:
●init(ServletConfigconfig)方法用于初始化Servlet。
●destory()方法销毁Servlet。
●getServletInfo()方法获得Servlet的信息。
●getServletConfig()方法获得Servlet配置相关信息。
●service(ServletRequestreq,ServletResponseres)方法是应用程序运行的逻辑入口点。
publicabstractclassGenericServlet提供了对Servlet接口的基本实现。
它是一个抽象类。
它的service()方法是一个抽象的方法,GenericServlet的派生类必须直接或间接实现这个方法。
publicabstractclassHttpServlet类是针对使用HTTP协议的Web服务器的Servlet类。
HttpServlet类实现了抽象类GenericServlet的service()方法,在这个方法中,其功能是根据请求类型调用合适的do方法(以下所示)。
do方法的具体实现是由用户定义的servlet,根据特定的请求/响应情况作具体实现。
也就是说必须实现以下方法中的一个。
●doGet,如果Servlet支持HTTPGET请求,用于HTTPGET请求。
●doPost,如果Servlet支持HTTPPOST请求,用于HTTPPOST请求。
●其它do方法,用于HTTP其它方式请求。
图6-1servlet类、接口结构图
2、请求和响应相关及其它
publicinterfaceHttpServletRequest接口中最常用的方法就是获得请求中的参数,实际上,内置对象request就是实现该接口类的一个实例。
因此关于该接口的方法和功能在前章节中,以讲述清楚,这不再重复。
publicinterfaceHttpServletResponse接口代表了对客户端的HTTP响应,实际上,内置对象response就是实现该接口类的一个实例。
因此关于该接口的方法和功能在前章节中,以讲述清楚,这不再重复。
会话跟踪接口(HttpSeesion)、Servlet上下文接口(ServletContext)、等与HttpServletRequest接口类似,不再重复介绍。
但有一点需要读者注意,JSP与servlet中内置对象相似,但二者获取内置对象的方法略有不同,以下就二种技术作简单比较。
请求对象
响应对象
会话跟踪
上下文内容对象
JSP
request,容器产生,直接使用。
response,容器产生,直接使用。
session,容器产生,直接使用。
application,容器产生,直接使用。
servlet
同上
同上
HttpSeesionsession=request.getSeesion()
用getServletContext()方法获取。
表6-2
3、RequestDispatcher接口代表servlet协作,它可以把一个请求转发到另一个servlet或JSP。
该接口主要有二个方法:
forward(ServletRequest,ServletResponseresponse)把请求转发到服务器上的另一个资源。
include(ServletRequest,ServletResponseresponse)把服务器上的另一个资源包含到响应中。
RequestDispatcher接口的forward处理请求转发,在servlet中是一个很有用的功能,由于该种请求转发属于request范围,所以,应用程序往往用这种方法实现由servlet向JSP页面或另一servlet传输程序数据。
其核心代码如下。
…
request.setAttribute("key",任意对象数据);
RequestDispatcherdispatcher=null;
dispatcher=getServletContext().getRequestDispatcher("目的地JSP页面或另一servlet");
dispatcher.forward(request,response);
…
以上代码中,RequestDispatcher的实例化由上下文的.getRequestDispatcher方法实现,在目的地JSP页面或另一servlet中,用户程序可以用(类型转换)request.setAttribute("key")来获取传递的数据。
另外,需要注意的是,利用RequestDispatcher接口的forw