教 学 活 动 首 页
基 本 内 容 |
第 6 章 JSP 与 JavaBeans |
教学目的与要求:通过本章的学习让学生了解JavaBean 的概念;理解如何编写JavaBean和使用JavaBean;掌握JavaBean的存放目录,获取和修改 beans 的属性,beans 的辅助类,带包名的 beans;并能够JSP 与 JavaBeans结合完成简单应用。 |
教学内容: 6.1 编写和使用 JavaBeans 6.2 beans 的存放目录 6.3 获取和修改 beans 的属性 6.4 beans 的辅助类 6.5 带包名的 beans 6.6 JSP 与 beans 结合的简单例子 |
教学基本要求: 了解:JavaBean 的概念 理解:编写JavaBean,使用JavaBean 掌握:JavaBean的存放目录,获取和修改 beans 的属性,beans 的辅助类,带包名的 beans 应用:JSP 与 JavaBeans 的结合 |
教学重点教学难点: JavaBean的存放目录,获取和修改 beans 的属性,beans 的辅助类,带包名的 beans, JSP 与 JavaBeans 的结合 |
教学方法: 教学手段:多媒体教学和计算机程序演示 |
教学小结: (见教学进程) |
作业与思考:见课后习题 |
课后记载:
|
教 学 进 程
第6章 JSP与 JavaBeans 在谈论组件之前让我们看一个通俗的事情:组装电视机。组装一台电视机时,人们可以选择多个组件,例如电阻、电容、显象管等,一个组装电视机的人不必关心显象管是怎么研制的,只要根据说明书了解其中的属性和功能就可以了。不同的电视机可以安装相同的显象管,显象管的功能完全相同,但他们是在不同的电视机里面,一台电视机的显象管发生了故障并不影响其它的电视机;也可能两台电视安装了一个共享的组件:天线,如果天线发生了故障,两台电视机都受到同样的影响。 “可视化组件编程”非常成功的一个例子就是微软公司的VB。人们在使用VB编写程序时,经常把一个按钮组件或文本框组件拖放到你的应用程序窗体中,并了解这个按钮的名字、它有哪些功能、方法等,而且你还可以重新更改它的名字,当你创建生成应用程序时,这个按钮的名字被保存了下来。但是,微软的组件只适用于微软的操作平台上,不能为其它的平台所使用。 按着Sun公司的定义,JavaBeans是一个可重复使用的软件组件。实际上JavaBeans是一种Java类,通过封装属性和方法成为具有某种功能或者处理某个业务的对象,简称beans。由于javabeans是基于java语言的,因此javabeans不依赖平台,具有以下特点: 1.可以实现代码的重复利用 2.易编写、易维护、易使用 3.可以在任何安装了Java运行环境的平台上的使用,而不需要重新编译。 我们已经知道,一个基本的JSP页面就是由普通的HTML标签和java程序片组成,如果程序片和HTML大量交互在一起,就显得页面混杂,不易维护。JSP页面应当将数据的处理过程指派给一个或几个beans来完成,我们只需在JSP页面中调用这个beans即可。不提倡大量的数据处理都用java程序片来完成。在JSP页面中调用beans,可有效的分离的静态工作部分和动态工作部分。 6.1 编写javabeans和使用javabeans 6.1.1 编写beans Javabeans分为可视组件和非可视组件。在JSP中主要使用非可视组件。对于非可视组件,我们不必去设计它的外观,主要关心它的属性和方法。 编写javabeans就是编写一个java的类,所以你只要会写类就能编写一个beans,这个类创建的一个对象称做一个beans。为了能让使用这个beans的应用程序构建工具(比如JSP引擎)知道这个beans的属性和方法,只需在类的方法命名上遵守以下规则: 1.如果类的成员变量的名字是xxx,那么为了更改或获取成员变量的值,即更改或获取属性,在类中就需要有两个方法: l getXxx():用来获取属性xxx。 l setXxx():用来修改属性xxx。 2.对于boolean类型的成员变量,即布尔逻辑类型的属性,允许使用“is”代替上面的“get”和“set”。 3.类中的普通方法不适合上面的命名规则,但这个方法必须是public的。 4.类中如果有构造方法,那么这个构造方法也是public的并且是无参数的。 下面我们编写一个简单的beans,并说明在JSP中怎样使用这个beans。 Circle.java: import java.io.*; public class Circle { int radius; public Circle() { radius=1; } public int getRadius() { return radius; } public void setRadius(int newRadius) {radius=newRadius; } public double circleArea() {return Math.PI*radius*radius; } public double circlLength() {return 2.0*Math.PI*radius; } } 将上述java文件保存为Circle.java,并编译通过,得到字节码文件Circle.class。 6.1.2 使用beans 为了在JSP页面中使用benas,我们必须使用JSP动作标签:useBean useBean格式:
或
当服务器上某个含有useBean动作标签的JSP页面被加载执行时,JSP引擎将首先根据id的名字,在一个同步块中,查找JSP引擎内置pageContent对象中是否含有名字id和作用域scope的对象,如果这个对象存在,JSP引擎就分配一个这样的对象给客户,这样,客户就获得了一个作用域是scope、名字是id的beans(就像我们组装电视机时获得了一个有一定功能和使用范围的电子元件)。如果在pageContent中没有查找到指定作用域、名字是id的对象,就根据class指定的类创建一个名字是id对象,即创建了一个名字是id的beans,并添加到pageContent内置对象中,并指定该beans的作用域是scope,同时JSP引擎分配给客户一个作用域是scope、名字是id的beans。 下面就useBean标签中scope取值的不同情况阐述如下: l scope取值page JSP引擎分配给每个客户的beans是互不相同的,也就是说,尽管每个客户的beans的功能相同,但它们占有不同的内存空间。该beans的有效范围是当前页面,当客户离开这个页面时,JSP引擎取消分配给该客户的beans。 l scope取值session JSP引擎分配给每个客户的beans是互不相同的,该beans的有效范围是客户的会话期间,也就是说,如果客户在多个页面中相互连接,每个页面都含有一个useBeans标签,这些useBean标签中id的值相同,并且scope的值都是session,那么,该客户在这些页面得到的beans是相同的一个。如果客户在某个页面更改了这个beans的属性,其它页面的这个beans的属性也将发生同样的变化。当客户关闭浏览器时,JSP引擎取消分配给客户的beans。 l scope取值request JSP引擎分配给每个客户的beans是互不相同的,该beans的有效范围是request期间。客户在网站的访问期间可能请求过多个页面,如果这些页面含有socope取值是request的useBeans标签,那么pageCotent对象在每个页面分配给客户的beans也是互不相同的。JSP引擎对请求作出响应之后,取消分配给客户的这个beans。 l scope取值application JSP引擎为每个客户分配一个共享的beans,也就是说,所有客户共享这个beans,如果一个客户改变这个beans的某个属性的值,那么所有客户的这个beans的属性值都发生了变化。这个beans直到服务器关闭才被取消。 注:当使用作用域是session的beans时,要保证客户端支持Cooker. 为了使服务器的所有web服务目录下的JSP页面文件都能使用我们的beans,我们必须将上面编译通过生成的字节码类文件:Circle.class拷贝到JSP引擎的classes文件夹下,即D:tomcat\Jakarta-tomcat-4.0\classes下,如图6.1所示。 另外,在使用beans的JSP页面中,必须有如下的import指令: <@page import= “Circle”>
useBeans.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Circle"%>
<%--通过上述JSP标签,客户获得了一个作用域是page,名字是girl的beans --%> <% //设置圆的半径: girl.setRadius(100); %> 圆的半径是: <%=girl.getRadius()%> 圆的周长是: <%=girl.circlLength()%> 圆的面积是: <%=girl.circleArea()%> 在下面的例子2中我们将beans的scope的值设为session 创建的beans的名字是girl,创建该beans的类文件仍然是上述的Circle.class。在beans1.jsp 页面中,girl的半径radius的值是1(图6.3),然后连接到beans2.jsp页面,显示半径radius的值,然后将girl的半径radius的值更改为400(图6.4),当再刷新beans1.jsp时会发现radius的值已经变成了400(图6.5)。 例子2(效果如图6.3、6.4、6.5所示) beans1.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Circle"%>
圆的半径是: <%=girl.getRadius()%>
beans2.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Circle"%>
圆的半径是: <%=girl.getRadius()%> <%girl.setRadius(400);%> 修改后的圆的半径是: <%=girl.getRadius()%>
在下面的例子3中,将beans的scope的值设为application。当第一个客户访问这个页面时,显示beans的属性radius的值,然后把这个属性的值修改为1000(图6.6)。当其它客户访问这个网页时,看到的这个属性的值都是1000(图6.7)。 例子3(效果如图6.6、6.7所示) appbeans.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Circle"%>
圆的初始半径是: <%=girl.getRadius()%> <%girl.setRadius(1000);%> 修改后的圆的半径是: <%=girl.getRadius()%>
6.2 beans的存放目录 (1)任何web服务目录都可使用的beans的存放位置 如果让任何web服务目录中的JSP页面都可以使用某个beans,那么创建这个beans的字节码文件需存放在Tomcat安装目录的classes目录中,例如,本书所用机器的Tomcat安装目录就是:D:tomcat\Jakarta-tomcat-4.0\classes,如图6.1所示。 我们已经知道,当服务器上某个含有useBean动作标签的JSP页面被加载执行时,JSP引擎将首先根据id的名字,在一个同步块中,查找JSP引擎内置pageContent对象中是否含有名字id和作用域scope的对象,如果这个对象存在,JSP引擎就分配一个这样的对象给客户,这样,客户就获得了一个作用域是scope、名字是id的benas。如果在pageContent中没有查找到指定作用域、名字是id的对象,就根据class指定的类创建一个名字是id的对象,并添加到pageContent内置对象中,并指定该对象的作用域是scope,同时JSP引擎分配给客户一个作用域是scope、名字是id的beans。 JSP引擎的内置PageContenet对象用来存储供服务器使用的数据信息,通过该对象向客户提供不同类型的各种数据对象。当含有ussBeans标签的JSP页面被执行后,beans就被存放在pageContenet对象中,如果你更改了创建beans的java类文件后,pageContent对象中的beans并不能被更新,这是因为任何JSP页面再次被访问执行时,总是先到pageContenet中查找beans。而pageContent对象直到服务器关闭才释放它存储的数据对象。 (2)只对examples服务目录可用的beans的存放目录 examples是默认web服务目录之一,如图6.8 如果想让某个beans只对examples目录下的JSP页面可用,那么创建该beans的字节码文件需存放在webapps/example/Web-inf/classes目录中,如图6.8所示。 存放在该目录中的beans和存放在上面(1)中所述的目录中的beans有所不同的是:JSP引擎首先检查webapps/example/Web-inf/classes目录中的创建该beans的字节码文件是否被修改过,如果重新修改过,就会用新的字节码文件创建一个beans,beans的名字是id,并添加到pageContent内置对象中,并指定该对象的作用域是scope,同时JSP引擎分配给客户一个作用域是scope、名字是id的beans。 如果经常调试beans,可以把beans放在webapps/example/Web-inf/classes。需要注意的是,当用户请求服务时,由于服务器引擎每次都要检查字节码文件是否被修改过,将降低服务器的运行效率。 下面是创建beans的java文件,将该文件编译通过,把字节码文件CircleTest.class存放到/webapps/example/Web-inf/classes目录中。
import java.io.*; public class CircleTest { int radius; public CircleTest() { radius=6500; } public int getRadius() { return radius; } public void setRadius(int newRadius) {radius=newRadius; } public double circleArea() {return Math.PI*radius*radius; } public double circlLength() {return 2.0*Math.PI*radius; } } 下面的JSP页面useBeansTest.jsp存放在web服务目录examples中,该页面效果如图6.9。 UseBeansTest.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="CircleTest"%>
<%--通过上述JSP标签,客户获得了一个作用域是page,名字是girl的beans --%>
圆的半径是: <%=girl.getRadius()%>
重新设置圆的半径是100: <% girl.setRadius(100); %> 现在圆的半径是: <%=girl.getRadius()%> 圆的周长是: <%=girl.circlLength()%> 圆的面积是: <%=girl.circleArea()%>
6.3 获取和修改beans的属性 当我们使用useBean动作标签创建一个beans后,在java程序片中这个beans就可以调用方法产生行为,比如修改属性,使用类的中的方法等,如前面的例子1、2、3所示。获取或修改beans的属性还可以使用动作标签getProperty、setProperty,下面讲述怎样使用JSP的动作标签去获取和修改beans的属性。 6.3.1 getProperty动作标签 使用该标签可以获得beans的属性值,并将这个值用串的形式显示给客户。使用这个标签之前,必须使用useBean标签获取得到一个beans getProperty动作标签:
或
其中,name取值是beans的名字,用来指定要获取哪个beans的属性的值;property取值是该beans的一个属性的名字。该指令的作用相当于在程序片中使用beans调用getXxx()方法。 现在,我们将Circle类文件给予改进,增加circleArea和circleLength两个属性。
Circle2.java: import java.io.*; public class Circle2 { double radius=1; double circleArea=0; double circleLength=0; public double getRadius() { return radius; } public void setRadius(double newRadius) {radius=newRadius; } public double getCircleArea() {circleArea=Math.PI*radius*radius; return circleArea; } public double getCircleLength() { circleLength=2.0*Math.PI*radius; return circleLength; } }
在下面的JSP页面中使用useBean标签,用Circle2类创建一个名字是apple的beans。并使用getProperty获取apple的各个属性的值。把Circle2.java编译生成的字节码Circle2.class文件拷贝到JSP引擎的classes文件下。本书所使用的机器的该目录是: D:\tomcat\Jakarta-tomcat-4.0\classes
例子4(效果如图6.10所示) beansGetproperty.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Circle2"%>
<%apple.setRadius(100);%> 圆的半径是: 圆的面积是: 圆的周长是: 6.3.2 setProperty动作标签 使用该标签可以设置beans的属性值。使用这个标签之前,必须使用useBean标签得到一个可操作的beans。 setProperty动作标签可以通过3种方式设置beans属性的值。 (1)将benas属性的值设置为一个表达式的值或字符串。 这种方式不如后面的两种方式方便,但当涉及属性值是汉字时,使用这种方式更好一些。 benas属性的值设置为一个表达式的值:
benas属性的值设置为一个字符串:
如果将表达式的值设置为beans属性的值,表达式值的类型必须和beans的属性的类型一致。如果将字符串设置为beans的属性的值,这个字符串会自动被转化为beans的属性的类型。Java语言将字符串转化为其它数值类型的方法如下: l 转化到int :Integer.parseInt(Sting s), l 转化到long :Long.parseInt(Sting s), l 转化到float :Float.parseInt(Sting s), l 转化到double :Double.parseInt(Sting s), 这些方法都可能发生NumberFormatException异常,例如,当试图将字符串:“ab23”转化为int型数据时就发生了NumberFormatException。 在下面的例子中,我们写了一个描述学生的beans,在一个JSP页面中获得一个这样的beans,其有效范围是page。在JSP页面中使用动作标签设置、获取该beans的属性。
创建beans的源文件 Student.java: public class Student { String name=null; long number; double height,weight; public String getName() { return name; } public void setName(String newName) {name=newName; } public long getNumber() {return number; } public void setNumber(long newNumber) { number=newNumber; } public double getHeight() {return height; } public void setHeight(double newHeight) { height=newHeight; } public double getWeight() {return weight; } public void setWeight(double newWeight) { weight=newWeight; } } 例子5(效果如图6.11所示) student.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Student"%>
名字是: 学号是: <% double height=1.70; %> 身高是: 米 体重是: 公斤 (2)使用setProperty设置beans属性值的第2种方式是:通过HTTP表单的参数的值来设置beans的相应属性的值,要求表单参数名字必须与beans属性的名字相同,JSP引擎会自动将字符串转换为beans属性的类型。
该标签不用再具体指定beans属性的值将对应表单中哪个参数指定的值,系统会自动根据名字进行般配对应。 下面的例子6通过表单来指定beans的属性值。由于客户可能提交汉语的姓名,所以我们将Student.java文件中的getName方法做以下改进:
public String getName() { try {byte b[]=name.getBytes("ISO-8859-1"); name=new String(b); return name; } catch(Exception e) { return name; } }
例子6(效果如图6.12所示) student2.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Student"%> 名字是: 学号是: 身高是: 米 体重是: 公斤
注:需要注意的是,只有提交了和该beans相对应的表单后,该指令标签才被执行。 注:使用这种方式设置和获取beans的值很方便,我们把汉字的处理放在了beans中,但需要注意的是,如果使用第1种方式,不要在beans中处理汉字,而应当在JSP页面中处理。 (3)使用setProperty设置beans属性值的第3种方式是:通过request的参数的值来设置beans的相应属性的值,要求request参数名字必须与beans属性的名字相同,JSP引擎会自动将request获取的字符串数据类型转换为beans相应的属性的类型。
下面的例子7说明使用request参数设置beans的属性的值。 例子7(效果如图6.13所示) student3.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Student"%> 名字是: 学号是: <% double height=1.70; %> 身高是: 米 体重是: 公斤
注:不能在 6.4 beans的辅助类 通过上面的学习,我们已经知道怎样使用一个简单的beans。有时我们在写一个beans的时候,除了需要用import语句引入Java的内置包中的类,可能还需要其它自己写的一些类。那么你只要将这些类的字节码文件放在默认的classes目录中即可,本书配置的服务器的classes目录在: D:\Tomcat\jakarta-tomcat-4.0\classes 在下面的例子8中,我们使用一个beans:ListFile,列出JSP页面所在目录中特定扩展名的文件。在写beans的类文件ListFile时,我们需要一个实现FilenameFilter接口的辅助类:FileName,该类可以帮助我们的beans列出指定扩展名的文件。
创建beans的源文件 ListFile.java: import java.io.*; class FileName implements FilenameFilter { String str=null; FileName (String s) {str="."+s; } public boolean accept(File dir,String name) { return name.endsWith(str); } } public class ListFile { String extendsName=null; public void setExtendsName(String s) { extendsName=s; } public String getExtendsName() {return extendsName; } public String[] listFile() { File dir=new File("d:/Tomcat/Jakarta-tomcat-4.0/webapps/root/"); FileName file_jsp=new FileName(extendsName); String file_name[]=dir.list(file_jsp); return file_name; } } 上述java源文件编译通过后,会生成两个字节码文件:ListFile.class和FileName.class。我们需要将这两个字节码文件放在classes目录中。 注:也可以将上述的ListFile.java文件分为两个java文件:ListFile.java和FileNmae.java,然后,首先编译FileNmae.java,再编译ListFile.java,生成各自的字节码文件,然后将这两个字节码文件存放在classes目录中。 现在,就可以在JSP页面中使用FileList创建beans了。在下面的例子8中,客户通过表单设置beans的extendsName属性的值,beans列出相应扩展名的文件给客户。 例子8(效果如图6.14所示) listfile.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="ListFile" %> 6.6 JSP与beans结合的简单例子 6.6.1 三角形beans 三角形beans Triangle.java: public class Triangle { double sideA,sideB,sideC; double area; boolean triangle; public void setSideA(double a) {sideA=a; } public double getSideA() {return sideA; } public void setSideB(double b) {sideB=b; } public double getSideB() {return sideB; } public void setSideC(double c) {sideC=c; } public double getSideC() {return sideC; } public double getArea() { double p=(sideA+sideB+sideC)/2.0; area=Math.sqrt(p*(p-sideA)*(p-sideB)*(p-sideC)); return area; } public boolean isTriangle() { if(sideA triangle=true; else triangle=false; return triangle; } } 使用三角形beans的JSP页面(效果如图6.17所示) triangle.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Triangle"%> 6.6.2 计数器beans 计数器beans是一个application范围的beans,所有的客户共享这个beans,任何客户改变这个beans的属性值,都会对其它客户产生影响。计数器beans有一个记录访问次数的属性count。
Counter.java: public class Counter { long count=0; public synchronized long getCount() {count++; return count; } }
count.jsp:(效果如图6.18所示) <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="Counter"%> <% if(session.isNew()) { %>
您是第 位访问本站的人 <% } else { out.print("禁止通过刷新增加计数!"); } %>
6.6.3 购物车beans Car1.java: import java.util.*; import java.io.*; public class Car1 implements Serializable { Hashtable list=new Hashtable(); String item="Welcome!"; int mount=0; String unit=null; public void Car1() { } public void setItem(String newItem) { item=newItem; } public void setUnit(String newUnit) { unit=newUnit; } public void setMount(int m) { mount=m; } public void 添加商品到购物车() { String str="Name: "+item+" Mount:"+mount+" Unit:"+unit; list.put(item,str); } public Hashtable 列出购物车中的商品() { return list; } public void 删除货物(String s) { list.remove(s); } } 选择物品页面(效果如图6.19所示) car.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <%@ page import="Car1" %> 这里是第一百货商场,选择您要购买的商品添加到购物车: <% String str=response.encodeRedirectURL("add.jsp"); %> 您的购物车有如下商品: <% Hashtable list=car1.列出购物车中的商品(); Enumeration enum=list.elements(); while(enum.hasMoreElements()) { String goods=(String)enum.nextElement(); byte b[]=goods.getBytes("ISO-8859-1"); goods=new String(b); out.print(" } %> <% String str1=response.encodeRedirectURL("selectRemovedGoods.jsp"); %>
添加货物到购物车页面(效果如图6.20所示) add.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <%@ page import="Car1" %> <% car1.添加商品到购物车(); %> 您的购物车有如下商品: <% Hashtable list=car1.列出购物车中的商品(); Enumeration enum=list.elements(); while(enum.hasMoreElements()) { String goods=(String)enum.nextElement(); byte b[]=goods.getBytes("ISO-8859-1"); goods=new String(b); out.print(" } %> <% String str=response.encodeRedirectURL("car.jsp"); %> <% String str1=response.encodeRedirectURL("selectRemovedGoods.jsp"); %>
选择删除货物的页面(效果如图6.21所示) selectRemovedGoods.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <%@ page import="Car1" %> 选择从购物车删除的商品: <% String str=response.encodeRedirectURL("removeWork.jsp"); %>
您的购物车有如下商品: <% Hashtable list=car1.列出购物车中的商品(); Enumeration enum=list.elements(); while(enum.hasMoreElements()) { String goods=(String)enum.nextElement(); byte b[]=goods.getBytes("ISO-8859-1"); goods=new String(b); out.print(" } %> <% String str1=response.encodeRedirectURL("car.jsp"); %> 删除货物页面(效果如图6.22所示) removeWork.jsp: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.*" %> <%@ page import="Car1" %> <% String name=request.getParameter("deleteitem"); if(name==null) {name=""; } byte c[]=name.getBytes("ISO-8859-1"); name=new String(c); car1.删除货物(name); out.print("您删除了货物:"+name); %> 购物车中现在的货物: <% Hashtable list=car1.列出购物车中的商品(); Enumeration enum=list.elements(); while(enum.hasMoreElements()) { String goods=(String)enum.nextElement(); byte b[]=goods.getBytes("ISO-8859-1"); goods=new String(b); out.print(" } %> <% String str1=response.encodeRedirectURL("car.jsp"); %> <% String str=response.encodeRedirectURL("selectRemovedGoods.jsp"); %>
|