1. JavaBean简介
JavaBean是一种可重复使用且跨平台的软件组件。可分为两种:一种是又用户界面的JavaBean,还有一种没有用户界面,主要负责表示业务数据或者处理事务(如数据运算、操纵数据库)的JavaBean。JSP访问的通常是后一种JavaBean。
JSP与JavaBean搭配使用的好处:
- 使得HTML与Java程序分离,这样便于维护代码。如果把所有的程序代码都写到JSP网页中,会使得代码繁杂、难以维护。
- 可以降低对开发JSP网页的人员的java编程能力的要求。
- JSP侧重于生成动态网页,事务处理由JavaBean来完成,这样可以充分利用JavaBean组件的可重用性特点,提高开发网站的的效率。
一个标准的JavaBean有以下特性:
- JavaBean是一个公共的(public)类。
- JavaBean有一个不带参数的构造方法。
- JavaBean通过get()方法获取属性,通过set()方法设置属性。
- 属性名和get/set方法名之间存在着固定的对应关系:如果属性名为xyz,那么get/set方法名为getXyz/setXyz,属性名中的第一个字母在方法名中大写。
- 如果希望JavaBean能被持久化,那么可以使它实现java.io.Serializable接口。5.2章的例程ShoppingCart类就属于JavaBean,它实现了Serializable接口,因此当Servlet容器持久化一个会话时,也会对存放在其中是ShoppingCart对象进行持久化。
- 在JavaBean中除了定义get和set方法,也可以像普通Java类一样定义其他完成特定功能的方法。
以下是一个JavaBean的例子,类名为CounterBean,在该类中定义了一个属性count,还定义了访问这个属性的get/set方法。注意,Bean要放在命名包里,不可以放在默认包里,否则无法被JSP文件引用。
CounterBean.java
package mypack;
public class CounterBean {
private int count;
public CounterBean(){}
public int getCount(){
return count;
}
public void setCount(int count) {
this.count = count;
}
}
2. JSP访问JavaBean的语法
在JSP网页中既可以通过程序代码来访问JavaBean,也可以通过特定的JSP标签访问JavaBean。采用后一中方法可以减少JSP网页中的程序代码,使它更接近HTML页面。使用JSP标签访问JavaBean的方法如下:
1) 导入Javabean类
如果在JSP网页中访问JavaBean,首先要通过<%@ page import=""%>指令来引入JavaBean类:
<%@ page import="CounterBean" %>
2) 声明JavaBean对象
<jsp:useBean>标签用来声明JavaBean对象:
<jsp:useBean id="myBean" class="CounterBean" scope="session"/>
上述代码声明了一个名字为myBean的JavaBean对象。该标签具有以下属性:
- id属性:代表JavaBean对象的ID,实际上表示引用JavaBean对象的局部变量名,以及存放在特定范围的属性名。JSP规范要求存放在所有范围内的JavaBean对象都有唯一的ID。例如不允许在会话范围内存在两个ID为“myBean”的JavaBean,也不允许在会话范围内核请求范围内分别存在ID为“myBean”的JavaBean。
- class属性:用来指定Javabean的类名。
- scope属性:用来指定JavaBean对象的存放范围,可选值包括page(页面范围)、request(请求范围)、session(会话范围)和application(Web应用范围)。scope属性的默认值是page,范例中的scope属性取值为session,表示会话范围.
以上示范代码中的<jsp:useBean>标签的处理流程如下:
- 定义一个名为myBean的局部变量。
- 尝试从scope指定的会话范围内读取名为myBean的属性,并且使得myBean局部变量引用具体的属性值,即CounterBean对象。
- 如果scope指定的会话范围内,名为“myBean”的属性不存在,那么久通过CounterBean类的默认构造方法创建一个CounterBean对象,并把它存放在会话范围内,令其属性名为"myBean",此外,myBean局部变量也引用该对象。
以上<jsp:useBean>标签和以下Java程序片段的作用是等价的:
CounterBean myBean = null;
//试图从会话范围内读取myBean属性
myBean = (CounterBean)session.getAttribute("myBean");
if (myBean == null){
myBean = new CounterBean();
session.setAttribute("myBean",myBean);
}
可以看到,<jsp:useBean>标签在形式上比Java程序片段简洁多了。
3) 访问JavaBean属性
JSP提供了访问JavaBean属性的标签,如果要将JavaBean的某个属性输出到网页上,可以用<jsp:getProperty>标签:
<jsp:getProperty name="myBean" property="count" />
以上标签根据name属性的值"myBean"找到又<jsp:useBean>标签声明的ID为"myBean"的CounterBean对象,然后打印它的count属性。它等价于: <%=myBean.getCount()%>程序片段。
Servlet容器在运行该标签时,会根据property指定的属性名,自动调用JavaBean的相应的get方法。属性名和get方法名之间存在固定的对应关系,在第一节javaBean特性中已经提到。范例中的CounterBean的属性名为count,那么对应的get方法就是getCount()。加入在CounterBean类中不存在getCount()方法,那么Servlet容器在运行<jsp:getProperty>标签时就会抛出异常。因此开发人员创建的JavaBean类必须严格遵守JavaBean的规范。
如果要给JavaBean的某个属性赋值,可以用<jsp:setProperty>标签,例如:
<jsp:setProperty name="myBean" property="count" value="1"/>
需要注意的是,如果一个JSP文件通过<jsp:setProperty>或<jsp:getProperty>标签访问一个JavaBean的属性,要求该JSP文件先通过<jsp:useBean>标签声明这个JavaBean,否则<jsp:setProperty>和<jsp:getProperty>运行时就会抛出异常。
3. JavaBean的范围
<jsp:useBean>标签中可以设置JavaBean的scope属性,它决定了JavaBean对象存在的范围。下面用访问CounterBean的4个JSP例子来演示4种范围的特性和区别。
1) 页面(page)范围内的JavaBean
页面范围对应的时间段为:从客户请求访问一个JSP文件开始,到这个JSP文件执行结束。在pageCounter1.jsp中声明了一个存放在页面范围内的CounterBean,每次当客户请求访问pageCounter1.jsp时,<jsp:useBean>比起哦爱你都会创建一个CounterBean对象,并把它存放在页面范围内,该CounterBean对象在两种情况下会结束生命周期:
- 客户请求访问当前pageCounter1.jsp页面执行完毕,接着通过<jsp:forward>标记将请求转发到另一个Web组件。
- 客户请求访问的当前pageCounter1.jsp页面执行完毕并向客户端发送响应。
由此可见,页面范围内的JavaBean对象只在当前爱你JSP页面中有效。加入pageCounter1.jsp把请求转发给pageCounter2.jsp,那么pageCounter2.jsp是无法访问到pageCounter1.jsp页面范围内的JavaBean对象的。
pageCounter1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="myPageBean" class="mypack.CounterBean" scope="page"/>
<html><head><title>pageCounter</title></head>
<body>
<jsp:setProperty name="myPageBean" property="count" value="<%=myPageBean.getCount()+1 %>"/>
Current count value is :<jsp:getProperty name="myPageBean" property="count"/>
<%
String scopeNames[] = {"No Scope","page","request","session","application"};
int scope = pageContext.getAttributesScope("myPageBean");
%>
<p>scope = <%=scopeNames[scope]%></p>
</body>
</html>
运行Web应用,通过浏览器多次访问pageCounter1.jsp,会看到CounterBean对象的count属性的值始终为1.客户端每次访问pageCounter1.jsp,服务器端都会创建新的CounterBean对象,并把它存放在当前页面范围内。count属性的初始值为0,接下来<jsp:setProperty>标签把count属性的值增加1.等到pageCounter1.jsp完成了对本次客户端请求的响应,这个CounterBean对象就结束生命周期。
现在,修改pageCounter1.jsp文件,在文件末尾把请求转发给pageCounter2.jsp:
<jsp:forward page="pageCounter2.jsp"/>
pageCounter2.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>pageCounter</title>
</head>
<body>
<jsp:useBean id="myPageBean" scope="page" class="mypack.CounterBean"/>
Current count value is :<jsp:getProperty name="myPageBean" property="count"/>
</body>
</html>
该JSP页面也在页面范围内声明了一个名为myPageBean的CounterBean对象,然后打印它的count属性。
下一步,运行应用,通过浏览器访问地址:localhost:8080/pageCounter1.jsp,pageCounter1.jsp把请求转发给pageCounter2.jsp,浏览器端最后得到pageCounter2.jsp的打印结果:
pageCounter2.jsp页面范围和pageCounter1.jsp的页面范围各自独立。当客户请求被转发给2的时候,1的页面范围内的CounterBean对象就结束生命周期,接下来pageCounter2.jsp创建一个CounterBean对象,并把它存放在自己的当前页面范围内。CounterBean对象的count属性的初始值为0 。
2) 请求(request)范围内的JavaBean
请求范围对应的时间段为:从客户请求访问一个JSP文件开始,到这个JSP文件返回响应结果结束,如果这个JSP文件把请求转发给其他Web组件,那么直到其他Web组件返回响应结果结束。
对于请求范围内的javaBean对象,它存在于响应一个客户请求的整个过程中。当所有共享同一个客户请求的JSP文件执行完毕并向客户端返回响应时,本次请求范围内的JavaBean对象结束生命周期。在JSP文件中声明的request范围内的javaBean对象,它可以被一下Web组件共享:
- 该JSP文件本身。
- 和该JSP文件共享同一个客户请求(即HttpServletRequest对象)的Web组件,包括该JSP文件通过<%@ include>指令或<jsp:include>标记包含的其他Web组件,以及通过<jsp:forward>标记转发的其他目标Web组件。
请求范围内的javaBean对象实际上是作为属性保存在HttpServletRequest对象中的,其属性名和JavaBean对象的ID相同,属性值为JavaBean对象,因此也可以通过HttpServletRequest.getAttribute()方法来读取请求范围内的JavaBean对象:
CounterBean obj = (CounterBean)request.getAttribute("nyRequestBean");
3) 会话(session)范围内的JavaBean
会话范围对应整个会话的生存周期,处于同一个会话中的Web组件共享这个会话范围内的JavaBean对象。
会话范围内的JavaBean对象实际上是作为属性保存在HttpSession对象(在JSP固定饮用为session)中的,和request类似。
4) Web应用(application)范围内的JavaBean
Web应用范围对应整个Web应用的生存周期,处于同一个Web应用中的所有Web组件共享这个Web应用范围内的JavaBean对象。
Web应用范围内的JavaBean对象实际上是作为属性保存在ServletContext对象(在JSP固定饮用为application)中的,和request类似。