`
javababy1
  • 浏览: 1161949 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

javabean与jsp

 
阅读更多

综述:JavaBean体系结构是第一个全面的基于组件的标准模型之一,为Java类提供了定义方法、事件、属性的方法,以便在设计时允许外部的操作和定制。JavaBean组件是Java类,这些类遵循一个统一的接口格式,以便该类的方法命名,底层行为以及具体实现能够符合标准的JavaBean组件构造方式。这些组件的容器能以标准方式与JavaBean进行交互,使得JavaBean可以部署在多种设计工具和运行环境中。

  如何定制JavaBean属性?

  一个标准的JavaBean组件应该满足以下几点特性:


  (1)持续性
  持续性允许一个构件保存它的状态,因此它还能被重新创建。利用持续性机制,表单构件可存为一个文件,并在其它时间被打开,使以前的数据、公式和设置完好无损。JavaBeans持续性使用Java1.1环境对象序列化机制产生I/O流并在以后恢复。构件创建者只需实现可序列化的接口以使构件保持持续。持续的流可能为一个Java文件、一网络连接或更有趣一些,一个由其它构件模型提供的流。若JavaBean构件嵌入一个ActiveX或OpenDoc构件中,Bean通过相关的"桥"提供持续的流。
  (2)制定性
  制定是JavaBean构件的新特性之一。简而言之,Bean的创建者不仅创建运行状态的构件,而且还通过扩展Java.awt.Component类创建了UI工具箱的类。这个UI工具箱可被用来制定Bean的一个实例。利用其它的构件模型,开发环境、可视化开发工具或任何其它的都必须提供所有对该构件的制定逻辑。JavaBean构件可随同自己的UI工具箱类发布,智能的制定该构件。开发环境可制定任何在别人创建的构件。开发工具只是寻找相关的制定器类并在其窗口中创建一个它的实例,而不必需要其它的。
  (3)自查性
  对于能在开发环境中复用的Java构件,需要有查询一个Bean能做些什么和产生和监听事件的类型。在JavaBeans规范中,这被称为规范并且是Java1.1提供的基本的反映机制的扩展。反映机制允许运行状态进行查询以得到对象的类并由此得到其公开的方法和变量。Bean的自查机制进行了扩展,查找指定的设计方式的使用。通过BeanInfo类,Bean作者可以暴露要暴露的公共方法和变量。当作为构件复用现存Java代码时,BeanInfo类也是很有用的。编程人员可用创建一个BeanInfo类,具体指定要用到的得到和设置属性的方法名,由此覆盖缺省的自查。
  (4)封装性
  JavaBean构件常被打包为JAR文件。JAR的格式允许构件作为一个单独的实体,随同其支持类(如制定编辑器、BeanInfo和其它资源文件)被打包。开发环境必须了解JAR的格式并使用其manifest文件一个JAR中所包括的Bean。包含一个JavaBean构件的JAR还可能包括该构件的序列化版本。若这个持续的实例存在,便使用它。这样,提供商就可以发布该构件的可用的或制定好的版本。
  JavaBean的属性与一般Java程序中所指的属性,或者说与所有面向对象的程序设计语言中对象的属性是一个概念,在程序中的具体体现就是类中的变量。在JavaBean设计中,按照属性的不同作用又细分为四类:Simple,Index,Bound与Constrained属性。

  1. Simple属性
  一个简单属性表示一个伴随有一对get/set方法(C语言的过程或函数在Java程序中称为"方法")的变量。属性名与和该属性相关的get/set方法名对应。例如:如果有setX和getX方法,则暗指有一个名为"X"的属性。如果有一个方法名为isX,则通常暗指"X"是一个布尔属性(即X的值为true或false)。例如在下面这个程序中:

public class alden1 extends Canvas {
string ourString= "Hello"; //属性名为ourString,类型为字符串
public alden1(){// alden1的构造函数,与C++中构构造函数的义相同
setBackground(Color.red);
setForeground(Color.blue);
}
/* "set"属性*/
public void setString(String newString) {
ourString=newString;
}
/* "get"属性 */
public String getString() {
return ourString;
}
}

  2. Indexed属性
  一个Indexed属性表示一个数组值。使用与该属性对应的set/get方法可取得数组中的数值。该属性也可一次设置或取得整个数组的值。例:

public class alden2 extends Canvas {
int[] dataSet={1,2,3,4,5,6}; // dataSet是一个indexed属性
public alden2() {
setBackground(Color.red);
setForeground(Color.blue);
}
/*

  设置整个数组

*/
public void setDataSet(int[] x){
dataSet=x;
}
/*

  设置数组中的单个元素值

*/
public void setDataSet(int index, int x){
dataSet[index]=x;
}
/*

  取得整个数组值

*/
public int[] getDataSet(){
return dataSet;
}
/*

  取得数组中的指定元素值

*/
public int getDataSet(int x){
return dataSet[x];
}
}

3. Bound属性
  一个Bound属性是指当该种属性的值发生变化时,要通知其它的对象。每次属性值改变时,这种属性就激活一个PropertyChange事件(在Java程序中,事件也是一个对象)。事件中封装了属性名、属性的原值、属性变化后的新值。这种事件是传递到其它的Bean,至于接收事件的Bean应做什么动作由其自己定义。例:

public class alden3 extends Canvas{
String ourString= "Hello"; //ourString是一个bound属性
private PropertyChangeSupport changes = new PropertyChangeSuppor(this);
/**

  注:Java是纯面向对象的语言,如果要使用某种方法则必须指明是要使用哪个对象的方法,在下面的程序中要进行激活事件的操作,这种操作所使用的方法是在PropertyChangeSupport类中的。所以上面声明并实例化了一个changes对象,在下面将使用changes的firePropertyChange方法来点火ourString的属性改变事件。

*/
public void setString(string newString){
String oldString = ourString;
ourString = newString;
/*

  ourString的属性值已发生变化,于是接着激活属性改变事件

*/
changes.firePropertyChange("ourString",oldString,new String);
}
public String getString(){
return ourString;
}
/**

  以下代码是为开发工具所使用的。我们不能预知alden3将与哪些其它的Bean组合成为一个应用,无法预知若alden3的ourString属性发生变化时有哪些其它的组件与此变化有关,因而alden3这个Bean要预留出一些接口给开发工具,开发工具使用这些接口,把其它的JavaBean对象与alden3挂接。

*/
public void addPropertyChangeListener(PropertyChangeLisenerl){
changes.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l){
changes.removePropertyChangeListener(l);
}

  通过上面的代码,开发工具调用changes的addPropertyChangeListener方法把其它JavaBean注册入ourString属性的监听者队列l中,l是一个Vector数组,可存储任何Java对象。开发工具也可使用changes的removePropertyChangeListener方法,从l中注销指定的对象,使alden3的ourString属性的改变不再与这个对象有关。当然,当程序员手写代码编制程序时,也可直接调用这两个方法,把其它Java对象与alden3挂接。

  4. Constrained属性
  一个JavaBean的constrained属性,是指当这个属性的值要发生变化时,与这个属性已建立了某种连接的其它Java对象可否决属性值的改变。constrained属性的监听者通过抛出PropertyVetoException来阻止该属性值的改变。例:(下面程序中的constrained属性是PriceInCents。)

public class JellyBean extends Canvas{
private PropertyChangeSupport changes=new PropertyChangeSupport(this);
private VetoableChangeSupport Vetos=new VetoableChangeSupport(this);

  /*与前述changes相同,可使用VetoableChangeSupport对象的实例Vetos中的方法,在特定条件下来阻止PriceInCents值的改变。*/
  public void setPriceInCents(int newPriceInCents) throws PropertyVetoExcption {
  /*方法名中throws PropertyVetoException的作用是当有其它Java对象否决PriceInCents的改变时,要抛出例外。
  */
  /*
  先保存原来的属性值

*/
int oldPriceInCents=ourPriceInCents;
/**

  激活属性改变否决事件

*/
vetos.fireVetoableChange("priceInCents",new Integer(OldPriceInCents),
new Integer(newPriceInCents));
/**

  若有其它对象否决priceInCents的改变,则程序抛出例外,不再继续执行下面的两条语句,方法结束。若无其它对象否决priceInCents的改变,则在下面的代码中把ourPriceIncents赋予新值,并激活属性改变事件

*/
ourPriceInCents=newPriceInCents;
changes.firePropertyChange("priceInCents", new Integer(oldPriceInCents),
new Integer(newPriceInCents));
}
/**

  与前述changes相同,也要为PriceInCents属性预留接口,使其它对象可注册入PriceInCents否决改变监听者队列中,或把该对象从中注销*/

public void addVetoableChangeListener(VetoableChangeListener l){
vetos.addVetoableChangeListener(l);
}
public void removeVetoableChangeListener(VetoableChangeListener l){
vetos.removeVetoableChangeListener(l);
}
……
}


  从上面的例子中可看到,一个constrained属性有两种监听者:属性变化监听者和否决属性改变的监听者。否决属性改变的监听者在自己的对象代码中有相应的控制语句,在监听到有constrained属性要发生变化时,在控制语句中判断是否应否决这个属性值的改变。
  总之,某个Bean的constrained属性值可否改变取决于其它的Bean或者是Java对象是否允许这种改变。允许与否的条件由其它的Bean或Java对象在自己的类中进行定义。

如何创建JavaBean事件对象

  事件处理是JavaBean体系结构的核心之一。通过事件处理机制,可让一些组件作为事件源,发出可被描述环境或其它组件接收的事件。这样,不同的组件就可在构造工具内组合在一起,组件之间通过事件的传递进行通信,构成一个应用。从概念上讲,事件是一种在"源对象"和"监听者对象"之间,某种状态发生变化的传递机制。事件有许多不同的用途,例如在Windows系统中常要处理的鼠标事件、窗口边界改变事件、键盘事件等。在Java和JavaBean中则是定义了一个一般的、可扩充的事件机制,这种机制能够:
  ·对事件类型和传递的模型的定义和扩充提供一个公共框架,并适合于广泛的应用。
  ·与Java语言和环境有较高的集成度。
  ·事件能被描述环境捕获和点火。
  ·能使其它构造工具采取某种技术在设计时直接控制事件,以及事件源和事件监听者之间的联系。
  ·事件机制本身不依赖于复杂的开发工具。

  特别地,还应当:

  ·能够发现指定的对象类可以生成的事件。
  ·能够发现指定的对象类可以观察(监听)到的事件。
  ·提供一个常规的注册机制,允许动态操纵事件源与事件监听者之间的关系。
  ·不需要其它的虚拟机和语言即可实现。
  ·事件源与监听者之间可进行高效的事件传递。
  ·能完成JavaBean事件模型与相关的其它组件体系结构事件模型的中立映射。

  1. 概述
  事件从事件源到监听者的传递是通过对目标监听者对象的Java方法调用进行的。对每个明确的事件的发生,都相应地定义一个明确的Java方法。这些方法都集中定义在事件监听者(EventListener)接口中,这个接口要继承Java.util.EventListener。
  实现了事件监听者接口中一些或全部方法的类就是事件监听者。伴随着事件的发生,相应的状态通常都封装在事件状态对象中,该对象必须继承自Java.util.EventObject。事件状态对象作为单参传递给应响应该事件的监听者方法中。
  发出某种特定事件的事件源的标识是:遵从规定的设计格式为事件监听者定义注册方法,并接受对指定事件监听者接口实例的引用。
  有时,事件监听者不能直接实现事件监听者接口,或者还有其它的额外动作时,就要在一个源与其它一个或多个监听者之间插入一个事件适配器类的实例,来建立它们之间的联系。

  2. 事件状态对象(Event State Object)
  与事件发生有关的状态信息一般都封装在一个事件状态对象中,这种对象是Java.util.EventObject的子类。按设计习惯,这种事件状态对象类的名应以Event结尾。例如:
  public class MouseMovedExampleEvent extends Java.util.EventObject {
  protected int x,y;
  /* 创建一个鼠标移动事件MouseMovedExampleEvent */

MouseMovedExampleEvent(Java.awt.Component source,Point location){
  super(source);
  x = location.x;
  y = location.y;
  }
  /* 获取鼠标位置*/
  public Point getLocation() {
  return new Point(x,y);
  }
  }


  3. 事件监听者接口(EventListener Interface)与事件监听者
  由于Java事件模型是基于方法调用,因而需要一个定义并组织事件操纵方法的方式。JavaBean中,事件操纵方法都被定义在继承了Java.util.EventListener类的EventListener接口中,按规定,EventListener接口的命名要以Listener结尾。任何一个类如果想操纵在EventListener接口中定义的方法都必须以实现这个接口方式进行。这个类也就是事件监听者。例如:
  /*先定义了一个鼠标移动事件对象*/
  public class MouseMovedExampleEvent extends Java.util.EventObject {
  // 在此类中包含了与鼠标移动事件有关的状态信息
  ……
  }
  /*定义了鼠标移动事件的监听者接口*/
  interface MouseMovedExampleListener extends Java.util.EventListener {
  /*在这个接口中定义了鼠标移动事件监听者所应支持的方法*/
  void mouseMoved(MouseMovedExampleEvent mme);
  }
  在接口中只定义方法名,方法的参数和返回值类型。如:上面接口中的mouseMoved方法的具体实现是在下面的ArbitraryObject类中定义的。

class ArbitraryObject implements MouseMovedExampleListener {
  public void mouseMoved(MouseMovedExampleEvent mme)
  {……}
  }


  ArbitraryObject就是MouseMovedExampleEvent事件的监听者。

  4. 事件监听者的注册与注销

  为了各种可能的事件监听者把自己注册入合适的事件源中,建立源与事件监听者间的事件流,事件源必须为事件监听者提供注册和注销的方法。在前面的bound属性介绍中已看到了这种使用过程,在实际中,事件监听者的注册和注销要使用标准的设计格式:

public void add< ListenerType>(< ListenerType> listener);
  public void remove< ListenerType>(< ListenerType> listener);


  例如:

  ·首先定义了一个事件监听者接口

public interface ModelChangedListener extends Java.util.EventListener {
  void modelChanged(EventObject e);
  }


  ·接着定义事件源类

  public abstract class Model {
  private Vector listeners = new Vector(); // 定义了一个储存事件监听者的数组
  /*上面设计格式中的< ListenerType>在此处即是下面的ModelChangedListener*/
  public synchronized void addModelChangedListener(ModelChangedListener mcl){
  listeners.addElement(mcl);//把监听者注册入listeners数组中
  }
  public synchronized void removeModelChangedListener(ModelChangedListener mcl){
  listeners.removeElement(mcl); //把监听者从listeners中注销
  }

  /*以上两个方法的前面均冠以synchronized,是因为运行在多线程环境时,可能同时有几个对象同时要进行注册和注销操作,使用synchronized来确保它们之间的同步。开发工具或程序员使用这两个方法建立源与监听者之间的事件流

*/
protected void notifyModelChanged(){


  /**事件源使用本方法通知监听者发生了modelChanged事件

*/
Vector l;
EventObject e = new EventObject(this);


  /* 首先要把监听者拷贝到l数组中,冻结EventListeners的状态以传递事件。这样来确保在事件传递到所有监听者之前,已接收了事件的目标监听者的对应方法暂不生效。

*/
synchronized(this){
l = (Vector)listeners.clone();
}
for (int i = 0; i < l.size(); i++) {


  /* 依次通知注册在监听者队列中的每个监听者发生了modelChanged事件,并把事件状态对象e作为参数传递给监听者队列中的每个监听者*/

((ModelChangedListener)l.elementAt(i
)).modelChanged(e);
}
}
}


  在程序中可见事件源Model类显式地调用了接口中的modelChanged方法,实际是把事件状态对象e作为参数,传递给了监听者类中的modelChanged方法。

  5. 适配类
  适配类是Java事件模型中极其重要的一部分。在一些应用场合,事件从源到监听者之间的传递要通过适配类来"转发"。例如:当事件源发出一个事件,而有几个事件监听者对象都可接收该事件,但只有指定对象做出反应时,就要在事件源与事件监听者之间插入一个事件适配器类,由适配器类来指定事件应该是由哪些监听者来响应。
  适配类成为了事件监听者,事件源实际是把适配类作为监听者注册入监听者队列中,而真正的事件响应者并未在监听者队列中,事件响应者应做的动作由适配类决定。目前绝大多数的开发工具在生成代码时,事件处理都是通过适配类来进行的。


如何深入JavaBean的用户编程接口?

  JavaBean开发者可以给一个Bean添加用户化器(Customizer)、属性编辑器(Property Editor)和BeanInfo接口来描述一个Bean的内容,Bean的使用者可在构造环境中通过与Bean附带在一起的这些信息来用户化Bean的外观和应做的动作。一个Bean不必都有BeanCustomizer、PrpertyEditor和BeanInfo,根据实际情况,这些是可选的,当有些Bean较复杂时,就要提供这些信息,以Wizard的方式使Bean的使用者能够用户化一个Bean。有些简单的Bean可能这些信息都没有,则构造工具可使用自带的透视装置,透视出Bean的内容,并把信息显示到标准的属性表或事件表中供使用者用户化Bean,前几节提到的Bean的属性、方法和事件名要以一定的格式命名,主要的作用就是供开发工具对Bean进行透视。当然也是给程序员在手写程序中使用Bean提供方便,使他能观其名、知其意。
  ⑴ 用户化器接口(Customizer Interface)
  当一个Bean有了自己的用户化器时,在构造工具内就可展现出自己的属性表。在定义用户化器时必须要实现Java.beans.Customizer接口。例如,下面是一个"按钮"Bean的用户化器:
  public class OurButtonCustomizer extends Panel implements Customizer {
  ……
  /*当实现象OurButtonCustomizer这样的常规属性表时,一定要在其中实现
addProperChangeListener和removePropertyChangeListener,这样,构造工具可用这些功能代码为属性事件添加监听者。*/

……
private PropertyChangeSupport changes=new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener l) {
changes.addPropertyChangeListener(l);
public void removePropertyChangeListener(PropertyChangeListener l){
changes.removePropertyChangeListener(l);
}
……
    }



  ⑵ 属性编辑器接口(PropertyEditor Interface)
  一个JavaBean可提供PropertyEditor类,为指定的属性创建一个编辑器。这个类必须继承自Java.beans.PropertyEditorSupport类。构造工具与手写代码的程序员不直接使用这个类,而是在下一小节的BeanInfo中实例化并调用这个类。例:

public class MoleculeNameEditor extends Java.beans.PropertyEditorSupport{
public String[] getTags(){
String resule[]={"HyaluronicAcid","Benzene","buckmisterfullerine"
"cyclohexane","ethane","water"};
return resule;
}
}


  上例中是为Tags属性创建了属性编辑器,在构造工具内,可从下拉表格中选择MoleculeName的属性应是"HyaluronicAid"或是"water"。

  ⑶ BeanInfo接口

  每个Bean类也可能有与之相关的BeanInfo类,在其中描述了这个Bean在构造工具内出现时的外观。BeanInfo中可定义属性、方法、事件,显示它们的名称,提供简单的帮助说明。例如:

public class MoleculeBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors(){
try {
PropertyDescriptor pd=new PropertyDescriptor("moleculeame",
Molecule.class);
/*通过pd引用了上一节的MoleculeNameEditor类,取得并返回mleculeName属性*/
pd.setPropertyEditorClass(MoleculeNameEditor.class);
PropertyDescriptor result[]={pd};
return result;
} catch(Exception ex){
System.err.println("MoleculeBeanInfo: unexpected exeption: "+ex);
return null;
}
}
}


  当一个JavaBean在构造工具内被用户化,并与其它Bean建立连接之后,它的所有状态都应当可被保存,下一次被load进构造工具内或在运行时,就应当是上一次修改完的信息。为了能做到这一点,要把Bean的某些字段的信息保存下来,在定义Bean时要使它实现Java.io.Serializable接口。例如:
  public class Button implements Java.io.Serializable {……}
  实现了序列化接口的Bean中字段的信息将被自动保存。若不想保存某些字段的信息则可在这些字段前冠以transient或static关键字,transient和static变量的信息是不可被保存的。通常,一个Bean所有公开出来的属性都应当是被保存的,也可有选择地保存内部状态。Bean开发者在修改软件时,可以添加字段,移走对其它类的引用,改变一个字段的private、protected或public状态,这些都不影响类的存储结构关系。然而,当从类中删除一个字段,改变一个变量在类体系中的位置,把某个字段改成transient/static,或原来是transient/static,现改为别的特性时,都将引起存储关系的变化。
  JavaBean组件被设计出来后,一般是以扩展名为jar的Zip格式文件存储,在jar中包含与JavaBean有关的信息,并以MANIFEST文件指定其中的哪些类是JavaBean。以jar文件存储的JavaBean在网络中传送时极大地减少了数据的传输数量,并把JavaBean运行时所需要的一些资源捆绑在一起。
  本小节主要论述了JavaBeans的一些内部特性及其常规设计方法,参考的是JavaBeans规范1.0A版本。随着世界各大ISV对JavaBeans越来越多的支持,规范在一些细节上还在不断演化,但基本框架不会再有大的变动。

  用JSP和JavaBean如何实现"简单购物车"应用?

  1. 简单购物车的实现方案
  下面,本节将通过一个简单的购物车程序来说明一下JSP和JavaBean在网络体系结构中是怎样相互作用的,并且借这个例子解释编写一个实际可用的电子商务应用程序应该注意的一些问题。在电子商务应用中JSP和JavaBean的结合方式如下图所示:



  JSP和JavaBean在电子商务应用中的结合方式

  如果从Model/View/Controller(MVC)模式来理解电子商务应用体系结构,可以把应用程序划分成独立的数据管理(Model),表现形式(View)和控制组件(Controller),成为最先进的图形用户接口的基础,这些划分模块支持独立开发并且可以重复使用组件。其中JSP最适合充当实现网络应用程序的对外表现的部分;而JavaBeans封装了提供给Web网站的服务信息内容并且简化了数据在体系结构组件之间的传输;Servlet则正好充当控制者和协调用户请求和应用程序信息、更新程序数据等功能,其逻辑关系图如下所示:

  MCV模式下的电子商务应用体系结构图

  2.简单购物车的实现细节
  ⑴ Controller部分
  本部分的实现代码和解释如下:

CustomerServlet.Java
  package shoppingcart;
  import Javax.servlet.*;
  import Javax.servlet.http.*;
  import Java.io.IOException;
  public class CustomerServlet extends HttpServlet {
  ……

  上面的程序段显示了CustomerServlet类中的doGet()和doPost()方法。  CustomerServlet类做了两件事情来控制应用程序的工作流程:
  ·通过 BasketBean类实现,保持购物车组件的状态,;
  ·它通过一系列的JSP页面向顾客发送请求。
  一旦购物车与某一个特定的顾客session相联系,顾客的BasketBean对象的实例就会存储在 HttpSession对象中。一个以普通ID进入CustomerServlet工作流程的客户,他会产生很多动作,servlet引擎提供了HttpSession对象来组织并存储这一系列的相互作用(Session对象为存储和取回任何使用唯一的键/值对的Java对象提供了方便的方法)。在CustomerServlet类中 ,首先通过HttpSession session = request.getSession(true)从 servlet 引擎中取得Session对象,读者可以看到,程序传递了true值,意思是告诉Servlet引擎,如果一个session对象已经不存在了,就新建一个;然后查看Session中是否有购物车,如果找不到购物车,就知道这个购物Session刚刚开始,必须新建一辆购物车,并且把它保存在Session对象中,如果能够在Session中找到购物车,那就知道顾客正处在一个购物期间,那时就必须存储购物车当前的状态。在查看了购物车的状态之后,把顾客的请求发送到相应的JSP页中去,请求本身包含一个状态参数(BasketBean.PAGE)告诉CustomerServlet把请求发送到哪里,控制器取回这个参数,然后使用一个RequestDispatcher对象把请求提交给下一个JSP页。
  ⑵ Model部分
  本部分的实现代码和解释如下(BasketBean类):

package shoppingcart;
  import Javax.servlet.http.HttpServletRequest;
  import Java.util.Hashtable;
  import Java.util.Enumeration;
  public class BasketBean {
……

  BasketBean类实现购物车应用程序中一个简单的数据管理模型,它提供了一个方法,用于取得一个顾客正在购买的货物的信息,还提供了一个方法用来更新购物车的内容,程序使用一张哈希表来维护顾客请求的商品列表。InventoryBean对象管理商品的目录,我们是使用一个数组来实现商品的目录的。每个Product类的实例存储四个属性:商品名字,商品标识号,单价和购买的数量,只要顾客购买了东西,Product类的实例就会改变。
  ⑶ View部分
  购物车方案中设定了3个JSP页面:Inventory.jsp,Purchase.jsp和Receipt.jsp(代码见下)。应用程序发送Inventory.jsp页面给新来的顾客,顾客通过不断的更新Inventory.jsp,来挑选商品;顾客选择好想要购买的商品以后,应用程序就会把顾客的购买请求发送到Purchase.jsp页,进行处理;最后,顾客证实确实购买这些商品,应用程序把顾客请求发送到Receipt.jsp。



  JSP页面交互流程图

 


a.Inventory.jsp代码段
  下面的JSP片段用来声明局部变量保存当前购物篮(BasketBean的实例)和产品目录。

<%
BasketBean basket;
Product[] catalogue;
%>

  从上面可以看出,JSP 声明必须以一个分号结束,并且这个声明的范围是整个JSP页。声明这些局部变量以后,Inventory.jsp 使用一段小脚本从session对象中取回购物车对象(BasketBean)和商名目录,如下。

<%
basket =(BasketBean) session.getAttribute( BasketBean.BASKET);
catalogue = InventoryBean.getCatalogue();
%>

  由上可以看出,JSP 声明和JSP小脚本只是放在特定的JSP标记之间的Java代码,当JSP引擎把一个JSP程序翻译成一个servlet时,它就把这些Java代码内嵌到新的Servlet代码中去。
  如前所述,程序从一个session对象中取得购物车对象,这个session对象是一个内部物体。JSP引擎提供一些内部隐含对象,这些对象可以直接被引用,我们可以不事先声明,也不需要专门的代码来创建他们的实例。它们在小脚本和表达式中总是可以使用的,而不需要预先声明。JSP1.1规范中列出内部隐含对象完整的集合。在程序中,另一个象这样的对象就是HttpServletRequest对象(request),它在CustomerServlet类中作为一个参数被传递到doPost()方法中,这就意味着Inventory.jsp能够通过调用request.getSession(true).getAttribute(BasketBean.BASKET)来取回购物车的信息了。
  在JSP中表达式和小脚本为JSP动态生成网页提供一个强有力的工具。从下面的Inventory.jsp程序中可以看出,JSP代码段循环访问商品目录并且动态地为每个产品产生HTML表格,代码使用小脚本编写循环,然后在每一行中都混合使用HTML和JSP表达式。
  (注:JSP引擎把小脚本标记之间的Java代码直接插入引擎内部产生的servlet代码。JSP引擎对待JSP表达式也是不同的。它先把JSP表达式变换成字符串,然后在内部产生的servlet中把它们包入一个out.println()调用中。)

  b.Receipt.jsp代码段
  Receipt.jsp程序中,使用了JSP动作,来处理顾客发送来请求的参数值。因此本节将简要的介绍一下JSP中的动作元素。除了指令和脚本元素外,JSP动作也是JSP页面不可缺少的一部分,一个动作元素有两种基本的语法形式:
  <prefix:tag attr_list />
  <prefix:tag attr_list>
  <body>
  </prefix:tag>
  当动作有语句体时,必须使用后一种表式方法。动作背后基本的概念就是与特定的JSP标签联系的"标签处理器"。这些处理器是基于标签的一些代码段,用来执行某些操作。JSP引擎提供了一些标准的动作,所有的这些动作都要以" jsp "为前缀。例如,电子商店使用一个助手Bean来简化请求参数分析,就要使用<jsp:useBean>元素声明这样一个Bean:<jsp:useBean id="receiptBean" scope="request" class="shoppingcart.ReceiptBean" /> JSP声明了一个对象变量,取名为receiptBean,作为 ReceiptBean 的一个实例,在当前请求完成时就会被释放。使用Bean的主要优点就是它分析并且返回 HTML请求参数的简洁性。
  在声明完Bean以后,就可以使用<jsp:setProperty>元素从HTML请求中获取参数,来设置它的属性值。可以显式的指出属性和HTML 参数的名字,来设置属性值。例如,下面是Receipt.jsp中用来设置我们的ReceiptBean实例的属性的一些语句:
  <jsp:setProperty name="receipt_bean" property="name" param="name" />
  如果属性名和相应的参数名相同,可以指示用一个JSP元素来设置所有的属性:
  <jsp:setProperty name="receipt_bean" property="*" />
  这个单独的元素告诉引擎,使用 Java映像来匹配所有的JSP参数和JavaBean属性名,然后使用HTML请求信息中的值来设置JavaBean的属性值。同样,使用<jsp:getProperty>元素从助手Bean中返回属性值。例如,下面是返回属性的语句:
  <jsp:getProperty name="receipt_bean" property="name" />
  在ReceiptBean类的代码中,每个在Receipt.jsp中被分析的参数,在程序Bean中都有一个相关联的用来设置了取得的方法:例如,<jsp:setProperty name="receipt_bean" property="name" param="name" />有一个相关联的设置方法:void setName(String phone);
  同样,<jsp:getProperty name="receipt_bean" property="name" />也有一个相关联的取得方法:String getName()。

  c.Confirm.jsp代码段
  Confiormljsp主要用来让顾客确认自己购买的商品,并显示应付帐单,相对来说比较简单。

  d.Error.jsp代码段
  Error.jsp是一个通用的错误处理页面,当购物车程序任何不分出现错误时,系统都会自动跳跃到本页面来。



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics