|
在JSP页面中包含内容
在JSP页面中加入另一项Web资源有两种机制:include指令和jsp:include元素。
在将JSP页面转换为servlet类时对include指令进行处理。指令的效果是将包含在另一个文件中的文字(不管是静态内容还是其他JSP页面)插入到外围JSP页面中。可以使用include指令加入横幅内容、版权信息、或者任何可能希望在另一页面中反复使用的一些内容。include指令的语法如下:
<%@ include file="filename"
%>
例如,用下面的指令让所有书店应用程序页面加入包含了横幅内容的文件banner.jsp:
<%@ include file="banner.jsp"
%>
此外,页面bookstore.jsp、bookdetails.jsp和catalog.jsp用下面的指令加入了创建及销毁数据库bean的JSP元素:
<%@ include file="initdestroy.jsp"
%>
因为必须将include指令静态地加入每一个重复使用指令所引用资源的页面中,这种方法有其限制。用各段内容创建页面的更灵活方法参见模板标签库。
jsp:include元素是在JSP页面被执行时进行处理的。include行动让您可以在JSP文件中加入静态或者动态的资源。加入静态和动态资源的结果是相当不同的。如果资源是静态的,那么其内容就插入到调用JSP文件中。如果资源是动态的,那么向要加入的资源发送请求、执行要加入的页面,然后将结果加入到调用JSP页面的所返回的响应中。jsp:include元素的语法为:
<jsp:include page="includedPage"
/>
注:Tomcat不会重新加载修改过的静态待加入页面,除非要求加入资源的页面也被修改了。
在本章开始时介绍的date应用程序包括了用下列语句生成显示符合本地区习惯的时间的页面:
<jsp:include page="date.jsp"/>
将控件转换为其他Web组件
将控件转换为另一种Web组件的机制使用在将控件转换为其他Web组件中描述的Java Servlet API提供的功能。在JSP页面中用jsp:forward元素访问这些功能:
<jsp:forward page="/main.jsp" />
注意如果数据曾经返回给客户端,那么jsp:forward元素将会失败并报IllegalStateException。
jsp:param 元素
调用一个include或者forward元素时,会将原来的请求对象提供给目标页面。如果希望为这一页面提供其他的信息,可以用jsp:param元素向请求对象附加参数:
<jsp:include page="..." > <jsp:param name="param1" value="value1"/> </jsp:include>
加入Applet
可以在JSP页面中用jsp:plugin元素加入applet或者JavaBeans组件。该元素生成包含适合该客户端浏览器的结构(<object>或者<embed>)的HTML,这种结构可以在需要时下载Java插件软件和客户端组件,并执行任何客户端组件。jsp:plugin元素的语法如下:
<jsp:plugin
type="bean|applet"
code="objectCode"
codebase="objectCodebase"
{ align="alignment" }
{ archive="archiveList" }
{ height="height" }
{ hspace="hspace" }
{ jreversion="jreversion" }
{ name="componentName" }
{ vspace="vspace" }
{ width="width" }
{ nspluginurl="url" }
{ iepluginurl="url" } >
{ <jsp:params>
{ <jsp:param
name="paramName" value= paramValue" /> }+
</jsp:params>
}
{ <jsp:fallback>
arbitrary_text </jsp:fallback> }
</jsp:plugin>
jsp:plugin标签被<object>或者<embed>标签所替换,看哪种更适合适合请求的客户端。jsp:plugin标签的属性提供了元素表达的配置数据以及所需要插件的版本。nspluginurl和iepluginurl属性指定可以下载插件程序的URL。
jsp:param元素指定applet或者JavaBean组件的参数。jsp:fallback元素指定如果插件程序不能启动时(因为客户端不支持<object>或者<embed>,或者由于某种其他一些问题)客户端浏览器使用的内容。
如果插件程序可以启动,但是不能找到或者启动applet或者JavaBean组件,那么就会向客户端展示插件程序特定的消息,很可能是一个弹出窗口报告ClassNotFoundException。
负责创建横幅的Duke's Bookstore页面banner.jsp显示由DigitalClock生成的动态数字时钟:

图15-3 带Applet的Duke's Bookstore
用于下载applet的jsp:plugin元素如下:
<jsp:plugin
type="applet"
code="DigitalClock.class"
codebase="/bookstore2"
jreversion="1.3"
align="center"
height="25" width="300"
nspluginurl="http://java.sun.com/products/plugin/1.3.0_01
/plugin-install.html"
iepluginurl="http://java.sun.com/products/plugin/1.3.0_01
/jinstall-130_01-win32.cab#Version=1,3,0,1"
>
<jsp:params>
<jsp:param
name="language"
value="<%=request.getLocale().getLanguage()%>"
/>
<jsp:param
name="country"
value="<%=request.getLocale().getCountry()%>"
/>
<jsp:param
name="bgcolor" value="FFFFFF"
/>
<jsp:param
name="fgcolor" value="CC0066"
/>
</jsp:params>
<jsp:fallback>
<p>Unable
to start plugin.</p>
</jsp:fallback>
</jsp:plugin>
JSP页面中的JavaBeans组件
JavaBean组件就是可以方便地重复使用且结合到应用程序之中的Java类。所有遵循特定设计规范的Java类都可以成为JavaBean组件。
JavaServer
Pages技术直接支持在JSP语言元素中使用JavaBean组件。可以容易地创建并初始化bean并取得和设置它们的属性。本章提供了有关JavaBean组件和在JSP页面中访问JavaBean组件的JSP语言元素的基本信息。有关JavaBean组件模型的更多信息见http://java.sun.com/products/javabeans。
JavaBean组件设计规范
JavaBean组件设计规范负责管理类的属性以及管理提供对这些属性的访问的公共方法。
JavaBean组件属性可以是
·
读/写、只读、或者只写
·
Simple,意味着它包含一个值,或者indexed,意味着它表示值数组
不需要由实例变量实现属性,只能用符合特定规范的公共方法访问属性:
·
对于每一种可读的属性,bean必须有以下形式的方法
PropertyClass getProperty() { ... }
·
对于每一种可写的属性,bean必须有以下形式的方法
setProperty(PropertyClass pc) { ... }
除了属性方法,JavaBean组件必须定义一个没有参数的构造函数。
Duke's
Bookstore应用程序的JSP页面enter.jsp、bookdetails.jsp、catalog.jsp和showcart.jsp使用了database.BookDB和database.BookDetails JavaBean组件。BookDB提供了一个JavaBean组件前端,以便访问对象BookDBAO。面向Bean的自定义标签(见JSP页面中的自定义标签)广泛使用了这两个Bean。JSP页面BookDBAO和cashier.jsp使用cart.ShoppingCart以表示用户的购物车。
JSP页面catalog.jsp、showcart.jsp和cashier.jsp使用util.Currency
JavaBean组件将货币编排为地区敏感的格式。这个bean有两个可写的属性:locale和amount,还有一个可读属性format。format属性不对应于任何变量实例,但是返回locale和amount属性的函数。
public class Currency { private Locale locale; private double amount; public Currency() { locale = null; amount = 0.0; }
public void setLocale(Locale l) { locale = l; }
public void setAmount(double a) { amount = a; }
public String getFormat() { NumberFormat nf = NumberFormat.getCurrencyInstance(locale); return nf.format(amount); } }
为什么使用JavaBeans组件?
JSP页面可以在声明或者scriptlet中创建和使用所有类型的Java编程语言对象。下列scriptlet创建书店购物车并将它储存为一个会话属性:
<% ShoppingCart cart = (ShoppingCart)session. getAttribute("cart"); // If the user has no cart, create a new one if (cart == null) { cart = new ShoppingCart(); session.setAttribute("cart", cart); } %>
如果购物车对象符合JavaBean规范,那么JSP页面可以使用JSP元素来创建和访问这个对象。例如,Duke's Bookstore页面bookdetails.jsp、catalog.jsp和showcart.jsp用更简捷的JSP useBean元素替换scriptlet。
<jsp:useBean id="cart" class="cart.ShoppingCart" scope="session"/>
创建和使用JavaBeans组件
用下列格式之一声明JSP页面将使用JavaBean组件:
<jsp:useBean id="beanName" class="fully_qualified_classname" scope="scope"/>
或者
<jsp:useBean id="beanName" class="fully_qualified_classname" scope="scope"> <jsp:setProperty .../> </jsp:useBean>
在要包括jsp:setProperty语句时使用第二种格式初始化bean属性,下一节将描述这种语句。
jsp:useBean元素声明页面将使用储存在指定作用域并在特定作用域内可以访问的bean,这个作用域可以是application、session、或者page。如果这种bean不存在,那么语句就会创建一个bean并将它储存为scope对象的一个属性(见使用Scope对象)。id属性的值确定bean在作用域中的名字和用于在其他JSP元素和scriptlet中引用这个bean时使用的标识。
注:在JSP脚本元素中,我们提到必须导入JSP页面使用的所有类和包。如果类只被useBean元素引用,则这个规则稍有改变。在这种情况下,如果类是在未命名的包中,则必须只导入这个类。例如,在什么是JSP页面中,index.JSP页面导入MyLocales类。不过,在Duke's Bookstore示例中,所有类都包含在包中,因而不用显式导入。
下列元素在没有Currency元素实例的情况下创建它的一个实例,将它储存为session对象的属性,并通过标识currency使这个bean在整个会话中可用。
<jsp:useBean id="currency" class="util.Currency" scope="session"/>
设置JavaBeans组件属性
在JSP页面中有两种设置JavaBean组件属性的方法:用jsp:setProperty元素或者用一个scriptlet。
<% beanName.setPropName(value); %>
jsp:setProperty元素的语法取决于属性值的来源。表15-3总结了用jsp:setProperty元素设置JavaBean组件的不同方式。
|
表 15-3 设置JavaBeans组件属性 |
| 值来源 |
元素语法 |
| 字符串常量 |
<jsp:setProperty
name="beanName"
property="propName"
value="string constant"/>
|
| 请求参数 |
<jsp:setProperty
name="beanName"
property="propName"
param="paramName"/>
|
| 匹配bean属性的请求参数名 |
<jsp:setProperty
name="beanName"
property="propName"/>
<jsp:setProperty
name="beanName"
property="*"/>
|
| 表达式 |
<jsp:setProperty
name="beanName"
property="propName"
value="<%=
expression %>"/>
|
| |
1. beanName 必须与在useBean元素中的id属性指定的值相同。
2. 在JavaBean组件中必须有一个setPropName方法。
3. paramName 必须为一个请求参数名。 |
用常量字符串或者请求参数设置的属性必须有在表15-4中列出的类型。因为常量和请求参数都是字符串,所以Web容器会自动将值转换为属性的类型,所使用的转换在表中列出。String值可以用于将值赋予有PropertyEditor类的属性。在这种情况下,使用setAsText(String)方法。如果方法抛出一个IllegalArgumentException,则出现转换失败。指定给索引属性的值必须是一个数组,前面描述的规则也适用于这个元素。
|
表15-4 有效值赋值 |
| 属性类型 |
字符串值转换 |
| Bean属性 |
使用setAsText(string-literal) |
| boolean 或者 Boolean
|
如在java.lang.Boolean.valueOf(String) 中表明的 |
| Byte或者 Byte
|
如在java.lang.Byte.valueOf(String)中表明的 |
| char 或者 Character
|
如在java.lang.String.charAt(0)中表明的 |
| Double或者Double
|
如在java.lang.Double.valueOf(String)中表明的 |
| Int或者Integer
|
如在java.lang.Integer.valueOf(String)中表明的 |
| Float或者 Float
|
如在java.lang.Float.valueOf(String)中表明的 |
| Long或者Long
|
如在java.lang.Long.valueOf(String)中表明的 |
| Short或者Short
|
如在java.lang.Short.valueOf(String) 中表明的 |
| Object
|
new String(string-literal) |
使用运行时表达式设置其类型为复合Java编程语言类型的属性的值。回想在表达式中,JSP表达式用于将转换为String的脚本语言表达式的值插入返回给客户端的流中。在setProperty元素中使用时,表达式只是返回其值,不执行自动转换。结果,从表达式返回的类型必须匹配或者可以造型为属性的类型。
Duke's
Bookstore应用程序展示了如何用setProperty元素和scriptlet以设置数据库 helper bean为当前图书。例如,bookstore3/web/bookdetails.jsp使用表单:
<jsp:setProperty name="bookDB" property="bookId"/>
其中bookstore2/web/bookdetails.jsp使用表单:
<% bookDB.setBookId(bookId); %>
下面取自bookstore3/web/showcart.jsp的片段展示了如何用Locale对象以及由对请求时表达式的判断得到的数量来初始化当前bean。因为初次初始化是嵌入到useBean元素中的,所以只有在创建bean时才执行它。
<jsp:useBean id="currency" class="util.Currency" scope="session"> <jsp:setProperty name="currency" property="locale" value="<%= request.getLocale() %>"/> </jsp:useBean> <jsp:setProperty name="currency" property="amount" value="<%=cart.getTotal()%>"/>
获取JavaBeans组件属性
有几种获取JavaBean组件属性的方法。其中两种方法(jsp:getProperty元素和表达式)将属性的值转换为String并将该值插入当前隐式out对象:
·
<jsp:getProperty name="beanName" property="propName"/>
·
<%= beanName.getPropName() %>
对于这两种方法,beanName都必须与在useBean元素中的id属性所指定的相同,在JavaBean组件中必须有一个getPropName方法。
如果只需要获取属性的值而不转换它及将它插入到输出对象中,那么必须使用scriptlet:
<% Object o = beanName.getPropName(); %>
注意表达式和scriptlet之间的区别,表达式在开始的%之后有=,并且不像scriptlet那样用分号结束。
Duke's
Bookstore应用程序展示了如何使用这两种表单从currency bean中获取编排了格式的货币并将它插入页面中,例如bookstore3/web/showcart.jsp使用表单
<jsp:getProperty name="currency" property="format"/>
而bookstore2/web/showcart.jsp使用表单:
<%= currency.getFormat() %>
Duke's
Bookstore应用程序页面bookstore2/web/showcart.jsp使用下列scriptlet从购物车中提取图书数量并打开按条件插入文字的输出流:
<% // Print a summary of the shopping cart int num = cart.getNumberOfItems(); if (num > 0) { %>
尽管scriptlet对于动态处理非常有用,但是使用自定义标签( 见JSP页面中的自定义标签)访问对象属性和执行流程控制是更好的方法。例如,bookstore3/web/showcart.jsp用下列自定义标签替换了scriptlet:
<bean:define id="num" name="cart" property="numberOfItems" /> <logic:greaterThan name="num" value="0" >
图15-4总结了不同类型对象的储存位置以及如何从JSP页面中访问这些对象。用jsp:useBean标签创建的对象储存为scope对象的属性,并且可以用jsp:[get|set]Property标签和在scriptlet和表达式中访问。在声明和scriptlet中创建的对象储存为JSP页面的servlet类的变量,并且可以在scriptlet和表达式中访问。

图15-4
从JSP页面中访问对象
扩展JSP语言
可以将JavaBean组件和scriptlet一同使用执行各种不同的动态处理任务,包括访问数据库、使用企业级服务如电子邮件和目录、流程控制。不过,Scriptlet有一个缺点,就是它们一般会使JSP页面更难维护。另一方面,JSP技术提供了一种被称为自定义标签的机制,使您可以将动态功能封装到对象中,可以通过对JSP语言的扩展访问这些对象。自定义标签为JSP页面带来了另一层次上的组件化。
例如,回想在Duke's Bookstore书店购物车中循环并显示其内容的scriptlet:
<% Iterator i = cart.getItems().iterator(); while (i.hasNext()) { ShoppingCartItem item = (ShoppingCartItem)i.next(); ... %> <tr> <td align="right" bgcolor="#ffffff"> <%=item.getQuantity()%> </td> ... <% } %>
自定义标签iterate消除了这个代码逻辑,并管理在购物车中引用元素的脚本变量item:
<logic:iterate id="item" collection="<%=cart.getItems()%>"> <tr> <td align="right" bgcolor="#ffffff"> <%=item.getQuantity()%> </td> ... </logic:iterate>
自定义标签打包成标签库并以此形式发布。自定义标签的语法与JSP元素所使用的语法相同。即<prefix:tag>,不过对于自定义标签, prefix是由标签库的用户定义的,tag是由标签开发者定义的。JSP页面中的自定义标签解释了如何使用和开发自定义标签。
更多信息
有关JavaServer Pages技术的更多信息参见:
·
Web站点 http://java.sun.com/products/jsp中列出的资源。
·
有关JSP技术的语法和语义的完整描述参见JavaServer
Pages 1.2 Specification。
|