【文章标题】自定义标签学习笔记
【文章作者】曾健生
【作者邮箱】 zengjiansheng1@126.com
【作者 QQ 】 190678908
【作者声明】本人水平有限,失误之处,敬请各位指出。
*******************************************************************************
首先对 JSP 中标签的各个基本概念作个基本的介绍,一个典型的标签如下图所示:
图 1
由上图可知,一个典型的标签一共有三部分:
1. 标签
2. 属性
3. 标签体
如果要在 JSP 页面上使用标签,还必须在网页中导入相应的标签,如图 1 的导入语句为
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
要实现自定义标签,其核心就是编写标签处理器类,一个标签对于一个处理器类,一个标签库可包含多个标签处理器。标签处理器类要实现 JspTag 接口,该接口没有任何方法,主要是用于 Tag 和 SimpleTag 的父接口。
在 JSP2.0 后,实现了一种新的处理器类规范称为简单标签,主要实现了 SimpleTag 接口。
下面分别对一个自定义标签的重要部分进行说明:
一.标签
这是一个最简单的自定义标签的例子: <newjueqi:hellotag/>
在 JSP 页面中执行完这个标签后在控制台输出语句“ hello ”,实现这个自定义标签分为以下 4 步:
1. 定义标签处理器类 , 需要实现 SimpleTag 接口,使用时会自动 调用 doTag 方法。
完成后的函数如下:
@Override
public void doTag() throws JspException, IOException {
// 在控制台上输出 “hello”
System. out .println( "hello" );
}
2. 创建一个 tld(tag library desctiptor) 文件 , 因为该描述文件是自定义标签的描述文件 , 所以该文件要放在 WEB-INF 下 .
编写完成后 mytag.tld 的文件如下:
<!-- 2. 创建一个 tld(tag library desctiptor) 文件 -->
< taglib xmlns = "http://java.sun.com/xml/ns/j2ee"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version = "2.0" >
<!-- 对 tld 文件的描述 -->
< description > mytag 0.2 core library </ description >
< display-name > mytag core </ display-name >
< tlib-version > 0.2 </ tlib-version >
<!-- 当前 tld 文件被 JSP 引用时建议的前缀 -->
< short-name > newjueqi </ short-name >
<!-- 标识当前 tld 文件的 uri, 不能够与其他 tld 文件的 uri 节点重复 , 因为在 Jsp 页面可以通过该标识来应用当前的 tld 文件 -->
< uri > http://newjueqi.javaeye.com/mytag </ uri >
<!-- 配置一个自定义标签 -->
< tag >
<!-- 指定自定义标签的名字 -->
< name > hellotag </ name >
<!-- 指定当前标签关联的 Java 类 -->
< tag-class > newjueqi.cn.javaeye.HelloTag </ tag-class >
<!-- 指定标签体的类型 : empty 代表标签体为空 -->
< body-content > empty </ body-content >
</ tag >
</ taglib >
3. 使用 taglib 指令导入标签 : <%@ taglib uri="" prefix="" %> 在 JSP 页面导入 tld 文件 . prefix 指定当前 tld 文件的引用前缀 , uri 标识指向哪个 tld 文件
本例的语句为: <%@ taglib uri="http://newjueqi.javaeye.com/mytag" prefix="newjueqi" %>
4. 使用自定义标签 : < 前缀 (3 中的 prefix): 标签名 (2 中的 name) />
正如: <newjueqi:hellotag/>
二.在自定义标签中定义属性
1. 在标签处理器类设置相关的属性,并定义相应的 set 方法。
在这个例子中有两个属性,分别为 num_1 和 num_2 ,在类中的定义如下:
private int num_1 ;
private int num_2 ;
public void setNum_1( int num_1) {
this . num_1 = num_1;
}
public void setNum_2( int num_2) {
this . num_2 = num_2;
}
2. 定义在 doTag 函数中定义相关的操作:
public void doTag() throws JspException, IOException {
// 记录两个数中的最大值
int maxNum= num_1 ;
if ( num_1 > num_2 )
{
maxNum= num_1 ;
}
else
{
maxNum= num_2 ;
}
System. out .println( maxNum );
}
3. 在 tld 文件中的 <tag> 标签中增加以下内容:
< attribute >
<!-- 定义属性的名字 , 该属性名称和标签处理器中定义的属性名字相对应 -->
< name > num_1 </ name >
<!-- 定义该属性是否为必须 ( 是否为可选 ) -->
< required > true </ required >
<!-- 该属性值是否可以接受动态表达式的值 : run time expression value (r t expr value) -->
< rtexprvalue > true </ rtexprvalue >
</ attribute >
< attribute >
<!-- 定义属性的名字 , 该属性名称和标签处理器中定义的属性名字相对应 -->
< name > num_2 </ name >
<!-- 定义该属性是否为必须 ( 是否为可选 ) -->
< required > true </ required >
<!-- 该属性值是否可以接受动态表达式的值 : run time expression value (r t expr value) -->
< rtexprvalue > true </ rtexprvalue >
</ attribute >
4. 使用带属性的自定义标签
本例为: <newjueqi:maxNum num_1="4" num_2="6"/>
在控制台上输出: 6
三.自定义标签的标签体
实现了一个最简单的带标签体的自定义标签,如下:
< newjueqi:showhelloonscreen >
hello
</ newjueqi:showhelloonscreen >
执行结果式在网页上输出字符串“ hello ”,注意是在网页上输出, 不是在控制台上
1. 在 tld 文件的 <tag> 标签中定义属性:
<body-content> :指定标签体的类型。可能取值有 3 种:
a) empty :没有标签体
b) scriptless :标签体可以包含 el 表达式和 JSP 动作元素,但不能包含 JSP 的脚本元素
c) tagdependent :表示标签体交由标签本身去解析处理。若指定 tagdependent ,在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器
本例为:
< tag >
< name > showHelloOnScreen </ name >
< tag-class > newjueqi.cn.javaeye.showHelloOnScreen </ tag-class >
< body-content > scriptless </ body-content >
</ tag >
2. 在自定义标签类中,接受 JspFragment 对象,该对象表示传进 的标签体。
实现了 SimpleTag 接口后,有个 public void setJspBody(JspFragment arg0) 方法,就是接收 JspFragment 对象。
该对象有两个方法:
a, getJspContext 方法:该方法用于返回代表调用页面的 JspContext 对象
b, Invoke 方法 (java.io.Writer out) :该方法用于执行 JspFragment 对象所代表的 JSP 代码片段。在 doTag() 方法中可以根据需要调用该方法。
1. 该方法的参数 out 用于指定将 JspFragment 对象的执行结果写入到哪个输出流对象中。若传递参数 out 的值为 null ,则将执行结果写入到 JspContext.geOut() 方法返回的输出流对象中 。
2. 若想在标签处理器中修改标签体内容:需在调用 invoke 方法时指定一个可取出结果数据的输出流对象 ( 如: StringWriter) ,让标签体的执行结果输出到该输出流中,然后从该输出流对象中取出数据进行修改后在输出到目标设备
所以为了实现在网友上输出语句的功能上,只需要在 doTag 方法中执行语句:
jspFragment.invoke(null);
就能把传进的标签体“ hello ”输出到屏幕上。
3. 使用标签体的标签
< newjueqi:showHelloOnScreen >
hello
</ newjueqi:showHelloOnScreen >
在网页上输出为: hello
四. EL 开发自定义函数
我们可以把“在自定义标签中定义属性 ” 中的输出两个数之间最大值的例子改为自定义函数。
1. 编 写 EL 自定义函数映射的 Java 类中的静态方法。 这个 Java 类必须带有 public 修饰符,方法必须是这个类的带有 public 修饰符的静态方法。
/**
* 输出两个数中的最大值
*/
public static void maxNum( int firstNum,
int secondNum )
{
int num_1=firstNum;
int num_2=secondNum;
int maxNum=num_1;
if ( num_1>num_2 )
{
maxNum=num_1;
}
else
{
maxNum=num_2;
}
System. out .println( maxNum );
}
2. 编写标签库描述文件 (tld 文件 ), 在 tld 文件中描述自定义函数。
<!-- 配置一个自定义的 EL 函数 -->
< function >
<!-- 配置自定义函数名 , 改名字将在 JSP 页面被引用 -->
< name > maxNum </ name >
<!-- 指定函数所在的类 -->
< function-class > newjueqi.cn.javaeye.funMaxNum </ function-class >
<!-- 指定函数的方法签名 -->
< function-signature > void maxNum( java.lang.Integer,
java.lang.Integer ) </ function-signature >
</ function >
3. 使用自定义的函数。
${newjueqi:maxNum(3,6) }
输出结果为: 6
五. SimpleTag 接口中函数的执行顺序
在一般实现 SimpleTag 接口中,除了实现了其中方法外,一般还有一个或多个 doXXX() 方法设置属性值,其中的执行顺序如下图:
图 2