6.5.4 <jsp:useBean>标签
<jsp:useBean>标签用于在指定的范围(pageContext、request、session和application)中查找一个指定名称的Java对象,如果在指定的范围存在该对象,则<jsp:userBean>标签直接返回该对象的引用,否则创建一个新的对象,并将这个新对象存储在指定的范围。
<jsp:useBean>标签的id属性用来指定对象名,class属性用来指定要查找或创建的对象所对应的类名。scope属性用来指定搜索范围。该属性可以接受如下四个值:
l page:表示<s:useBean>标签将从PageContext对象中搜索指定的对象,或将新创建的对象存储在PageContext对象中。page是scope属性的默认值。
2 request:表示<s:useBean>标签将从ServletRequest对象中搜索指定的对象,或将新创建的对象存储在ServletRequest对象中。
3 session:表示<s:useBean>标签将从HttpSession对象中搜索指定的对象,或将新创建的对象存储在HttpSession对象中。
4 application:表示<s:useBean>标签将从ServletContext对象中搜索指定的对象,或将新创建的对象存储在ServletContext对象中。
下面的代码使用Java代码将一个java.util.Date对象保存在request对象中,并通过<s:useBean>标签来读取该对象,最后输出该对象。
<!-- usebean.jsp -->
<%@ page language="java" pageEncoding="UTF-8"%>
<%
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.set(2001, 2,1);
request.setAttribute("myDate", calendar.getTime());
%>
<jsp:useBean id="myDate" scope="request" class="java.util.Date"/>
<%
out.println(myDate);
%>
访问usebean.jsp页面,在浏览器中将输出如下的信息:
Thu Mar 01 13:19:14 CST 2001
在上面的输出信息中,时间是当天的时间,而日期是使用Calendar.set方法设置的日期。从而可以断定,<jsp:useBean>返回的对象实例是保存在request对象中的对象。如果读者将保存在request对象中的myDate对象改成其他的名,<jsp:useBean>标签就会由于未找到相应的对象,而创建一个新的java.util.Date对象,从而输出当天的日期和时间。
查看由JSP生成的Servlet源代码可知,<jsp:useBean>标签被翻译成了如下的Java代码:
java.util.Date myDate = null;
synchronized (request)
{
myDate = (java.util.Date) _jspx_page_context.getAttribute("myDate",
PageContext.REQUEST_SCOPE);
if (myDate == null)
{
myDate = new java.util.Date();
_jspx_page_context.setAttribute("myDate", myDate,PageContext.REQUEST_SCOPE);
}
}
从上面的代码可以看出,生成的Java代码对request对象进行了同步,这是为了防止由于多个用户请求同时访问request对象而产生脏数据。
在同步块中的第一条语句就是使用getAttribute方法从request域中寻找myDate对象,如果未找到,则使用new java.util.Date()创建一个新的Date对象,将将其保存在request域中。
在上面的代码中,不仅可以将myDate声明成java.util.Date类型,而且也可以将myDate声明成java.util.Date的父类或java.util.Date类实现的接口。如java.lang.Object类是所有Java类的父类,为了将myDate声明成java.lang.Object,需要使用<jsp:useBean>标签的type属性。代码如下:
<jsp:useBean id="myDate" scope="request" class="java.util.Date" type="java.lang.Object"/>
上面的代码翻译成的Java代码如下:
java.lang.Object myDate = null;
synchronized (request)
{
myDate = (java.lang.Object) _jspx_page_context.getAttribute("myDate",
PageContext.REQUEST_SCOPE);
if (myDate == null)
{
myDate = new java.util.Date();
_jspx_page_context.setAttribute("myDate", myDate,PageContext.REQUEST_SCOPE);
}
}
可以看出上面的代码中的myDate被声明成了java.lang.Object。
除了class属性外,也可以使用beanName属性指定Java Bean名。该属性和class属性的功能类似,只是使用beanName属性指定Java Bean名时,使用了java.beans.Beans.instantiate方法动态建立了对象实例。
下面的JSP代码使用beanName属性来指定Java Bean名:
<jsp:useBean id="myDate" scope="request" beanName="java.util.Date" type="java.lang.Object"/>
上面的代码被翻译成如下的Java代码:
java.lang.Object myDate = null;
synchronized (request)
{
myDate = (java.lang.Object) _jspx_page_context.getAttribute("myDate",
PageContext.REQUEST_SCOPE);
if (myDate == null)
{
try
{
myDate = (java.lang.Object) java.beans.Beans.instantiate(this.getClass().getClassLoader(), "java.util.Date");
}
catch (ClassNotFoundException exc)
{
throw new InstantiationException(exc.getMessage());
}
catch (Exception exc)
{
throw new ServletException("Cannot create bean of class " + "java.util.Date", exc);
}
_jspx_page_context.setAttribute("myDate", myDate,
PageContext.REQUEST_SCOPE);
}
}
在上面的代码中使用了java.beans.Beans.instantiate方法创建了java.util.Date对象实例。
beanName除了可能使用普通字符串指定Java Bean名,还可以通过JSP表达式或EL来指定Java Bean名。
<jsp:useBean>标签完成的语法格式如下:
<jsp:useBean id = "name" scope = "page | request | session | application" typeSpec/>
typeSpec ::= class="className" |
class="className" type="typeName" |
type="typeName" class="className" |
beanName="beanName" type=”typeName” |
type="typeName" beanName="beanName" |
type="typeName"
beanName ::= package.class | <%= expression %> | EL
<jsp:useBean>标签还可以有标签体,如下面的代码所示:
<jsp:useBean id = "myDate" class = "java.util.Date">
useBean的标签体
</jsp:useBean>
只有当<s:useBean>标签创建对象实例时,才会执行标签体的内容。如果<jsp:useBean>从指定范围中获得对象实例,则标签体部分将被忽略。对于上面的代码,则于<jsp:useBean>标签的默认搜索范围是page,而page在每次刷新页面时都是新创建的,因此,在每次访问上面的代码时,都会显示<jsp:useBean>标签的标签体。如果scope属性值是session或application,由于第一次创建新对象后,将该对象保存在session或application中,而再次访问该页面时,如果是在同一个会话中(对于session域来说),或是应用程序未重新发布(对于application域来说),上回保存的对象仍然存在,因此就会忽略标签体部分。
综上所述,在使用<jsp:useBean>标签时应注意如下几点:
l 如果指定了class属性,而未指定type属性,则type属性的默认值是class属性的值。
2 如果指定了beanName属性,必须指定type属性。
3 class和beanName属性不能同时使用。
4 class或beanName指定的Java Bean必须有一个无参数的构造方法。