<jsp:useBean>标签
<jsp:useBean>标签用于在某个指定的域范围(pageContext、request、session、application等)中查找一个指定名称的JavaBean对象,如果存在则直接返回该JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它按指定的名称存储在指定的域范围中。<jsp:useBean>标签的语法格式如下所示:
<jsp:useBean id="beanInstanceName" [scope="{page | request | session | application}"]
{
class="package.class" |
type="package.class" |
class="package.class" type="package.class" |
beanName="{package.class | <%= expression %>}" type="package.class"
} />
从上面的语法格式中可以看出,<jsp:useBean>标签中有5个属性,接下来就针对这5个属性进行讲解,具体如下:
● id:用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
● scope:用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application四个值中的一个,其默认值是page(关于域范围,请参看本教材7.4小节)
● type:用于指定JavaBean实例对象的引用变量类型,它必须是JavaBean对象的类名称、父类名称或JavaBean实现的接口名称。type属性的默认值为class属性的设置值,当JSP容器将<jsp:useBean>标签翻译成Servlet程序时,它将使用type属性值作为JavaBean对象引用变量的类型。
● class:用于指定JavaBean的完整类名(即必须带有包名),JSP容器将使用这个类名来创建JavaBean的实例对象或作为查找到的JavaBean对象的类型。
● beanName:用于指定JavaBean的名称,它的值也是a.b.c的形式,这既可以代表一个类的完整名称,也可以代表a/b/c.ser这样的资源文件。beanName属性值将被作为参数传递给java.beans.Beans类的instantiate()方法,创建出JavaBean的实例对象。需要注意的是,beanName属性值也可以为一个脚本表达式。
在使用<jsp:useBean>标签时,id属性必须指定,scope属性可以不用指定,如果没有指定scope属性,则会使用它的默认值page。而对于class、type、beanName这三个属性,它们的使用方式有四种,可以参看<jsp:useBean>标签语法格式的第3行到第6行。为了更好地理解这三个属性的作用,接下来对它们的四种使用方式分别进行讲解。具体如下:
1、单独使用class属性
由于<jsp:useBean>标签会用到JavaBean组件,因此在使用标签之前,首先在cn.itcast.chapter08.javabean包下创建两个JavaBean类Employee和Manager,Manager类继承自Employee类,这两个类具体如例1和2所示。
例1 Employee.java
1 package cn.itcast.chapter08.javabean;
2 public class Employee {
3 private String company;
4 public String getCompany() {
5 return company;
6 }
7 public void setCompany(String company) {
8 this.company = company;
9 }
10 }
例2 Manager.java
1 package cn.itcast.chapter08.javabean;
2 public class Manager extends Employee {
3 private double bonus;
4 public double getBonus() {
5 return bonus;
6 }
7 public void setBonus(double bonus) {
8 this.bonus = bonus;
9 }
10 }
然后,创建一个useBean.jsp文件,在文件中使用<jsp:useBean>标签,如例3所示。
例3 useBean.jsp
1 <%@ page language="java" pageEncoding="GBK"%>
2 <html>
3 <body>
4 <jsp:useBean id="manager" scope="page"
5 class="cn.itcast.chapter08.javabean.Manager" />
6 </body>
7 </html>
在例3中,使用了<jsp:useBean>标签,并设置了该标签的id、scope和class属性。为了了解这个标签中这三个属性的作用,在浏览器中访问useBean.jsp页面,然后在 <Tomcat安装目录>\work\Catalina\localhost\chapter08\org\apache\jsp目录下查看useBean.jsp文件翻译成的Servlet,可以看到<jsp:useBean>标签翻译成的Java代码如下所示:
......
cn.itcast.chapter08.javabean.Manager manager = null;
manager = (cn.itcast.chapter08.javabean.Manager) _jspx_page_context
.getAttribute("manager",javax.servlet.jsp.PageContext.PAGE_SCOPE);
if (manager == null) {
manager = new cn.itcast.chapter08.javabean.Manager();
_jspx_page_context.setAttribute("manager", manager,
javax.servlet.jsp.PageContext.PAGE_SCOPE);
}
......
从上面的代码可以看到,JSP容器首先定义一个引用变量manager,manager为class属性指定的类型,然后在scope属性指定的域范围中查找以manager为名称的JavaBean对象,如果该域范围中不存在指定JavaBean对象,JSP容器会创建class属性指定类型的JavaBean实例对象,并用变量manager引用。
需要特别注意的是,翻译成的Servlet代码中,用于引用JavaBean实例对象的变量名和JavaBean存储在域中的名称均为id属性设置的值manager。
2、单独使用type属性
将上面<jsp:useBean>标签中的class属性改成type属性,示例代码具体如下:
<jsp:useBean id="manager" scope="page"
type="cn.itcast.chapter08.javabean.Manager" />
刷新浏览器再次访问useBean.jsp页面,可以发现浏览器出现了500异常,如图1所示。
图1 运行结果
从图1中可以看出,发生异常的原因是manager这个JavaBean对象没有找到。为了找出发生异常的根源,我们仍然去<Tomcat安装目录>\work\Catalina\localhost\chapter08\org\apache\jsp目录下查看useBean.jsp文件翻译成的Servlet,可以看到<jsp:useBean>标签翻译成的Java代码如下所示:
…… ……
cn.itcast.chapter08.javabean.Manager manager = null;
manager = (cn.itcast.chapter08.javabean.Manager) _jspx_page_context
.getAttribute("manager",javax.servlet.jsp.PageContext.PAGE_SCOPE);
if (manager == null) {
throw new java.lang.InstantiationException("bean manager not found within scope");
}
…… ……
从上面的代码中可以看出,当只设置了type属性值时,JSP容器会在指定的域范围中查找以id属性值为名称的JavaBean对象,如果对象不存在,JSP容器不会创建新的JavaBean对象,而会抛出InstantiationException异常。了解了源代码,就不难理解在访问useBean.jsp页面时为什么会出现异常了。
为了解决这个问题,在<jsp:useBean>标签上面写一段JSP脚本片段,为pageContext域增加一个属性,属性的名称为“manager”,值为Manger对象。JSP脚本片段如下所示:
<%
pageContext.setAttribute("manager",new cn.itcast.chapter08.javabean.Manager());
%>
刷新浏览器再次访问useBean.jsp页面,发现页面浏览器页面中的异常消失了。
需要注意的是,<jsp:useBean>标签的type属性值还可以指定为JavaBean的父类或者由JavaBean实现的接口。下面对type属性的值进行修改,将其设置为“cn.itcast.chapter08.javabean.Employee”,访问useBean.jsp页面后,再次查看翻译的Servlet文件,可以看到<jsp:useBean>标签翻译成的Java代码如下所示:
…… ……
cn.itcast.chapter08.javabean.Employee manager = null;
manager = (cn.itcast.chapter08.javabean.Employee) _jspx_page_context
.getAttribute("manager",javax.servlet.jsp.PageContext.PAGE_SCOPE);
if (manager == null) {
throw new java.lang.InstantiationException("bean manager not found within scope");
}
…… ……
从上面的代码中可以看到,JSP容器将 Javabean引用变量的类型指定为type属性的值“cn.itcast.chapter08.javabean.Employee”,同时将从域范围中查找到的JavaBean也转换成了Employee类型。
3、class属性和type属性结合使用
由于type属性的默认值为class属性的设置值,也就是说在<jsp:useBean>标签中只要设置了class属性,
相当于设置了type属性的默认值,因此这种情况和第一种情况相同,这里就不再赘述了。
4、beanName属性和type属性的结合使用
将useBean.jsp页面中的JSP脚本片段去掉,并对<jsp:useBean>标签进行修改,使用id、beanName和
type属性,示例代码具体如下:
<jsp:useBean id="manager" beanName="cn.itcast.chapter08.javabean.Manager"
type="cn.itcast.chapter08.javabean.Manager" />
在浏览器中访问useBean.jsp页面,然后查看翻译的Servlet文件,可以看到<jsp:useBean>标签翻译成的Java代码如下所示:
…… ……
cn.itcast.chapter08.javabean.Employee manager = null;
manager = (cn.itcast.chapter08.javabean.Employee) _jspx_page_context
.getAttribute("manager",javax.servlet.jsp.PageContext.PAGE_SCOPE);
if (manager == null) {
try {
manager = (cn.itcast.chapter08.javabean.Employee) java.beans.Beans
.instantiate(this.getClass().getClassLoader(),
"cn.itcast.chapter08.javabean.Employee");
} catch (java.lang.ClassNotFoundException exc) {
throw new InstantiationException(exc.getMessage());
} catch (java.lang.Exception exc) {
throw new javax.servlet.ServletException(
"Cannot create bean of class "
+ "cn.itcast.chapter08.javabean.Employee",exc);
}
_jspx_page_context.setAttribute("manager", manager,
javax.servlet.jsp.PageContext.PAGE_SCOPE);
}
…… ……
从上面的代码中可以看到,JSP容器会在scope属性指定的域范围中查找以id属性值为名称的JavaBean对象,如果该域范围中不存在指定JavaBean对象,JSP容器会将加载当前类的对象和beanName属性值作为参数传递给java.beans.Beans类的instantiate()方法,去创建新的JavaBean实例对象,如果创建成功,JSP容器会将该对象以id属性值为名称存储到scope属性指定的域范围中。至于instantiate()方法如何创建JavaBean对象这里就不再讲解了,大家如果有兴趣可以自己去查看源代码。