一. 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"
}
{
/> |
> other elements </jsp:useBean>
}
二. JSP动作元素useBean使用示例:
<jsp:useBean id="cart" scope="session" class="session.Carts" />
<jsp:setProperty name="cart" property="*" />
<jsp:useBean id="checking" scope="session" class="bank.Checking" >
<jsp:setProperty name="checking" property="balance" value="0.0" />
</jsp:useBean>
三. JSP动作元素useBean执行步骤:
<jsp:useBean>元素用来定位或初始化一个JavaBeans组件。<jsp:useBean>首
先会尝试定位Bean实例,如果其不存在,则会依据class名称(class属性指定)或序
列化模板(beanName属性指定)进行实例化。
进行定位或初始化Bean对象时,<jsp:useBean>按照以下步骤执行。
步骤1: 尝试在scope属性指定的作用域使用你指定的名称(id属性值)定位Bean对
象;
步骤2: 使用你指定的名称(id属性值)定义一个引用类型变量;
步骤3: 假如找到Bean对象,将其引用给步骤2定义的变量。假如你指定类型(type
属性),赋予该Bean对象该类型;
步骤4: 假如没找到,则实例化一个新的Bean对象,并将其引用给步骤2定义的变
量。假如该类名(由beanName属性指定的类名)代表的是一个序列化模
板(serialized template),该Bean对象由java.beans.Beans.instantiate初始
化;
步骤5: 假如<jsp:useBean>此次是实例化Bean对象而不是定位Bean对象,且它有体
标记(body tags)或元素(位于<jsp:useBean>和</jsp:useBean>之间的内容,则执
行该体标记。
<jsp:useBean>和</jsp:useBean>之间经常包含<jsp:setProperty>,用来设置该
Bean的属性值。正如步骤5所描述的,该元素仅在<jsp:useBean>实例化Bean对象时
处理。假如Bean对象早已存在,<jsp:useBean>是定位到它,则体标记毫无用处。
我们可以使用<jsp:useBean>元素来定位或实例化一个JavaBean对象,但不能是
EJB。对于EJB,我们可以通过创建自定义标记来直接调用彧采用其它方式。
四. <jsp:useBean>元素各属性解析:
1. id="beanInstanceName"
一个用来标识你指定作用域的变量。可以在JSP文件的表达式或脚本小应
用程序中使用该变量名称。
该名称大小写敏感,必须符合JSP页面中脚本语言的命名规则。假如你使
用的是Java语言,则该名称遵守的是Java命名规范。假如该Bean对象已由
其它<jsp:useBean>元素创建,则该值必须和实例化该Bean对象
的<jsp:useBean>元素id属性值一致,才能实现定位到该Bean对象。
2. scope="page | request | session | application"
Bean对象存在的作用范围,默认值为 page. 不同作用域解释如下:
1) page: 你可以在<jsp:useBean>元素所在JSP页面或其静态包含页面使
用该JavaBean对象,直到该页面发送响应回客户端或跳转(forwards)至其
它页面。
2) request: 你可以在处理同一个请求的任意一个页面使用该JavaBean对
象,直到该页面发送响应回客户端或产生新的请求。你可以使用request
对象访问该JavaBean对象,示例:
request.getAttribute(beanInstanceName).
3) session: 你可以在同一次会话的任意一个页面使用该JavaBean对象,该
JavaBean对象在整个会话期间一直存在。使用<jsp:useBean/>创建JavaBean对象的
页面的<%@page %>指令元素的session属性值必须设置为true;
4) application: 你可以在创建该JavaBean对象的同一个应用的任意一个页面
使用该JavaBean对象,该JavaBean对象在整个应用期间一直存在。应用中任意一个
页面均可使用它。
3. class="package.class"
从一个class实例化Bean对象,使用new关键字调用class的构造方法完
成。
该 class 必须不能是抽象,必须有一个 public、无参的构造器。包名和
类名称大小写敏感。
4. type="package.class"
用来指定该Bean对象的数据类型,假如既没有指定 class 或 beanBean, 没
有Bean对象能被实例化。包和类名称大小写敏感。
5. class="package.class" type="package.class"
使用class属性指定的类实例化JavaBean对象,并声明其数据类型为type
属性指定的类型;type属性值可和class属性值同,或为其超类、接口。
class属性中所指定类名称必须不能为抽象的,必须包含有public,无参的
构造方法。class和type属性所指定的包名,类名均大小写敏感。
6. beanName="{package.class | <%= expression %>}" type="package.class"
使用java.beans.Beans.instantiate方法实例化beanName属性指定的类或序列
化模板对应的Bean对象,赋予JavaBean对象type属性指定的数据类型。
Beans.instantiate方法会检查beanName属性指定的名称是类名称还是序列化模板
的名称。假如该JavaBean对象已被序列化,则Beans.instantiate使用类加载器读
取序列化的内容,更多信息可参考JavaBeans.
beanName属性值要么是一个完整类名,要么是一个可以转化为完整类名的表达式。
用来传给Beans.instantiate方法。type属性值可和beanName属性值同,或为其超
类、接口。
beanName和type属性所指定的包名,类名均大小写敏感。
五. JSP动作元素useBean使用剖析:
对于<jsp:useBean>执行步骤的理解,我们可以通过阅读JSP转化成的Servlet源码
完成。以下给出二段示意代码, 可参阅之前步骤进行深化理解:
1) 通过beanName指定要实例化的JavaBean类名:
JSP源码 :
------------------------------------
-------
<jsp:useBean id="u" type="bean.User" beanName="bean.User"/>
JSP转译成Servlet的源码 :
------------------------------------
-------
bean.User u = null;
synchronized (_jspx_page_context) {
u = (bean.User) _jspx_page_context.getAttribute("u",
PageContext.PAGE_SCOPE);
if (u == null){
try {
u = (bean.User)
java.beans.Beans.instantiate(this.getClass().getClassLoader(),
"bean.User");
} catch (ClassNotFoundException exc) {
throw new InstantiationException(exc.getMessage());
} catch (Exception exc) {
throw new ServletException("Cannot create bean of class " +
"bean.User", exc);
}
_jspx_page_context.setAttribute("u", u,
PageContext.PAGE_SCOPE);
}
}
2) 通过class指定要实例化的JavaBean类名:
JSP源码 :
------------------------------------
-------
<jsp:useBean id="u" type="bean.User" class="bean.User"/>
JSP转译成Servlet的源码 :
------------------------------------
-------
bean.User u = null;
synchronized (_jspx_page_context) {
u = (bean.User) _jspx_page_context.getAttribute("u",
PageContext.PAGE_SCOPE);
if (u == null){
u = new bean.User();
_jspx_page_context.setAttribute("u", u,
PageContext.PAGE_SCOPE);
}
}
六. 注意几点:
1) class或beanName不能同时存在;它们用来指定实例化的类名称或序列化模板;
如果确信JavaBean对象已存在,class和beanName属性均可无须指定, 可只须指定
type属性。
2) class可以省去type独自存在,beanName必须和type一起使用;
3) class指定的是类名,beanName指定的是类名或序列化模板的名称;
4) class指定的类名必须包含public、无参的构造方法;在对象已实例化时,
beanName指定的名称可以为其接口、父类;
5) 如果JavaBean对象已存在,<jsp:useBean>只是用来定位JavaBean,则只需使用
type属性即可,class和beanName这时舍去不影响使用。
6) class或beanName指定的类名必须包括包名称,type可以省去包名,通过<%
@page import=""%>指定所属包亦可。
7) class通过new创建JavaBean对象;beanName通过
java.beans.Beans.instantiate初始化JavaBean对象。
page指令的属性:
language:jsp页面采用的语言,只有Java,默认为java
extends:jsp页面产生的Servlet继承的父类
import:导入包,多个包用逗号隔开
session:是否使用Session,默认值为true
buffer:指定输出流缓存大小,默认8kb
autoFlush:自动刷新缓冲区,默认为true
isThreadSafe:是否线程安全(是否能处理多个线程的同步请求)
info:指定jsp页面的相关信息
errorPage:指定出错时跳转的错误页面
contentType:指定MIME类型
isErrorPage:指定当前页面是否为错误处理页面,不能与errorPage同时为true
pageEncoding:页面编码,如”UTF-8″,”GBK”,默认为”"ISO-8859-1″.
page指令不能用于被jsp:include包含的文件,可以在同一页面中多次使用page指令,但是同一属性只能出现一次,除import外。
范围:在JSP中设置一个页的属性范围,必须通过pageContext完成。
例:
<body>
//在同一个页面中,我们设置他得值
<%
pageContext.setAttribute("name", "姓名");
pageContext.setAttribute("QQ", "1234567");
%>
//则在同一个页面中,我们取得到他的值:
<%
String name = (String) pageContext.getAttribute("name");
String QQ = (String) pageContext.getAttribute("QQ");
%>
<h1>
<%=name%>
</h1>
<h1>
<%=QQ%>
</h1>
</body>
好了,在这里强调一个重要概念:
默认情况下,表示一个页面的保存范围,我们是用pageContext的。
但实际上,四种属性范围,都是通过pageContext对象完成的。
pageContext对象的补充:
JSP中如果要想设置一个page范围的属性则一定使用pageContext对象,实际上对于整个JSP代码,所有的四种属性范围都是可以通过pageContext对象进行设置的,因为在此对象中的设置属性方法有两个:
public void setAttribute(String name,Object attribute) 设置的属性默认为page范围
public void setAttribute(String name,Object o,int scope) 可以指定属性的范围
|- 在PageContext类中提供了以下几个常量:
|- 表示page范围:public static final int PAGE_SCOPE
|- 表示request范围:public static final int REQUEST_SCOPE
|- 表示session范围:public static final int SESSION_SCOPE
|- 表示application范围:public static final int APPLICATION_SCOPE
下面通过pageContext对象设置一个request范围的属性
RequestScopeDemo04.jsp:
<%@page contentType="text/html;charset=GBK"%>
<%@page import="java.util.*"%>
<%
// 设置两个属性
pageContext.setAttribute("uname","HELLO",PageContext.REQUEST_SCOPE) ;
pageContext.setAttribute("udate",new Date(),PageContext.REQUEST_SCOPE) ;
%>
<jsp:forward page="RequestScopeDemo02.jsp"/>
这样在访问RequestScopeDemo04.jsp,跳转到RequestScopeDemo02.jsp之后,同样会得到同样的输出。
<jsp:useBean>标签用来在jsp页面中创建一个Bean实例,定义语法如下:
一:<jsp:useBean>语法
<jsp:useBean id="id" scope="page|request|session|application" typeSpec/>
二:<jsp:setProperty>语法
<jsp:setProperty name="beanName" propertyDetail />其中,propertyDetail可以是以下中的一个:
1,property="*"
2,property="propertyName" param="parameterName"
3,property="propertyName"
4,property="propertyName" value="property value"
三:<jsp:getProperty>语法
<jsp:getProperty name="beanName" property="propertyName"/>
程序例子:
一共有三个文件:TestBean.java,register.jsp,register.html
TestBean.java
register.html
register.jsp
一个tag就是一个普通的java类,它惟一特别之处是它必须继承TagSupport或者BodyTagSupport类。这两个类提供了一些方法,负责jsp页面和你编写的类之间的交互,例如输入,输出。而这两个类是由jsp容器提供的,无须开发人员自己实现。换句话说,你只需把实现了业务逻辑的类继承TagSupport或者BodyTagSupport,再做一些特别的工作,你的类就是一个Tag。并且它自己负责和jsp 页面的交互,不用你多操心。 “特别的工作”通常有以下几个步骤: [1]提供属性的set方法,此后这个属性就可以在jsp页面设置。以jstl标签为例 c:out value=""/,这个value就是jsp数据到tag之间的入口。所以tag里面必须有一个setValue方法,具体的属性可以不叫value。例如setValue(String data){this.data = data;} [2]处理 doStartTag 或 doEndTag 。这两个方法是 TagSupport提供的。 还是以c:out value=""/为例,当jsp解析这个标签的时候,在“<”处触发 doStartTag 事件,在“>”时触发 doEndTag 事件。通常在 doStartTag 里进行初始化,流程选择操作,在 doEndTag 里后续页面输出控制。 通常你会发现自己绝大多数活动都集中在 doStartTag 或 doEndTag方法里,如果在服务器端处理标签中的正文或则是嵌套标签时的话,还是过问一下doAfterBody。 package test; public class OutputTag extends TagSupport { 简要说明: 编写tld 在WEB-INF下新建tlds文件夹,把这个文件取名为test.tld,放到tlds文件夹下。引用时的路径应该这样:WEB-INF\tlds\test.tld 关于tld的简单说明: <%@ page language="java"%> 启动服务器,如果一切按照上面步骤的话,就能看到 Test Tag: Hello! TEST 字样。最简单的tag就这么出来了。并不难,是不是? |
文章出处:http://book.csdn.net/bookfiles/230/10023010778.shtml 定制标签是为JSP定义新功能而创建的JSP标签。例如,假定有一个名为<temp:F>的定制标签,它将摄氏温度值转换为华氏温度值。可以在JSP中这样使用它: 这段代码显示为: 虽然这个简单例子展示了什么是定制标签,但在实际情况下,可以列出定制标签有用的很多理由。 l 因为它们大大削减了JSP中的代码重复,所以促进了代码复用。 l 因为可以避免使用scriptlet,所以它们使得JSP变得更具有可维护性。 l 因为它们消除了对更难读写的scriptlet的需要,所以它们的使用也简化了Web设计人员的工作。 l 它们是用来贯彻“关注点分离”原则(见第1章)的一个主要工具。大部分Web应用框架,包括Struts和JavaServer Faces,都基于这一理由来使用定制标签。 因为Struts广泛地使用了定制标签,所以理解如何创建和使用定制标签对于用好Struts会有莫大帮助。 4.1 定制标签基础 标签具有一个在JSP页面中定义的前缀(在前述的例子中,前缀是temp)和一个标签名(在前一例子中,是F),它们都是固定在标签的TLD(标签库描述文件)文件中的。 标签能够被用在JSP中之前,它必须在页面的开始处进行声明。例如,对于<temp:F>标签,其声明可能是: 我们将会在下一节分析这个声明。现在,只需注意到前缀是在JSP中被定义的即可。 注意 标签的前缀用来避免标签名字冲突。比如,如果必须通过相同的名字使用两个不同的标签(来自于不同的标签库),就可以给它们赋以不同的前缀,以示区别。因此,前缀具有很强的灵活性,甚至可以在每一个单独的JSP中分别定义它们。另一方面,标签名是不能随意改变的,它是在标签库描述文件中定义的。 标签也可能具有属性,例如: 最后,多个标签可以归集到一起,放入一个TLD文件之内,这也是该文件为何叫标签库描述文件的原因。我们接下来看一看典型的标签生命周期。 4.2 如何处理定制标签 假如有一个带有一个定制标签的JSP文件。它是如何转换为我们在屏幕上面看到的文本的?其实,当servlet容器第一次解析JSP的时候,它遇到定制标签,例如: servlet容器就会期待并且寻找JSP页面中对应的taglib声明。例如: 在JSP中可能有多个这样类似的taglib声明。servlet通过匹配标签的前缀和taglib声明中的prefix属性来决定使用哪一个声明,如代码清单4-1所示。 代码清单4-1 具有taglib声明和定制标签的示例JSP taglib声明只是简单地将一个前缀和一个URI(统一资源标识符)相联系,这里的URI是标签的TLD文件的逻辑路径。uri属性是逻辑性的,而不是实际路径,因为它指向的是标准的servlet配置文件web.xml中特定的配置项,而不是硬盘驱动器上的某个位置。 web.xml文件必须包含被uri属性指定的标签库的真实位置。在这里,web.xml中的相关信息被配置在一个<taglib>标签之中(见代码清单4-2)。 代码清单4-2 web.xml中的taglib配置 代码清单4-2中需要注意的是: l taglib-uri必须匹配在给定JSP文件中的taglib中声明的uri属性。 l taglib-location必须包含TLD文件实际的相对路径。在前一个例子中,TLD文件是struts-bean.tld。 TLD文件的物理位置总是相对于Web应用程序的WAR文件的根目录(或者相对于servlet容器中webapps目录下的Web应用程序子目录)。因此,在代码清单4-2中,我们会看到TLD文件位于WEB-INF文件夹中,名为struts-bean.tld。 最后,TLD文件只是一份包含了描述库中标签之元数据的XML文档。这些元数据是: l 标签的名称(在代码清单4-1中标签名称是write)。 l 标签的可选的和必需的属性,以及来自代码清单4-1中的属性。 l 处理标签的属性和主体部分以产生输出的Java处理器类。这些Java类通常被打包到Web应用程序的WEB-INF\lib文件夹的一个JAR文件中。 我们将会在实验课程中详细讨论TLD文件的核心细节。图4-1总结了定制标签的处理流程。 在最后一个步骤中,servlet容器调用Java标签处理器类中的特定函数,而该处理器类负责处理定制标签的输出。 可见,甚至最简单的定制标签的处理流程也稍微有些棘手。建议你重复阅读这一节,直到能够确信已掌握了所有细节之后再继续往下阅读。 图4-1 定制标签的处理流程 4.3 Java标签处理器类 把定制标签的主体和属性转变成HTML代码的实际工作,是由必须要实现的Java标签处理器类来完成的。 处理器类可以子类化一个或者两个基类,这取决于标签的需求。 如果定制标签没有主体部分,那么可以子类化javax.servlet.jsp.tagext.TagSupport。这个基础处理器类表达了没有主体的定制标签,但是它可能会有属性。 如果定制标签具有主体,那么必须子类化javax.servlet.jsp.tagext.BodyTagSupport。当然,使用BodyTagSupport并不意味着当它们在JSP中使用的时候,必须要有一个主体。实际上,必须实现一个额外的处理功能来处理标签的主体部分。 为简单起见,在接下来的内容中我们会主要关注BodyTagSupport。 注意 我在这里稍微歪曲了一下事实。事实上,不管定制标签是否有一个主体部分,都能子类化BodyTagSupport或TagSupport。只不过,BodyTagSupport有额外的方法能够让用户可以方便地读取标签的主体。TagSupport就没有这种能力。但是这种方便是有代价的,因为servlet容器必须做些额外工作而且要使用更多内存。这就解释了为什么定制标签没有主体部分的时候应该子类化TagSupport,且只是在必要的时候才使用BodyTagSupport。 还有一个额外的函数是doAfterBody(),它是在servlet容器读进标签的主体部分之后被调用的。这一函数也在读取标签主体部分时进行所有必要的处理,并且显示输出。标签必须返回一个名为EVAL_PAGE的标记,该标记是在BodyTagSupport中定义的。这个标记告诉servlet容器继续处理页面的其他部分。 标签处理器类必须满足的另一个需求是,它们必须具有与标签所支持的属性(attribute)相对应的getXXX和setXXX函数。 注意 换句话说,除了作为BodyTagSupport或者TagSupport的子类之外,处理器类还须是一个JavaBean,具有与标签所支持的属性(attribute)相对应的属性(property)。 例如,在代码清单4-1中,通过查看<bean:write>标签,就能推断出对应的Java处理器类具有函数getProperty()和setProperty()。代码清单4-3展示了这个原则。 代码清单4-3 <bean:write>标签的Java处理器类的部分代码 当包含了标签的JSP被载入后,servlet容器便调用所有必需的setXXX()函数,以便标签中的属性能够被标签的Java代码访问。再次以<bean:write>标签为例,在运行时,可以调用getProperty()函数,或者查看_property来读取<bean:write>标签的property属性值。 4.4 辅助类 为了使Java处理器类能做些有用的事情,比如读取一个标签主体部分的内容,或者写标签的输出,必须要了解两个辅助类。 第一个是javax.servlet.jsp.tagext.BodyContent,可以用它来读取标签的主体以及其他东西。函数getString()将标签的主体返回为一个字符串(假定它有一个主体)。如果已经子类化了BodyTagSupport,就可以通过调用在BodyTagSupport基类中已经实现的函数来得到一个BodyContent实例。 BodyContent也会给出一个Writer实例,通过它,可以写出标签经过转换后的主体部分的输出。调用BodyContent实例上的getEnclosingWriter()函数将会给出一个Writer的子类——明确地说,它是javax.servlet.jsp.JSPWriter的一个子类。 为了看清所有这些是如何工作的,请考虑一个简单的<message:write>标签,可以这样使用它: 我们需要将消息“Hello World!”显示为特定的字体颜色——在这里是红色。一个Java处理器类就实现了这个功能,如代码清单4-4所示。 代码清单4-4 <message:write>处理器类的实现 4.5 TLD文件 定制标签拼图中的最后一块是TLD(标签库描述符)文件。创建的每个标签都必须在一个TLD文件中声明,而且这一文件还必须连同标签的Java处理器类一起被部署。正如在前一节中所看到的,servlet容器知道在何处放置了TLD文件,因为已经在web.xml标准servlet配置文件中声明了路径。 注意 这一节主要是作为参考。如果你已经心痒痒地想要编写自己的定制标签,可以跳过这一节而继续实验4。 请看一下声明了先前开发的<message:write>标签的TLD文件,如代码清单4-5所示。 代码清单4-5 声明 <message:write>的TLD文件 可以看到,TLD文件只不过是一个XML文件。根标签是<taglib>,它包含一个或者多个<tag>标签,该元素用来声明定制标签。表4-1、表4-2和表4-3解释了TLD中的每个标签。注意每个<taglib>都必须包含一个或者多个<tag>声明。 表 4-1 TLD文件中的标签 标 签
标 签
标 签
4.6 实验4:温度转换标签 在这个实验中,将会创建、部署和测试一个进行温度转换的定制标签。下面是一些主要需求规格: l 标签库将只包含一个名为convert的标签,该标签有一个可选的属性。 l 可选属性to指示需要转换到的温度单位。 l 默认情况下,to属性的值是华氏温度。 l 转换是从摄氏温度到华氏温度或者开氏温度。 注意 在生产实现中,最好包括一些错误报告机制。 例如,下面的代码将100摄氏度转换为212华氏度: 而下面这些代码则将100摄氏度转换为373开氏度: 为了创建这个标签,必须做到以下几点: (1) 准备开发目录和脚本; (2) 编写Java标签处理器类; (3) 编写TLD文件来描述标签; (4) 编写JSP来测试定制标签; (5) 修改web.xml来注册TLD文件; (6) 将应用程序安装到Tomcat中。 4.6.1 步骤1:准备开发环境和脚本 (1) 在硬盘合适的地方创建一个Struts目录。 (2) 复制www.apress.com上的lab4.zip文件到这个Struts目录。 (3) 解压,请确保保留了原来的目录结构。 (4) 应该能够看到.\Struts\lab4\子目录。 (5) 在文本编辑器中打开.\Struts\lab4\compile.bat文件,并且修改PATH环境变量以便它指向JDK安装位置。 注意 在Windows XP、Windows ME或者Windows 2000中,系统内置了解压能力,但是系统解压的文件可能会加上一个额外的lab4目录到被解压的路径中。所以,compile.bat文件的路径可能变成是.\Struts\lab4\lab4\compile.bat。可以将文件夹向上移动,或者就放在那儿。编译脚本也能够正确运行。 单击compile.bat测试修改结果。应该不会得到任何错误,并且能够在.\Struts\lab4\目录中看到一个lab4.war文件。 接下来,我们提及的所有路径都是相对于.\Struts\lab4\的。 4.6.2 步骤2:编写Java标签处理器 (1) 在文本编辑器中打开文件.\src\Converter.java。 (2) 添加一个私有的字符串变量_to。这将对应于定制标签的to属性。 (3) 创建一个getTo()和setTo()方法来获得和设置_to的值。servlet容器将使用这些方法来通过属性(attribute)to的值获得/设置属性(property)_to的值。 (4) 完成doAfterBody()方法,使用上面所属的需求规格。需要使用辅助类来做这些工作(详见代码清单4-4)。 (5) 注意doAfterBody()必须返回整数值的标记EVAL_PAGE来指示JSP页面的剩余部分是否需要继续处理。 (6) 单击compile.bat进行编译工作。 4.6.3 步骤3:编写标签库描述文件 (1) 在文本编辑器中打开.\web\WEB-INF\lab4-converter.tld文件。 (2) 这是一个空的TLD文件,只包含强制的样板文件。在样板之后创建一个根<taglib>... </taglib>元素。 (3) 在<taglib>元素之内,插入一个适当的标签定义,把代码清单4-5作为一个参考。 4.6.4 步骤4:修改web.xml web.xml是一个标准的servlet配置文件。每个Web应用程序,甚至空的Web应用程序都必须要有自己的web.xml文件。 注意 如果将TLD文件放到WEB-INF目录中,实际上完全不必在web.xml中声明它们。但是,为了完整起见,我们会这样做。 (1) 在文本编辑器中打开.\web\WEB-INF\web.xml文件。注意web目录仅存在于开发时。compile.bat脚本会将整个WEB-INF目录上移,并且删除web文件夹。 (2) web.xml文件包含了样板文本,后面跟了一个<webapp>标签。将代码清单4-6所示的标签插入<webapp>元素封装标签之内。 代码清单4-6 插入到web.xml的代码 注意 请注意在代码清单4-6中,路径分隔符是UNIX风格的斜线(/),而不是Windows风格的反斜线(\)。 4.6.5 步骤5:编写JSP (1) 在文本编辑器中打开文件.\web\test.jsp。 (2) 在JSP中加入定制标签库的taglib声明。记住使用在web.xml中定义的URI。 (3) 放入相应的标签代码来测试convert标签。至少应该测试一下在本实验开头所给出的全部例子。 4.6.6 步骤6:部署和测试 (1) 如果Tomcat在运行,请停止它。 (2) 单击compile.bat。这将编译源代码,并且产生一个WAR文件lab4.war。 (3) 将WAR文件拖到Tomcat的webapps目录中。记住,如果想要重新部署lab4应用,必须删除在webapps目录下的原有子目录。 (4) 启动Tomcat。使用http://localhost:8080/lab4/进行测试工作。 如果在某处被卡住了,你可能想要参考本实验的答案。可以在www.apress.com上的lab4-answers.zip文件中找到答案。 |
<%@ taglib uri="http://jsptags.com/tags/navigation/pager" prefix="pg" %>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="/WEB-INF/tld/c.tld" prefix="c"%> <%@ taglib uri="http://jsptags.com/tags/navigation/pager" prefix="pg" %> <html> <head></head> <body> <pg:pager url="/PageAction.do" index="half-full" maxPageItems = "3" maxIndexPages="5" isOffset = "<%=false%>" export = "pageOffset,currentPageNumber=pageNumber" scope = "request"> <table> <c:forEach items="${userlist}" var="user"> <pg:item> <tr> <td height="39">${user.userId}</td> <td height="39">${user.username}</td> <td height="39">${user.password}</td> </tr> </pg:item> </c:forEach> </table> <pg:index> <center> <table border=0 cellpadding=0 width=10% cellspacing=0> <tr align=center valign=top> <td valign=bottom><font face=arial,sans-serif size=-1>Result Page: </font></td> <pg:prev ifnull="true"> <% if (pageUrl != null) { %> <td align=right><A HREF="<%= pageUrl %>"><IMG SRC=http://www.google.com/nav_previous.gif alt="" border=0><br> <b>Previous</b></A></td> <% } else { %> <td><IMG SRC=http://www.google.com/nav_first.gif alt="" border=0></td> <% } %> </pg:prev> <pg:pages> <% if (pageNumber == currentPageNumber) { %> <td><IMG SRC=http://www.google.com/nav_current.gif alt=""><br> <font color=#A90A08><%=pageNumber%></font></td> <% } else { %> <td><A HREF="<%=pageUrl%>"><IMG SRC=http://www.google.com/nav_page.gif alt="" border=0><br> <%= pageNumber %></A></td> <% } %> </pg:pages> <pg:next ifnull="true"> <% if (pageUrl != null) { %> <td><A HREF="<%=pageUrl%>"><IMG SRC=http://www.google.com/nav_next.gif alt="" border=0><br> <b>Next</b></A></td> <% } else { %> <td><IMG SRC=http://www.google.com/nav_last.gif alt="" border=0></td> <% } %> </pg:next> </tr> </table> </center> </pg:index> </pg:pager> </body></html>
<pg:pager items="${totalRows} " url="/PageAction.do?pagesize=5"
<pg:pager items="${totalRows}" url="/PageAction.do"maxIndexPages="5"> <pg:param name=" pagesize " value="5" />另外由于不需要在页面分页所在<pg:param>要去调
<pg:pager items="${ totalRows }" url="/PageAction.do" index="half-full" maxPageItems = "5" maxIndexPages="10" isOffset = "<%=false%>" export = "pageOffset,currentPageNumber=pageNumber" scope = "request"> <pg:param name="pagesize" value="5" /> <table align="center"> <c:forEach items="${userlist}" var="user"> <!--pg:item--> <tr> <td height="39">${user.userId}</td> <td height="39">${user.username}</td> <td height="39">${user.password}</td> </tr> <!--/pg:item--> </c:forEach> </table> <pg:index> <center> <table border=0 cellpadding=0 width=10% cellspacing=0> <tr align=center valign=top> <td valign=bottom><font face=arial,sans-serif size=-1>Result Page: </font></td> <pg:prev ifnull="true"> <% if (pageUrl != null) { %> <td align=right><A HREF="<%=pageUrl%>&pageNo=<%=pageNumber%>"><IMG SRC=http://www.google.com/nav_previous.gif alt="" border=0><br> <b>Previous</b></A></td> <% } else { %> <td><IMG SRC=http://www.google.com/nav_first.gif alt="" border=0></td> <% } %> </pg:prev> <pg:pages> <% if (pageNumber == currentPageNumber) { %> <td><IMG SRC=http://www.google.com/nav_current.gif alt=""><br> <font color=#A90A08><%= pageNumber %></font></td> <% } else { %> <td><A HREF="<%=pageUrl%>&pageNo=<%=pageNumber%>"><IMG SRC=http://www.google.com/nav_page.gif alt="" border=0><br> <%=pageNumber%></A></td> <% } %> </pg:pages> <pg:next ifnull="true"> <% if (pageUrl != null) { %> <td><A HREF="<%=pageUrl%>&pageNo=<%=pageNumber%>"><IMG SRC=http://www.google.com/nav_next.gif alt="" border=0><br> <b>Next</b></A></td> <% } else { %> <td><IMG SRC=http://www.google.com/nav_last.gif alt="" border=0></td> <% } %> </pg:next> </tr> </table> </center> </pg:index> </pg:pager>
getRequestDispatcher
这是javax.servlet.ServletRequest下的一个public成员函数。
episode:
一看就明白,这是用来传递request的,可以一个Servlet接收request请求,另一个Servlet用这个request请求来产生response。request传递的请求,response是客户端返回的信息。forward要在response到达客户端之前调用,也就是 before response body output has been flushed。如果不是的话,它会报出异常。 例:
The included servlet cannot change the response status code or set headers; any attempt to make a change is ignored.这个是用来记录保留request和response,以后不能再修改response里表示状态的信息了,如http head呀,其实保留这个有什么用呢,........thinking........... ok,继续我们的正题。getRequestDispatcher(String)可以得到一个RequestDispatcher对象,那我们就可以用它来动态的调用我们想要的调用的Servlet,jsp等;而参数String,就是那个你要调用的Servlet或JSP的名称,它可以是相对路径(如前例),也可以是绝对路径,如果你在前面加上“/”。 |