版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
9.1Servlet概述9.2Servlet的基本结构与成员方法9.3调用Servlet的多种方法9.4两种模式的JSP技术9.5Servlet模式的留言板案例9.6Servlet的会话跟踪习题9第9章Servlet随着动态网页技术的日益发展,1955年Sun公司首先将Java引入,并介绍了基于Java的小应用程序Applet,随后又在1996年推出了Servlet。JavaServlet的编程模式和CGI类似,但它的功能和性能要比CGI强大得多。Sun公司1999年6月推出的JSP技术,是基于JavaServlet以及整个Java体系的Web开发技术。Servlet技术为Web开发者提供了一种简便、可靠的机制来扩展Web服务器的功能和访问现有的事务系统,Servlet是快速、高效地开发Web动态网站的工具。JSP+Servlet技术使服务器端动态页面程序可以真正地做到跨平台,因此,这种技术得到了越来越多的支持和使用。这一章主要讲解Servlet的特点、工作原理及JSP+
Servlet的编程技术。
Servlet就是使用JavaServletAPI及相关类和软件包的Java程序。JavaApplet是运行在客户端(浏览器)的Java类,Servlet是运行在Web服务器上的Applet,主要用于处理Web请求,动态产生HTML页面。但是,Servlet没有运行界面,它与协议和平台无关,不受客户端的安全限制。Servlet为构建Web应用程序提供了一种基于组件的平台无关的方法,它可以使用所有的JavaAPI,包括可以访问企业级数据库的JDBCAPI,还可以访问特殊的HTTP库。Servlet具有所有Java语言的方便、可复用、安全性等优点。
9.1Servlet概述9.1.1Servlet的特点
Servlet具备Java跨平台的优点,它不受软硬件环境的限制,其特点如下:
(1)可移植性好。Servlet用Java编写。Servlet代码被编译成字节码后,字节码由WebServer中与平台有关的Java虚拟机(JVM)来解释。因此,Servlet本身由无平台的字节码组成,所以,Servlet无需任何实质上的改动即可移植到别的服务器上。几乎所有的主流服务器都直接或通过插件支持Servlet。
(2)高效。在传统的CGI中,客户机向服务器发出的每个请求都要生成一个新的进程。在Servlet中,每个请求将生成一个新的线程,而不是一个完整的进程。Servlet被调用时,它被载入驻留在内存中,直到更改Servlet,它才会被再次加载。
(3)功能强大。Servlet可以使用JavaAPI核心的所有功能,这些功能包括Web和URL访问、图像处理、数据压缩、多线程、JDBC、RMI、序列化对象等。
(4)方便。Servlet提供了大量的实用工具例程,例如自动地解析和解码HTML表单数据、读取和设置HTTP头、处理Cookie、跟踪会话状态等。
(5)可重用性。Servlet提供重用机制,可以给应用建立组件或用面向对象的方法封装共享功能。
(6)模块化。JSP、Servlet、JavaBean都提供把程序模块化的途径——把整个应用划分为许多离散的模块,各模块负责一项具体的任务,使程序便于理解。每一个Servlet可以执行一个特定的任务,Servlet之间可以相互交流。
(7)节省投资。不仅有许多廉价甚至免费的Web服务器可供个人或小规模网站使用,而且对于现有的服务器,如果它不支持Servlet的话,想要加上这部分功能也往往是免费的或只需要极少的投资。
(8)安全性。Servlet可以充分利用Java的安全机制,并且可以实现类型的安全性。9.1.2Servlet的工作原理
Servlet由支持Servlet的服务器Servlet引擎负责管理运行。引擎为每一个请求创建一个轻量级的线程并进行管理。Servlet的工作原理如图9.1所示,其工作步骤如下:
(1)浏览器向Web服务器发出请求。例如,使用浏览器按照HTTP协议键入一个URL地址,向Web服务器提出请求。
(2)
Web服务器响应请求后,把发给Servlet的请求,转交给Servlet引擎处理。
(3)
Servlet引擎检查对应的Servlet是否已装载,如果没有装载,则将其载入内存并初始化,然后由该Servlet对请求进行处理。如果Servlet中含有访问数据库的操作,则还要通过相关的JDBC驱动程序,与数据库相连,对数据库进行访问。
(4)
Servlet通过JDBC取回结果,生成HTML页面并将页面送回Web服务器。
(5)
Web服务器将页面发送回浏览器。最后Servlet将动态生成的标准HTML页面送给客户端浏览器。
图9.1Servlet的工作原理9.1.3Servlet的应用范围
Servlet的主要功能是处理Web请求,动态产生HTML页面。它的功能涉及范围很广,例如:
(1)创建并返回一个包含基于客户请求性质的、动态内容的、完整的HTML页面。
(2)创建可嵌入到现有HTML页面中的一部分HTML页面(HTML片段)。
(3)处理多个客户机的连接,接收多个客户机的输入,并将结果广播到多个客户机上。
(4)可以与其它服务器资源(包括数据库和基于Java的应用程序)进行通信,转交请求给其它的服务器和Servlet,按照任务类型或组织范围,允许在几个服务器中划分逻辑上的服务器。
(5)
Servlet开发人员可以定义彼此之间共同工作的激活代理,每个代理都是一个Servlet,代理者之间可以传送数据。9.1.4Servlet的生命周期
Servlet的生命周期分为装载Servlet、处理客户请求和结束Servlet三个阶段。
1.装载Servlet
在下列时刻服务器装载Servlet:
●如果配置了自动装载选项,则在启动Web服务器时自动装载Servlet。
●在Web服务器启动后客户端首次向Servlet发出请求时,自动装载Servlet。
●重新装载Servlet时自动装载Servlet。
所谓装载Servlet,实际上是用Web服务器创建一个Servlet对象,调用这个对象的init()方法完成必要的初始化工作。
2.处理客户请求
当Servlet初始化结束后,Servlet接收由服务器传来的用户请求,调用service()方法处理客户请求。
service()方法首先获得关于请求对象的信息,处理请求,访问其它资源,获得需要的信息。然后,service()方法使用响应对象的方法将响应传回Web服务器,Web服务器做相应处理后再将其传送至客户端。service()方法也可能激活其它方法(如doGet()、doPost()或用户自己开发的新的方法)以处理请求。
Servlet的响应有以下类型:
●一个输出流,浏览器根据它的内容类型(如TEXT/HTML)进行解释。
●一个HTTP错误响应,重定向到另一个URL、Servlet、JSP。
Servlet能够同时运行多个service()方法。对于每一个客户请求,Servlet都在它自己的线程中调用service()方法为用户服务。如此循环,但Servlet不再调用init()方法进行初始化,一般情况下只初始化一次。图9.2Servlet对客户端提供服务的过程
3.结束Servlet
当Web服务器要卸载Servlet或重新装入Servlet时,服务器会调用servlet的destroy()方法,将Servlet从内存中删除,否则它一直为客户服务。
总之,Servlet的生命周期如图9.2所示,开始于将它装载到Web服务器,结束于终止或重新装载Servlet。当Servlet被加载后,主要通过循环调用service()方法为用户服务。9.1.5init()、service()和destroy()方法
1. init()方法
Servlet第一次被请求加载时,服务器创建一个Servlet对象,这个对象调用init()方法完成必要的初始化工作。该方法在执行时,Servlet会把一个ServletConfig类型的对象传递给init()方法,这个对象就被保存在Servlet对象中,直到Servlet对象被销毁。
服务器只调用一次init()方法,以后的客户再请求Servlet服务时,Web服务器将启动一个线程,在该线程中,Servlet调用service()方法响应客户的请求,除非它要重载这个Servlet。在重载某个Servlet之前,服务器必须先调用destroy()方法卸载这个Servlet。缺省的init()方法设置了Servlet的初始化参数,并用它的ServletConfig对象参数来启动配置,所以,通常不必覆盖init()方法。但是,在个别情况下也可以用自己编写的init()方法来覆盖它。例如,可以编写一个init()方法用于一次装入GIF图像,也可以编写一个init()方法初始化数据库连接。同时需要注意,所有覆盖init()方法的Servlet应调用super.init()方法,以确保仍然执行这些任务。此外,在调用service()方法之前,应确保已完成了init()方法。
2. service()方法
service()方法是Servlet的核心。每当客户请求一个Servlet对象时,该对象的service()方法就被调用,而且传递给service()方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。service()方法根据请求的类型调用相应的服务功能,缺省的服务功能是调用与HTTP请求的方法相应的do功能。例如,当客户通过HTML表单发出一个HTTPGET请求时,则缺省情况下就调用doGet()方法;当客户发出的是一个HTTPPOST请求时,就调用doPost()方法。
Servlet应该为Servlet支持的HTTP方法覆盖do功能。因为HttpServlet.service()方法会检查请求方法是否调用了适当的处理方法。不必要覆盖service()方法,只需覆盖相应的do方法就可以了。
3. destroy()方法
destroy()方法仅执行一次,即在服务器停止且卸载Servlet时执行该方法。缺省的destroy()方法通常是符合要求的。也可以覆盖destroy()方法。例如,如果Servlet在运行时要累计统计数据,则可以编写一个destroy()方法,该方法用于在未装载Servlet时将统计数字保存在文件中,也可以编写一个destroy()方法关闭数据库连接等。
一个Servlet程序就是一个在Web服务器端运行的特殊Java类。Sun公司提供了javax.servlet和javax.servlet.http两个扩展包来开发Servlet。这两个包属于Java的标准扩展JavaServletAPI。
javax.servlet包提供了控制Servlet生命周期所必需的Servlet接口。
javax.servlet.http包提供了从Servlet接口派生出的专门用于处理HTTP请求的抽象类和一般的工具类。9.2Servlet的基本结构与成员方法9.2.1Servlet的基本层次结构
Servlet的基本层次结构如图9.3所示。
Servlet程序必须实现javax.servlet.Servlet接口。Servlet接口定义了Servlet容器与Servlet程序之间的通信协议。为了简化Servlet程序的编写,ServletAPI中也提供了一个实现Servlet接口的GenericServlet类,这个类实现了Servlet程序的基本特征和功能。ServletAPI中还提供了一个专用于HTTP协议的HttpServlet类。HttpServlet类是GenericServlet类的子类,在GenericServlet类的基础上进行了一些针对HTTP特点的扩充。因此,开发基于Servet类的应用必须继承GenericServlet类或HttpServlet类。为了充分利用HTTP协议的功能,一般情况下,都将自己编写的Servlet作为HttpServlet类的子类。而HttpServlet类是一个抽象类,开发者必须在自己定义的继承类中实现HttpServlet类的所有方法。图9.3Servlet接口和类的继承关系9.2.2HttpServlet类的成员方法
由于大多数Servlet是针对HTTP协议的Web服务器,所以,最通用的开发Servlet的方法是使用HttpServlet类。由于HttpServlet类是一个抽象类,可以从该类派生出一个类来实现HttpServlet,即将自己定义的类作为HttpServlet的子类。
Servlet被设计成请求驱动的。Servlet的请求可能包含多个数据项,当Web站点接收某个对Servlet的请求时(该请求来自访问此Web站点的客户端浏览器),它把这个请求封装成一个HttpServletRequest对象,然后把此对象传给Servlet的对应服务方法(doGet()、doPost())或高级的处理方法(doPut()、doTrace()、doDelete())进行处理。经这些方法中的某个方法处理后,将处理的响应结果返回Web站点,Web站点再将响应发送给客户端浏览器。因此,在开发者自己定义的HttpServlet的子类中,必须至少重载下列方法中的一种。
HttpServlet类中常用的成员方法如下。
(1)
protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;
被这个类的service()方法调用,用来处理一个HTTPGET操作。这个操作允许客户端简单地从HTTP服务器“获得”资源。对这个方法的重载将自动地支持HEAD方法。
当一个客户通过HTML表单发出一个HTTPGET请求或直接请求一个URL时,doGet()方法被调用。与GET请求相关的参数添加到URL的后面,并与这个请求一起发送。当不需修改服务器端的数据时,应该使用doGet()方法。
(2)
protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;
被这个类的service()方法调用,用来处理一个HTTPPOST操作。这个操作包含请求体的数据。当开发者要处理POST操作时,必须在HttpServlet的子类中重载这一方法。
当一个客户通过HTML表单发出一个HTTPPOST请求时,doPost()方法被调用。与POST请求相关的参数作为一个单独的HTTP请求从浏览器发送到服务器。当需要修改服务器端的数据时,应该使用doPost()方法。
(3)
protectedvoiddoHead(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;
被这个类的service()方法调用,用来处理一个HTTPHEAD操作。默认的情况是,这个操作会按照一个无条件的get方法来执行,该操作仅仅是返回包含内容长度的头信息。
(4)
protectedvoiddoDelete(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;
被这个类的service()方法调用,用来处理一个HTTPDELETE操作。这个操作允许客户端请求从服务器上删除URL。当开发者要处理DELETE请求时,必须重载这一方法。
(5)
protectedvoiddoOptions(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;
被这个类的service()方法调用,用来处理一个HTTPOPTION操作。这个操作自动地决定支持哪一种HTTP方法。
(6)
protectedvoiddoPut(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;
被这个类的service()方法调用,用来处理一个HTTPPUT操作。这个操作类似于通过FTP发送文件。当要处理PUT操作时,必须在HttpServlet的子类中重载这一方法。
(7)
protectedvoiddoTrace(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;
被这个类的service()方法调用,用来处理一个HTTPTRACE操作。这个操作的默认执行结果是产生一个响应,这个响应包含一个反映TRACE请求中发送的所有头域的信息。当开发Servlet时,在多数情况下需要重载这个方法。
(8)
protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;
publicvoidservice(ServletRequestrequest,ServletResponseresponse)throwsServletException,IOException;
service()方法是Servlet的核心,它是一个Servlet的HTTP-specific方案,负责把请求分配给支持这个请求的其它方法。每当客户请求一个HttpServlet对象时,该对象的service()方法就被调用,而且传递给该方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在service()方法。缺省的服务功能是调用与HTTP请求的方法相应的do功能。例如,如果HTTP请求的方法为get,则缺省情况下就调用doGet()。Servlet应该为Servlet支持的HTTP方法覆盖do功能。因为HttpServlet.service()方法会检查请求方法是否调用了适当的处理方法。
在开发Servlet时,大多数情况下不必重载service()方法,只需覆盖相应的do方法就可以了。9.2.3在Eclipse中建立Servlet
下面我们使用Eclipse开发平台,建立一个简单的Servlet,以说明如何开发Servlet。
在Eclipse建立、编译、运行Servlet程序(C9_1.java程序)的步骤与第3章所述建立JSP程序的步骤基本相同。当建立了ch9项目(文件夹)后,存放C9_1.java程序,操作过程如图9.4所示。
在“ch9”文件夹下单击右键,依次单击“新建”/“servlet”,弹出如图9.5所示的“创建servlet”对话框。图9.4新建Servlet图
图9.5“创建servlet”对话框在图9.5中输入类名C9_1,然后单击“下一步”,弹出编辑界面,在其中输入程序。图9.6是在编辑界面中输入程序后的状态。
【示例程序C9_1.java】在浏览器上输出“ThefirstServlet程序”。
importjava.io.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassC9_1extendsHttpServlet
{ publicvoidinit(ServletConfigcfig)throwsServletException
图9.6在“创建servlet”对话框的编辑界面中输入程序后的显示
{super.init(cfig);}
//重写service方法
publicvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException
{ response.setContentType("text/html;charset=GB2312");//设置响应的MIME类型
PrintWriterout=response.getWriter();//获得向客户发送数据的输出流 out.println("<HTML><HEAD></HEAD><BODY>");
out.println("<H1ALIGN=CENTER><B>ThefirstServlet程序</H1><BR>");
out.println("</BODY></HTML>");
}
}
在图9.6中输入程序后,启动运行C9_1.java,最终的结果如图9.7所示。
图9.7C9_1的运行结果程序说明:
(1)基于HTTP协议的Servlet必须导入javax.servlet和javax.servlet.http包。
(2)当客户向Servlet发送一个请求时,经过init()方法初始化后,Servlet调用service()方法来对客户端(client)发出的各个请求进行响应。它接受ServletRequest和ServletResponse两个对象。Servlet从HttpServletRequest对象中取出输入数据流,完成相应的操作;Servlet通过HttpServletResponse对象的getWriter()方法来获得输出流,将Servlet的响应数据返回给客户。
(3)
HttpServletResponse必须知道输出流的格式才能输出,因此,要使用setContentType()方法来设置输出流的格式。
生成一个Servlet后,可通过多种方法来调用它。常用的方法是下面四种之一:
●在浏览器的URL地址栏中直接指定。
●在HTML表单中通过<FORM>标记的ACTION属性指定。
●使用服务器包含文件,即在HTML文件中使用<SERVLET>和</SERVLET>标记。
●在JSP页面中调用Servlet。
下面将逐一介绍。9.3调用Servlet的多种方法9.3.1在URL中直接调用Servlet
【示例程序C9_2.java】在URL中调用Servlet,在浏览器上输出客户端的部分信息。
importjava.io.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassC9_2extendsHttpServlet
{ //重写doPost方法
publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)
throwsServletException,IOException
{ res.setContentType("text/html;charset=GB2312");//设置响应的MIME类型
PrintWriterout=res.getWriter();//获得向客户发送数据的输出流
out.println("<HTML><HEAD></HEAD><BODY>");
out.println("<H3>输出客户端的信息</H3><BR>");
out.println("Method:"+req.getMethod()+"<BR>");//获取请求的方法
out.println("RequestURL:"+req.getRequestURL()+"<BR>");//获得请求URL
out.println("Protocol:"+req.getProtocol()+"<BR>");//获得该对象的协议
out.println("RemoteAddress:"+req.getRemoteAddr()+"<BR>");//获取客户端IP地址
out.println("</BODY></HTML>");
}
//重写doGet方法
publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres)
throwsServletException,IOException
图9.8C9_2的运行结果
{ doPost(req,res); }
}
该示例程序的运行结果如图9.8所示。
程序说明:
(1)
C9_2是HttpServlet的子类,HttpServlet是GenericServlet的一个子类,通过GenericServlet实现了Servlet界面。
(2)当service()方法缺省时,则调用与HTTP请求方法相应的do功能。根据接收的HTTP请求类型,分别调用doGet()、doPost()等方法。
(3)
doGet()、doPost()方法的参数HttpServletRequest对象包含了客户端请求的信息,可以通过该参数取得客户端的一些信息(例如IP地址等)以及HTTP请求类型(例如GET、HEAD、POST、PUT等),生成HTTP响应;最后通过参数HttpServletResponse对象返回响应信息,完成Servlet与客户端的交互。该程序中编写了doPost()和doGet()两个方法,并且在doGet()方法中调用了Servlet的doPost()方法,用于HTML请求。9.3.2在<FORM>标记中访问Servlet
在HTML表单中通过<FORM>标记的ACTION属性调用Servlet需要编写两个文件:一个是如c9_3.html所示的Web界面;另一个是如程序C9_3.java所示的Servlet。本例通过c9_3.html界面输入信息,用户的输入信息提交给Servlet程序(C9_3.java)处理,并将处理结果输出到用户界面上。
【示例程序c9_3.html】在<FORM>标记中调用Servlet。
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">
<HTML><HEAD>
<metahttp-equiv="Content-Type"content="text/html;charset=GB2312">
<TITLE>在〈FORM〉标记中调用Servlet</TITLE>
</HEAD><BODY>
<CENTER>在〈FORM〉标记中调用Servlet</CENTER><HR>
<FORMMETHOD="post"ACTION="C9_3">
<P>姓名:<INPUTTYPE="name"name="myname"size=25maxlength="30"></P>
<P>爱好:<INPUTTYPE="text"name="love"size=30maxlength="30"></P>
<INPUTTYPE="submit"VALUE="确定">
<INPUTTYPE="reset"VALUE="清除">
</FORM>
</BODY></HTML>
【示例程序C9_3.java】<FORM>标记中调用的Servlet程序。
importjava.io.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassC9_3extendsHttpServlet
{ //重写doPost方法
publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)throwsServletException,IOException
{ res.setContentType("text/html;charset=GB2312");//设置响应的MIME类型
PrintWriterout=res.getWriter();//获得向客户发送数据的输出流
byteb1[]=req.getParameter("myname").getBytes("ISO-8859-1");//获得客户端提交的参数
Strings1=newString(b1);
byteb2[]=req.getParameter("love").getBytes("ISO-8859-1");//获得客户端提交的参数
Strings2=newString(b2);
out.println("<HTML><HEAD></HEAD><BODY>");
out.println("<H3>输出客户端的信息</H3><BR>");
out.println("姓名:"+s1+"<BR>");//获得请求URL
out.println("爱好:"+s2+"<BR>");//获得请求URL
out.println("</BODY></HTML>");
}
//重写doGet方法
publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres) throwsServletException,IOException
{ doPost(req,res); }
}
该示例程序的运行结果如图9.9和图9.10所示。
图9.9在表单界面c9_3.html上输入数据
图9.10Servlet的运行结果9.3.3利用超链接访问Servlet
【示例程序c9_4.html】在HTML页面中利用超链接访问Servlet。
<HTML><HEAD><TITLE>超链接访问Servlet</TITLE></HEAD>
<BODY>
<CENTER>
在HTML页面中利用超链接访问Servlet
</CENTER>
<HR>
<H3>
<AHREF="C9_1">加载servlet(C9_1)</A>
</H3>
</BODY>
</HTML>
c9_4.html的运行结果如图9.11所示,单击超链接后的运行结果见图9.7所示。
图9.11c9_4.html的运行结果9.3.4在JSP文件中调用Servlet
JSP和Servlet是两种极具特色的动态Web技术,如果撇开底层运行机制上的共同之处(JSP被翻译成Servlet再执行),单从开发人员的角度来看,完全可以单独采用其中一种技术实现一个动态Web应用。由于Servlet输出HTML时采用CGI的方式,是一句一句输出的,所以,编写和修改HTML文件非常不方便。而JSP把Java代码嵌套到HTML语句中,大大简化和方便了网页的设计和维护。因此,在开发Web应用实践中,主要是整合这两种技术,实现两种技术的优势互补。在整合技术中,表示层的工作由JSP技术承担,注重页面的表现,编写输出HTML网页的程序;业务逻辑层的工作由Servlet承担,注重业务逻辑的实现,编写完成诸如数据计算、数据分析、数据库连接等操作处理的程序。在JSP文件中访问Servlet所采用的格式与HTML页面中调用Servlet的方法完全一样,而且原理也完全相同。只不过这时访问Servlet的是动态的JSP文件,而不是静态的HTML页面。显然,在JSP文件中访问Servlet也需要编写两个程序,即一个JSP程序和一个Servlet程序。本例中的c9_5.jsp程序是一个Web登录页面,在文本框中输入用户名和密码,单击“登录”按钮后,则把输入的信息提交给<FORM>标记中调用的Servlet。程序C9_5.java是<FORM>标记中调用的Servlet,它接收用户输入的信息并将处理结果输出到用户界面上。
在Eclipse中建立JSP+Servlet程序(c9_5.jsp,C9_5.java)的存储位置如图9.12所示。
图9.12JSP+Servlet的存储位置
【示例程序c9_5.jsp】编写一个调用Servlet的登录页面程序。
<%@pagecontentType="text/html;charset=GBK"%>
<HTML><HEAD><TITLE>在JSP中调用Servlet</TITLE></HEAD>
<BODY>
<CENTER>用户登录Servlet</CENTER><HR>
<FORMMETHOD="post"ACTION="C9_5">
<P>用户名:<INPUTTYPE="name"name="myname"size=25></P>
<P>密码:<INPUTTYPE="password"name="pass"></P>
<INPUTTYPE="submit"VALUE="确定">
<INPUTTYPE="reset"VALUE="清除">
</FORM>
</BODY></HTML>
【示例程序C9_5.java】测试登录密码,将处理结果输出到页面上。
importjava.io.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassC9_5extendsHttpServlet
{ //重写doPost方法
publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)throwsServletException,IOException
{ res.setContentType("text/html;charset=GB2312");//设置响应的MIME类型
PrintWriterout=res.getWriter(); //获得向客户发送数据的输出流
byteb1[]=req.getParameter("myname").getBytes("ISO-8859-1");
//获得客户端提交的用户名
//参数
Strings1=newString(b1);
Strings2=req.getParameter("pass"); //获得客户端提交的密码参数
out.println("<HTML><HEAD></HEAD><BODY>");
out.println("<H3>输出客户端的信息</H3><BR>");
if(s2.equals("abc"))//密码为“abc”
{out.println("用户名:"+s1+"<BR>");
out.println("登录成功!<BR>");
}
else
{
out.print("<PALIGN="+"CENTER"+">");
out.println("<AHREF="+"c9_5.jsp"+">密码写错重新输入</A></P>");
}
out.println("</BODY></HTML>");
}
//重写doGet方法
publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres) throwsServletException,IOException
{
doPost(req,res);
}
}
该示例程序的运行结果如图9.13和图9.14所示。
图9.13c9_5.jsp的运行结果
图9.14Servlet的运行结果
运用JSP/Servlet技术实现Web动态交互,主要采用模型Ⅰ(JSP+JavaBean)和模型Ⅱ(JSP+Servlet+JavaBean)。本节分别介绍这两种模型,并比较两种模型的优缺点。
9.4两种模式的JSP技术9.4.1JSP+JavaBean
模型Ⅰ的体系结构如图9.15所示,称之为JSP+JavaBean模型。其工作原理是:当浏览器发出请求时,JSP接收请求访问JavaBean。若需要访问数据库或后端服务器时,则通过JavaBean连接数据库或后端服务器,进行相应的处理。JavaBean将处理的结果数据提交给JSP。JSP提取结果并重新组织后,动态产生HTML页面,返回给浏览器。用户从显示的页面中得到交互的结果。
图9.15JSP+JavaBean模型模型Ⅰ充分利用了JSP技术易于开发动态网页的特点,页面显示层的任务由JSP承担(但它也含有事务逻辑层的内容),JavaBean主要负责事务逻辑层和数据层的工作。JSP+JavaBean模型依靠一个或几个JavaBean组件实现具体的应用功能,生成动态内容,其最大的特点是简单。9.4.2JSP+Servlet+JavaBean
模型Ⅱ的体系结构如图9.16所示,称之为JSP+Servlet+JavaBean模型。它是一种采用基于模型视图控制器(Model-View-Controller)的设计模型,即MVC模型。该模型将JSP程序的功能分为三个层次:Model(模型)层、View(视图)层和Controller(控制层)。Model层用来实现业务逻辑,包含了Web应用程序功能的核心,负责存储与应用程序相关的数据;View层用于用户界面的显示,它可以访问模型的数据,但不能改变这些数据;Controller层主要负责View层和Model层之间的控制关系。具体实现时,JavaBean作为模型层,Servlet作为控制层,JSP作为视图层。每层的作用如下:
(1)
JavaBean作为Model层,实现各个具体的应用逻辑和功能。
(2)
Servlet作为Controller层负责处理HTTP请求,包括:
①对输入数据的检查和转换。
②通过JavaBean访问数据库。
③初始化JSP中要用到的JavaBean或对象。
④根据处理中不同分支和执行的结果(如成功或失败),决定转向哪个JSP等。
(3)
JSP作为用户界面程序(View),负责生成交互后返回的页面。它主要通过信息共享,获取Servlet生成的对象或JavaBean,从中取出相关数据,插入到HTML页面中。
该模型的工作原理是:所有的请求都被发送给作为控制器的Servlet。Servlet接受请求,并根据请求信息将它们分发给适当的JSP来响应;同时Servlet还根据JSP的需求生成JavaBean的对象并输出给JSP环境。JSP可以通过直接调用方法或使用UseBean的自定义标签得到JavaBean中的数据。
这种设计模型通过JSP和Servlet的合作来实现交互处理,很好地实现了表示层、事务逻辑层和数据层的分离。
图9.16JSP+Servlet+JavaBean模型9.4.3两种模式的比较
从以上对两种模型的陈述可以看出,模型Ⅰ和模型Ⅱ的整体结构都比较清晰,易于实现。它们的基本思想都是实现表示层、事务逻辑层和数据层的分离。这样的分层设计便于系统的维护和修改。两种模型的主要区别在于:
(1)处理流程的主控部分不同。模型Ⅰ利用JSP作为主控部分,将用户的请求、JavaBean和响应有效地衔接起来。模型Ⅱ利用Servlet作为主控部分,将用户的请求、JavaBean、JSP和响应有效地衔接起来。
(2)实现表示层、事务逻辑层和数据层的分离的程度不同。模型Ⅱ比模型Ⅰ有更彻底的分离效果。当事务逻辑比较复杂、分支较多或者需要涉及多个JavaBean组件时,模型Ⅰ常常会导致JSP文件中嵌入大量的脚本或者Java代码。特别是在大型项目开发中,由于页面设计与逻辑处理分别由不同的专业人员承担,如果JSP有相当一部分处理逻辑和页面描述被混在一起,这就有可能引起分工不清,不利于两个部分的独立开发和维护,影响项目的施工和管理。在模型Ⅱ中,由Servlet处理HTTP请求,JavaBean承担事务逻辑处理,JSP仅负责生成网页的工作,所以,出现层的混合问题比较轻,适合于不同专长的专业人员独立开发Web项目中的各层功能。
(3)适用于动态交互处理的需求不同。当事务逻辑比较复杂、分支较多或者需要涉及多个JavaBean组件时,由于模型Ⅱ比模型Ⅰ具有更清晰的页面表现,更明确的开发模块的划分,所以使用模型Ⅱ比较适合。然而,模型Ⅱ需要编写Servlet程序,Servlet程序需要的工具是Java集成开发环境,编程工作量比较大。而对于简单的交互处理,利用模型Ⅰ,JSP主要是使用HTML工具开发,然后再插入少量的编程代码就可以实现动态交互。在这种情况下,使用模型Ⅰ更为方便快捷。模型Ⅰ与模型Ⅱ这两种用于开发Web应用的方法都有很好的实用性。当然,实现动态交互的Web应用,不限于这两种模型。在实际开发Web应用的过程中,要根据系统的特点、客户需求及处理逻辑的特性,选择合适的模型,力求使整个应用的体系结构更趋合理,从而实现不同的交互处理。
在第8章我们已经提供了一个用JSP+JavaBean开发的留言板案例,这一节我们仍然利用第8章的案例,开发一个JSP+Servlet+JavaBean的留言板,其目的是通过使用两种不同的模型来比较它们之间的区别。9.5Servlet模式的留言板案例
JSP+Servlet+JavaBean的留言板的界面如图9.17所示,它与图8.16完全相同。用户需要输入留言的标题、留言人的姓名、留言人的E-mail和留言内容。点击“提交留言”按钮后,要将留言人输入的信息保存到数据库。因此,我们建立一个Message数据库,并建立一个MessageTable表来存放留言人输入的信息。MessageTable表的结构与表8.2也完全相同。系统设计如下。
图9.17Messgages.html用户界面在Eclipse开发环境中,JSP+Servlet+JavaBean模型留言板的所有程序(Messgages.html、AddMessageServlet.java、ViewMessages_servlet.java、MessageDataBean.java和viewMessages.jsp)的存储位置如图9.18所示。
图9.18留言板程序的所有存储位置9.5.1填写留言的界面
填写留言界面的示例程序为Messgages.html,它的执行效果如图9.17所示。该程序与第8章提供的留言界面的示例程序Messgages.html基本相同,只需要修改form中的action的内容与“查看留言”的超链接。点击留言界面的“提交留言”按钮,使用Servlet(AddMessageServlet)接收HTTP请求。
【示例程序Messgages.html】填写留言的界面程序。
<!--Messgages.html-->
<HTML><HEAD>
<TITLE>留言板</TITLE></HEAD>
<BODY><CENTER>留言板</CENTER>
<FORMACTION="AddMessageServlet">
<TABLEborder=1ALIGN="CENTER">
<TR>
<TD>姓名:</TD>
<TD><INPUTTYPE="text"name="name"size=25></TD>
</TR>
<TR><TD>E-mail:</TD><TD><INPUTTYPE="text"name="email"size=25></TD></TR>
<TR><TD>主题:</TD><TD><INPUTTYPE="text"name="title"size=25></TD></TR>
<TR><TD>留言:</TD><TD><textareaname="content"rows=7cols=25></textarea></TD></TR>
<TR>
<TDcolspan=3>
<TABLEALIGN="CENTER"width="100%"cellspacing="0"cellpadding="0"></TD>
<TR>
<TDALIGN="CENTER"><INPUTTYPE="submit"VALUE="提交留言"></TD>
<TDALIGN="CENTER"><AHREF="ViewMessages_servlet">
<FORTsize=2>查看留言</FORT></A></TD>
<TDALIGN="CENTER"><INPUTTYPE="reset"VALUE="重新填写"></TD>
</TR>
</TABLE></TD>
</TR></TABLE>
</FORM>
</BODY></HTML>9.5.2接受请求保存留言的Servlet
该Servlet(AddMessageServlet)作为控制器,完成如下工作:
(1)接受浏览器发送的所有请求。
(2)建立与数据库的连接。
(3)将留言板中需要存入数据库的信息存入数据库。
(4)对于留言板中“查看留言”的请求,它通过访问另一个Servlet(ViewMessages_servlet)响应用户的请求。
【示例程序AddMessageServlet.java】保存留言的Servlet程序。
packagemessage;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjava.sql.*;
importjava.io.*;
publicclassAddMessageServletextendsjavax.servlet.http.HttpServletimplementsjavax.servlet.Servlet
{//建立数据库的连接
publicAddMessageServlet(){
StringJDriver="sun.jdbc.odbc.JdbcOdbcDriver"; //声明JDBC驱动程序对象
StringconURL="jdbc:odbc:message"; //定义JDBC的URL对象
try{
Class.forName(JDriver); //加载JDBC-ODBC桥驱动程序
con=DriverManager.getConnection(conURL); //连接数据库URL
}
catch(Exceptione)
{System.err.println(e.getMessage());}
}
privateConnectioncon;
/*接收GET请求*/
protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException
{
byteb1[]=request.getParameter("name").getBytes("ISO-8859-1");
Stringna=newString(b1);
byteb2[]=request.getParameter("email").getBytes("ISO-8859-1");
Stringem=newString(b2);
byteb3[]=request.getParameter("title").getBytes("ISO-8859-1");
Stringti=newString(b3);
byteb4[]=request.getParameter("content").getBytes("ISO-8859-1");
Stringco=newString(b4);
if(na==null)na="";
if(ti==null)ti="";
if(co==null)co="";
if(em==null)em="";
try
{//将获得的留言信息装入数据库
PreparedStatementstm=con.prepareStatement("insertintoMessageTablevalues(?,?,?,?)");
stm.setString(1,ti);
stm.setString(2,na);
if(em.length()==0)stm.setString(3,null);
elsestm.setString(3,em);
stm.setString(4,co);
try{ stm.executeQuery(); }
catch(Exceptione){ }
//对留言板中“查看留言”的请求,服务器端重定向给另一个Servlet来控制
RequestDispatcherrequestDispatcher=request.getRequestDispatcher("ViewMessages_servlet");
requestDispatcher.forward(request,response);
}
catch(Exceptione){e.printStackTrace();}
}
/*接收POST请求*/
protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException
{doGet(request,response);}
}程序说明:
requestDispatcher=request.getRequestDispatcher
("ViewMessages_servlet")语句表示生成一个RequestDispatcher类的对象,并将第一个Servlet的控制权转交给第二个Servlet(ViewMessages_servlet)。requestDispatcher.forward(request,response)语句表示服务器端的重定向方式。
RequestDispatcher是一个Web资源的包装器,可以用来把当前的request传递到该资源,或者把新的资源包括到当前响应中。RequestDispatcher的forward()方法将当前的request和response重定向到该RequestDispacher指定的资源,它只在服务器端起作用。使用forward()方法时,Servletengine传递HTTP请求从当前的Servlet或JSP到另外一个Servlet、JSP或普通的HTML文件。因为完成一个逻辑操作往往需要跨越多个步骤,每一步骤完成相应的处理后转向到下一个步骤,所以,这种方式在实际项目中大量使用。使用时应该注意,只有在尚未向客户端输出响应时才可以调用forward()方法;调用forward()方法时,如果页面缓存不为空,则在转向前将自动清除缓存,否则将抛出一个IllegalStateException异常。9.5.3查看留言的Servlet
该Servlet作为控制器,完成如下工作:
(1)接受AddMessageServlet请求。
(2)建立与数据库的连接。
(3)从数据库中读取存入留言板的信息。这些信息正是留言板界面中“查看留言”按钮所提供的信息。
(4)将留言信息提交给JavaBean(MessageDataBean),再由JavaBean对象保留到Collection对象中。具体内容见下面“表示留言板数据的JavaBean”。
(5)把Collection对象保存到request中,然后访问显示留言的JSP(viewMessages.jsp)页面。
【示例程序ViewMessages_servlet.java】实现“查看留言”请求的Servlet。
packagemessage;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjava.sql.*;
importjava.util.ArrayList;
importjava.util.Collection;
importjava.io.*;
publicclassViewMessages_servletextendsjavax.servlet.http.HttpServletimplementsjavax.servlet.Servlet
{ //连接数据库
publicViewMessages_servlet()
{
StringJDriver="sun.jdbc.odbc.JdbcOdbcDriver"; //声明JDBC驱动程序对象
StringconURL="jdbc:odbc:message"; //定义JDBC的URL对象
try{
Class.forName(JDriver); //加载JDBC-ODBC桥驱动程序
con=DriverManager.getConnection(conURL); //连接数据库URL
}
catch(Exceptione)
{System.err.println(e.getMessage());}
}
privateConnectioncon;
//得到GET请求,从数据库中读出留言信息
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsIOException,ServletException
{
Collectionret=newArrayList();
try
{
Statementstm=con.createStatement();
ResultSetresult=stm.executeQuery("selectcount(*)fromMessageTable"); intmessage_count=0;
if(result.next())
{
message_count=result.getInt(1);
result.close();
}
if(message_count>0)
{
result=stm.executeQuery("select*fromMessageTable");
while(result.next())
{
Stringtitle=result.getString("title");
Stringname=result.getString("name");
Stringemail=result.getString("email");
Stringcontent=result.getString("co
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024关于商品房的租房合同范本
- 汽车租赁合同范本参考
- 部编版八年级历史上册第26课《教育文化事业的发展》课时优化练习
- 13《纪念白求恩》公开课一等奖创新教学设计
- 胶囊在食品工业中的应用
- 2024车辆买卖协议,公司名下车辆转让合同书
- 人工智能驱动的金融科技变革
- 2024年有关童装特许加盟合同模板
- 后疫情时代线上汽车销售的发展趋势
- 光伏电站运营成本优化与收益提升
- 拆除台阶施工方案
- 2023年河南省普通高校专升本公共英语真题(试卷+答案)
- 领导班子议事制度
- 2023年10月自考00534外国文学作品选试题及答案含评分标准
- 2021中国Castleman病诊断与治疗专家共识
- 二级糖尿病医院基本标准
- 克服厌学情绪 班会教学设计
- 复合锂基润滑脂和脲基润滑脂成脂机理的对比研究
- 搪玻璃反应釜维护检修规程2016
- 面试问题大全及答案100则
- 河北省保定市顺平县2023-2024学年七年级上学期期中语文试题
评论
0/150
提交评论