您当前的位置: 首页 > 网站编程 > JSP教程 > Java Servlet 技术

Java Servlet 技术

作者:guanchaofeng 来源:本站整理 发布时间: 2009-11-02 09:35 点击:
JavaServlet技术 StephanieBodoff 当Web刚开始被用来传送服务时,服务提供者就已经意识到了动态内容的需要。Applet是为了实现这个目标的一种最早的尝试,它主要关注使用客户端平台来交付动态用户体验。与此同时,开发人员也在研究如何使用服务器平台实现这个

Java Servlet 技术

  JavaServlet技术
  StephanieBodoff
  
  当Web刚开始被用来传送服务时,服务提供者就已经意识到了动态内容的需要。Applet是为了实现这个目标的一种最早的尝试,它主要关注使用客户端平台来交付动态用户体验。与此同时,开发人员也在研究如何使用服务器平台实现这个目标。开始的时候,公共网关接口(CommonGatewayInterface,CGI)脚本是生成动态内容的主要技术。虽然使用得非常广泛,但CGI脚本技术有很多的缺陷,这包括平台相关性和缺乏可扩展性。为了避免这些局限性,JavaServlet技术因应而生,它能够以一种可移植的方法来提供动态的、面向用户的内容。
  
  什么是Servlet?
  一个servlet就是Java编程语言中的一个类,它被用来扩展服务器的性能,服务器上驻留着可以通过“请求-响应”编程模型来访问的应用程序。虽然servlet可以对任何类型的请求产生响应,但通常只用来扩展Web服务器的应用程序。JavaServlet技术为这些应用程序定义了一个特定于HTTP的servlet类。
  
  javax.servlet和javax.servlet.http包为编写servlet提供了接口和类。所有的servlet都必须实现Servlet接口,该接口定义了生命周期方法。
  
  当实现一个通用的服务时,您可以使用或扩展由JavaServletAPI提供的GenericServlet类。HttpServlet类提供了一些方法,诸如doGet和doPost,以用于处理特定于HTTP的服务。
  
  本章主要讲述如何编写对HTTP请求产生响应的servlet。这里假设您已经了解了一些HTTP协议的基础知识。如果对这些协议不熟悉的话,您可以从HTTP概述中对HTTP协议有一个初步的了解。
  
  Servlet示例
  本章使用Duke'sBookstore应用程序来说明与servlet编程相关的任务。表14-1列出了解决每个书店功能的servlet。每个编程任务用一个或多个servlet来说明。例如,BookDetailsServlet说明如何处理HTTPGET请求,BookDetailsServlet和CatalogServlet显示如何构建响应,而CatalogServlet则说明如何跟踪会话信息。
  
  表14-1Duke'sBookstoreServlet例子
  
  功能
  Servlet
  
  进入书店
  BookStoreServlet
  
  创建书店标识
  BannerServlet
  
  浏览书店的目录
  CatalogServlet
  
  将书放入购物车
  CatalogServlet,
  
  BookDetailsServlet
  
  获取关于特定的某本书的一些详细信息
  BookDetailsServlet
  
  显示购物车
  ShowCartServlet
  
  从购物车中移除一本或多本书
  ShowCartServlet
  
  购买购物车中的书
  CashierServlet
  
  获得对购买的确认
  ReceiptServlet
  
  
  这些书店应用程序的数据保存在数据库中,并通过帮助类database.BookDB进行存储。database包也包括BookDetails类,一个BookDetails类用来代表一种书。购物车和购物车项用cart.ShoppingCart和cart.ShoppingCartItem来分别表示。
  
  书店应用程序的源代码放在<JWSDP_HOME>/docs/tutorial/examples/web/bookstore1目录中,这个目录是在对指南包进行解压缩时创建的。
  
  要构建、安装和运行这个实例,需完成以下步骤:
  
  1.在终端窗口中,转到<JWSDP_HOME>/docs/tutorial/examples/web/bookstore1。
  
  2.运行build。build目标将产生任何必要的编码并且将文件直接拷贝到<JWSDP_HOME>/docs/tutorial/examples/web/bookstore1/build。
  
  3.确认Tomcat已经开始执行。
  
  4.运行antinstall。install目标通知Tomcat已经有了新的上下文。
  
  5.启动PointBase公司的数据库服务器,并且在没完全准备好的情况下仍然指向数据库(见从Web应用中访问数据库)。.
  
  6.打开书店的URLhttp://localhost:8080/bookstore1/enter以运行该应用程序。
  
  要部署该应用程序,要完成以下步骤:
  
  1.运行antpackage。这个包任务是创建一个WAR文件,该文件包含WEB-INF/classes中的应用程序类和META-INF中的context.xml文件。
  
  2.确认Tomcat已经开始执行。
  
  3.运行antdeploy。Deploy目标将WAR拷贝到Tomcat,并且通知已经有了新的上下文。
  
  故障排除
  一般的问题和其解决方案列举了Web客户端为什么会失败的一些原因。另外,Duke书店返回了以下异常:
  
  ·BookNotFoundException——如果一本书不能在书店的数据库中找到,则返回该异常。如果用户没有运行antcreate-book-db来加载书店数据库中的数据、或没有运行数据库服务器、或数据库已经崩溃,这些都将产生该异常。
  
  ·BooksNotFoundException——如果书店的数据不能被获取,则返回该异常。如果用户没有运行antcreate-book-db来加载书店数据库中的数据、或没有运行数据库服务器、或数据库已经崩溃,这些都将产生该异常。
  
  ·UnavailableException——如果servlet不能获取到用来表示书店的Web上下文属性,则返回该异常。如果您没有拷贝指向(PointBase)的客户端库<PB_HOME>/lib/pbclient45.jarto<JWSDP_HOME>/common/lib、或者如果指向的(PiontBase)服务器没有运行、或用户没有定义Tomcat中用来引用指向数据库(PointBase)的数据源,这都将产生该异常。
  
  因为指定了一个错误页,用户将看到这样的一个消息Theapplicationisunavailable.Pleasetrylater.如果指定了一个正确页,Web容器将产生一个包含AServletExceptionHasOccurred消息的默认页和一个用来帮助诊断异常产生原因的栈。如果使用errorpage.html,用户可以了解Web容器决定异常产生原因的日志。Web日志位于<JWSDP_HOME>/logs目录中,由jwsdp_log.<date>.txt来命名。
  
  Servlet的生命周期
  一个servlet的生命周期由部署servlet的容器来控制。当一个请求映射到一个servlet时,该容器执行下列步骤。
  
  1.如果一个servlet的实例并不存在,Web容器
  
  a.加载servlet类。
  
  b.创建一个servlet类的实例。
  
  c.调用init初始化servlet实例。该初始化过程将在初始化servlet中讲述。
  
  2.调用service方法,传递一个请求和响应对象。服务方法将在编写服务方法中讲述。
  
  如果该容器要移除这个servlet,可调用servlet的destroy方法来结束该servlet。结束过程将在结束Serlvet中讨论。
  
  处理Servlet生命周期事件
  在servlet的生命周期中,用户可以通过定义监听器对象对事件进行检测和产生反应。当生命周期事件发生时,调用该对象的方法。要使用这些监听器对象,用户必须定义监听器类,并且指定相应的监听器类。
  
  定义监听器类
  您可以将监听器类定义为一个listener接口的实现。Servlet生命周期事件列出了可以检测的事件和相应的必须实现的接口。当调用一个监听器方法时,需向该方法传递一个包含事件适当信息的事件。例如,向HttpSessionListener接口中的方法传递的是一个HttpSessionEvent事件,这个事件包含了一个HttpSession。
  
  表14-2Servle生命周期事件
  
  对象
  事件
  监听器接口和事件类
  
  Web上下文
  (见访问Web上下文)
  初始化和销毁
  javax.servlet.
  ServletContextListener和
  
  ServletContextEvent
  
  属性的添加、删除或替代
  javax.servlet.
  ServletContextAttributeListener和
  
  ServletContextAttributeEvent
  
  会话
  (见维护客户给状态)
  创建、失效和超时
  javax.servlet.http.
  HttpSessionListener和
  
  HttpSessionEvent
  
  属性的添加、删除或替代
  javax.servlet.http.
  HttpSessionAttributeListener和
  
  HttpSessionBindingEvent
  
  
  listeners.ContextListener类负责创建和移除在Duke书店应用程序中使用的数据库助手和计数器对象。方法从ServletContextEvent中获取Web上下文对象,进而存储(和移除)作为servlet上下文属性的对象。
  
  importdatabase.BookDB;
  importjavax.servlet.*;
  importutil.Counter;
  
  publicfinalclassContextListener
  implementsServletContextListener{
  privateServletContextcontext=null;
  publicvoidcontextInitialized(ServletContextEventevent){
  context=event.getServletContext();
  try{
  BookDBbookDB=newBookDB();
  context.setAttribute("bookDB",bookDB);
  }catch(Exceptionex){
  System.out.println(
  "Couldn'tcreatedatabase:"
  +ex.getMessage());
  }
  Countercounter=newCounter();
  context.setAttribute("hitCounter",counter);
  context.log("CreatedhitCounter"
  +counter.getCounter());
  counter=newCounter();
  context.setAttribute("orderCounter",counter);
  context.log("CreatedorderCounter"
  +counter.getCounter());
  }
  
  publicvoidcontextDestroyed(ServletContextEventevent){
  context=event.getServletContext();
  BookDBbookDB=context.getAttribute(
  "bookDB");
  bookDB.remove();
  context.removeAttribute("bookDB");
  context.removeAttribute("hitCounter");
  context.removeAttribute("orderCounter");
  }
  }
  
  指定事件监听器类
  为了指定一个事件监听器类,用户要为Web应用部署描述符添加一个listener元素。以下就是Duke书店应用程序的一个listener元素。
  
  <listener>
  <listener-class>listeners.ContextListener</listener-class>
  </listener>
  
  处理错误
  当servlet执行时,可能产生许多异常。而当异常产生时,Web容器将产生一个包含AServletExceptionHasOccurred消息的缺省页。但是,用户也可返回一个容器,该容器应包含为给定异常指定的错误页。为了指定这样一个页,用户要为Web应用添加部署描述符添加一个error-page元素。这些元素将Duke书店应用程序返回的异常映射到errorpage.html:
  
  <error-page>
  <exception-type>
  exception.BookNotFoundException
  </exception-type>
  <location>/errorpage.html</location>
  </error-page>
  <error-page>
  <exception-type>
  exception.BooksNotFoundException
  </exception-type>
  <location>/errorpage.html</location>
  </error-page>
  <error-page>
  <exception-type>exception.OrderException</exception-type>
  <location>/errorpage.html</location></error-page>
  
  共享信息
  像大多数对象一样,Web组件通常与其他一些对象协同工作,以完成任务。要做到这一点,可以有多种方法。Web组件可以使用私有的helper(助手)对象(例如,JavaBeans组件),也可以共享那些有公共作用域属性的对象,它们可以使用数据库,还可以调用其他的Web资源。JavaServlet技术机制允许一个Web组件调用其他的Web资源,这在调用其他Web资源中有描述。
  
  使用作用域对象
  几个协作的Web组件通过一些对象来共享信息,这些对象是作为四个作用域对象的属性来维护的。这些属性可以通过表示域的类的[get|set]Attribute方法访问。表14-3列出了这个作用域对象。
  
  表14-3作用域对象
  
  作用域对象
  类
  哪些组件可以对其进行访问
  
  Web上下文
  javax.servlet.
  ServletContext
  Web上下文中的Web组件。见访问Web上下文
  
  会话
  javax.servlet.
  http.HttpSession
  处理属于会话的请求的Web组件。见维护客户端状态。
  
  请求
  javax.servlet.
  ServletRequest
  
  的子类型
  处理请求的Web组件。
  
  页
  javax.servlet.
  jsp.PageContext
  创建对象的JSP页。见隐式对象。
  
  
  图14-1显示了Duke书店应用程序维护的作用域属性。
  
  
  
  图14-1Duke书店作用域属性
  
  控制对共享资源的并发访问
  在多线程的服务器中,可能出现对共享资源的并发访问。除了作用域对象属性外,共享资源还包括存储器中的数据(如实例和类变量)、外部对象(如文件)、数据库连接和网络连接。并发访问可出现在多个情况下。
  
  ·多个Web组件访问存储在Web上下文中的对象。t
  
  ·多个Web组件访问存储在会话中的对象。
  
  ·一个Web组件中的多个线程访问实例变量。一个Web容器一般为每个请求创建一个线程来处理。如果用户确认一个servlet实例每次只处理一个请求,servlet就能实现SingleThreadModel接口。如果servlet实现了这个接口,用户就能确保servlet的服务方法中不可能有两个线程并发执行。Web容器可通过同步访问一个servlet的单独实例、或者通过维护一个Web组件池为每个实例调用一个新的请求来实现。这个接口并不能防止Web组件访问共享资源(如静态类变量、外部对象)导致的同步问题
  
  当资源可以并发访问时,使用资源也就可以用不一致的方式。为了防止这样的情况发生,用户必须使用在Java指导中的线程单元中描述的同步机制来控制访问。
  
  在以前的部分中,我们说明了被多个servlet共享的5个作用域属性:bookDB,cart,currency,hitCounter和orderCounter。bookDB属性将在下一节中讨论。cart,currency和counter可以被多线程的servlet设置和读。使用同步方法来控制访问以防止这些对象的使用不一致。例如,下面是一个util.Counter类:
  
  publicclassCounter{
  privateintcounter;
  publicCounter(){
  counter=0;
  }
  publicsynchronizedintgetCounter(){
  returncounter;}
  publicsynchronizedintsetCounter(intc){
  counter=c;returncounter;
  }
  publicsynchronizedintincCounter(){
  return(++counter);
  }
  }
  
  访问数据库
  在Web组件之间共享,并且在对一个Web应用被调用的间隙内维持的数据通常是由一个数据库来维护的。Web组件使用JDBC2.0API来访问关系数据库。书店应用程序的数据由数据库来维护,并通过助手类database.BookDB访问。例如,当用户购买书后,ReceiptServlet调用BookDB.buyBooks方法来更新书的清单。buyBooks方法为每本包含在购物车中的书调用buyBook。为了确保命令被完全执行,buyBook的调用程序将被包装在一个单独的JDBC事务处理中。通过[get|release]Connection方法可以使共享数据库连接同步使用。
  
  publicvoidbuyBooks(ShoppingCartcart)throwsOrderException{
  Collectionitems=cart.getItems();
  Iteratori=items.iterator();
  try{
  getConnection();
  con.setAutoCommit(false);
  while(i.hasNext()){
  ShoppingCartItemsci=(ShoppingCartItem)i.next();
  BookDetailsbd=(BookDetails)sci.getItem();
  Stringid=bd.getBookId();
  intquantity=sci.getQuantity();
  buyBook(id,quantity);
  }
  con.commit();
  con.setAutoCommit(true);
  releaseConnection();
  }catch(Exceptionex){
  try{
  con.rollback();
  releaseConnection();
  thrownewOrderException("Transactionfailed:"+
  ex.getMessage());
  }catch(SQLExceptionsqx){
  releaseConnection();
  thrownewOrderException("Rollbackfailed:"+
  sqx.getMessage());
  }
  }
  }
  
  初始化Servlet
  在Web容器加载和实例化servlet类之后、servlet实例传递来自客户端的请求之前,Web容器对servlet进行初始化。用户可以自定义这个初始化过程,以允许servlet读持久的配置数据、初始化资源,并且忽略Servlet接口的init方法以执行任何其它的一次性的活动。servlet必须使用UnavailableException来完成初始化过程。
  
  所有的访问书店数据库的servlet(BookStoreServlet,CatalogServlet,BookDetailsServlet,和ShowCartServlet)在它们的init方法中初始化一个变量,指向用Web上下文监听器创建的数据库助手对象。
  
  publicclassCatalogServletextendsHttpServlet{
  privateBookDBbookDB;
  publicvoidinit()throwsServletException{
  bookDB=(BookDB)getServletContext().
  getAttribute("bookDB");
  if(bookDB==null)thrownew
  UnavailableException("Couldn'tgetdatabase.");
  }
  }
  
  编写服务方法
  servlet提供的服务实现在GenericServlet的service方法、HttpServlet的doMethod方法(在该方法中,Method可以带Get、Delete、Options、Post、Put、Trace的值),或者是任何其他的由实现了Servlet接口的类定义的协议指定(protocol-specific)的方法中。在这一章剩下的部分中,服务方法这个术语将用于在一个向客户端提供服务的servlet类中定义的任何方法。
  
  服务方法的一般模式是从请求中提取信息、访问外部资源并且基于这些信息填充响应。
  
  对于HTTPservlet来说,填充响应的正确过程是:首先填充响应头,然后从响应中获取一个输出流,最后编写输出流的所有主体内容。响应头必须在PrintWriter或ServletOutputStream被获取到之前设置好,因为HTTP协议希望获得主体内容前的所有头的信息。下两节将描述如何从请求中获得信息和产生响应。
  
  从请求中获得信息
  一个请求包含客户端和servlet之间传递的数据。所有请求都实现了ServletRequest接口,该接口为访问一下的信息定义了方法:
  
  ·参数,通常用来在客户端和servlet之间传送信息
  
  ·对象属性(Object-valuedattribute),通常用来在servlet容器与servlet之间或在协作的servlet之间传递信息
  
  ·有关协议的信息,用来在请求、客户端和涉及到该请求中的服务器之间的通信。
  
  ·有关地区化的信息。
  
  例如,在CatalogServlet中,顾客希望购买的书的标识符作为参数包含在请求中。下面的这段代码说明了如何使用getParameter方法提取标识符。
  
  StringbookId=request.getParameter("Add");
  if(bookId!=null){
  BookDetailsbook=bookDB.getBookDetails(bookId);
  
  用户也可以从请求中获取一个输入流,并对数据进行手工解析。要读字符数据,可以使用由请求的getReader方法返回的BufferedReader对象来完成。而要读二进制数据,可以使用getInputStream返回的ServletInputStream。
  
  HTTPserlvet通过HTTP请求对象传递,HttpServletRequest包含了请URL、HTTP头、查询字符串等等。
  
  一个HTTP请求URL包含以下几部分:
  
  http://[host]:[port][requestpath]?[querystring]
  
  请求路径由以下元素组成:
  
  ·上下文路径:向前的斜线/和servlet的Web应用的上下文根的拼接。
  
  ·servlet路径:与激活该请求的组件别名相应的路径部分,由向前的斜线/开始。
  
  ·路径信息:请求路径的部分,不是上下文路径或者servlet路径的部分。
  
  如果上下文路径是/catalog和表14-4列举出的别名,表14-5给出了一些实例,说明如何分解URL。
  
  表14-4别名
  
  模式
  Servlet
  
  /lawn/*
  LawnServlet
  
  /*.jsp
  JSPServlet
  
  
  表14-5请求路径元素
  
  请求路径
  Servlet路径
  路径信息
  
  /catalog/lawn/index.html
  /lawn
  /index.html
  
  /catalog/help/feedback.jsp
  /help/feedback.jsp
  null
  
  
  查询字符串由参数和值的集合组成。每个参数都是从请求中用getParameter方法获取得到的。这里有两种方法产生查询字符串:
  
  ·一个查询字符串能在Web页中明确地显示出来。例如,一个HTML页由CatalogServlet产生,该HTML页包含了<ahref="/bookstore1/catalog?Add=101">AddToCart</a>。CatalogServlet将命名为Add的参数提出,如下:
  
  StringbookId=request.getParameter("Add");
  ·当一个表单与一个GETHTTP方法一起被提交时,在URL上附加一个查询字符串。在Duke书店应用程序中,首先CashierServlet产生了一个表单,然后在表单中输入一个用户名,该表单附加在映射到ReceiptServlet的URL上,最后ReceiptServlet使用getParameter方法提取用户名。

分享到:
本文"Java Servlet 技术"由远航站长收集整理而来,仅供大家学习与参考使用。更多网站制作教程尽在远航站长站。
顶一下
(0)
0%
踩一下
(0)
0%
[点击 次] [返回上一页] [打印]
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 密码: 验证码:
关于本站 - 联系我们 - 网站声明 - 友情连接- 网站地图 - 站点地图 - 返回顶部
Copyright © 2007-2013 www.yhzhan.com(远航站长). All Rights Reserved .
远航站长:为中小站长提供最佳的学习与交流平台,提供网页制作与网站编程等各类网站制作教程.
官方QQ:445490277 网站群:26680406 网站备案号:豫ICP备07500620号-4