jsp中自定义Taglib详解
一、自定义标签入门之无参数自定义标签
1.开发自定义标签类
当我们在JSP页面使用一个简单的标签时,底层实际上由标签处理类提供支持,从而可以使用简单的标签来封装复杂的功能,从而使团队更好地协作开发(能让美工人员更好地参与JSP页面的开发)。
自定义标签类都必须继承一个父类:javax.servlet.jsp.tagext.SimpleTagSupport,或者TagSupport除此之外,JSP自定义标签类还有如下要求。
如果标签类包含属性,每个属性都有对应的getter和setter方法。
重写doTag()或者doStartTag()或doEndTag()方法方法,这个方法负责生成页面内容。
首先介绍是不带属性的标签以HelloWorld为例:
Java代码如下:
publicclassHelloWorldTagextendsTagSupport{
privatestaticfinallongserialVersionUID=-3382691015235241708L;
@Override
publicintdoEndTag()throwsJspException{
try{
pageContext.getOut().write("HelloWorld!");
returnsuper.doEndTag();
}catch(JspExceptione){
e.printStackTrace();
return0;
}catch(IOExceptione){
e.printStackTrace();
return0;
}
}
@Override
publicintdoStartTag(){
try{
pageContext.getOut().write("HelloWorld");
returnsuper.doStartTag();
}catch(JspExceptione){
e.printStackTrace();
return0;
}catch(IOExceptione){
e.printStackTrace();
return0;
}
}
}
注意:
问题1:tagsupport中的dostartTag和doEndTag这两个方法有什么区别
doStartTag是在扫描到起始标签时调用,doEndTag是在扫描到结束标签是调用。
例如:<helloWorld>helloWorld</helloWorld>
则jsp引擎分析到<helloWorld>时调用doStratTag,分析到</helloWorld>时调用doEndTag
2、建立TLD文件
TLD是TagLibraryDefinition的缩写,即标签库定义,文件的后缀是tld,每个TLD文件对应一个标签库,一个标签库中可包含多个标签,TLD文件也称为标签库定义文件。
标签库定义文件的根元素是taglib,它可以包含多个tag子元素,每个tag子元素都定义一个标签。通常我们可以到Web容器下复制一个标签库定义文件,并在此基础上进行修改即可。例如Tomcat6.0,在webapps\examples\WEB-INF\jsp2路径下包含了一个jsp2-example-taglib.tld文件,这就是示范用的标签库定义文件。
将该文件复制到Web应用的WEB-INF/路径,或WEB-INF的任意子路径下,并对该文件进行简单修改,修改后的helloworld.tld文件代码如下:
<?xmlversion="1.0"encoding="UTF-8"?> <taglibxmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>myhelloworld</short-name> <!--定义该标签库的URI必须添加但可以空--> <uri></uri> <!--定义第一个标签--> <tag> <!--定义标签名--> <name>helloWorld</name> <!--定义标签处理类--> <tag-class>org.lxh.taglib.HelloWorldTag</tag-class> <!--定义标签体为空--> <body-content>empty</body-content> </tag> </taglib>
问题1:为什么要用TagSupport与BodyTagSupport的区别主要是标签处理类是否需要与标签体交互,如果不需要交互的就用TagSupport,否则就用BodyTagSupport。
交互就是标签处理类是否要读取标签体的内容和改变标签体返回的内容。用TagSupport实现的标签,都可以用BodyTagSupport来实现,因为BodyTagSupport继承了TagSupport而不去实现IterationTag接口的,因为BodyTagSupport继承了TagSupport类,并且该类已经实现了IterationTag接口并且实现了功能.
doStartTag()方法在标签开始时执行,要记住每次都要对类进行初始化,避免上一次的遗留数据对操作造成影响。然后判断是否有数据需要处理,如果有,则返回EVAL_BODY_INCLUDE开始处理标签里的内容,如果没有,返回EVAL_PAGE跳过标签内容执行标签下面的内容。
doAfterBody()方法在每次处理完标签内部内容后执行,判断循环是否已经结束,如果可以继续循环,返回EVAL_BODY_AGAIN用循环得到新的数据再次处理标签内部内容,如果循环结束就返回EVAL_PAGE结束标签。
二、自定义JSP标签的处理过程:
1.在JSP中引入标签库:
2.在JSP中使用标签库标签
3.Web容器根据第二个步骤中的prefix,获得第一个步骤中声明的taglib的uri属性值
4.Web容器根据uri属性在web.xml找到对应的元素
5.从元素中获得对应的元素的值
6.Web容器根据元素的值从WEB-INF/目录下找到对应的.tld文件
7.从.tld文件中找到与tagname对应的元素
8.凑元素中获得对应的元素的值
9.Web容器根据元素的值创建相应的taghandleclass的实例
10.Web容器调用这个实例的doStartTag/doEndTag方法完成相应的处理
三、创建和使用一个TagLibrary的基本步骤:
1.创建标签的处理类(TagHandlerClass)
2.创建标签库描述文件(TagLibraryDescrptorFile)
3.在web.xml文件中配置元素
4.在JSP文件中引人标签库
四、TagSupport类简介:
1.处理标签的类必须扩展javax.servlet.jsp.TagSupport.
2.TagSupport类的主要属性:
A.parent属性:代表嵌套了当前标签的上层标签的处理类
B.pageContex属性:代表Web应用中的javax.servlet.jsp.PageContext对象
3.JSP容器在调用doStartTag或者doEndTag方法前,会先调用setPageContext和setParent方法,设置pageContext和parent。因此在标签处理类中可以直接访问pageContext变量
4.在TagSupport的构造方法中不能访问pageContext成员变量,因为此时JSP容器还没有调用setPageContext方法对pageContext进行初始化
五、TagSupport处理标签的方法:
1.TagSupport类提供了两个处理标签的方法:
publicintdoStartTag()throwsJspException
publicintdoEndTag()throwsJspException
2.doStartTag:但JSP容器遇到自定义标签的起始标志,就会调用doStartTag()方法,doStartTag()方法返回一个整数值,用来决定程序的后续流程。
A.Tag.SKIP_BODY:表示跳过了开始和结束标签之间的代码
B.Tag.EVAL_BODY_INCLUDE:表示标签之间的内容被正常执行
C.Tag.EVAL_BODY_BUFFERED:对包含的内容进行解析
3.doEndTag:但JSP容器遇到自定义标签的结束标志,就会调用doEndTag()方法。doEndTag()方法也返回一个整数值,用来决定程序后续流程。
A.Tag.SKIP_PAGE:表示立刻停止执行网页,网页上未处理的静态内容和JSP程序均被忽略任何已有的输出内容立刻返回到客户的浏览器上。
B.Tag.EVAL_PAGE:表示按照正常的流程继续执行JSP网页
4.doAfterTag:遇到标签体执行
A.Tag.EVAL_BODY_AGAIN;//如果集合中还有对像,则循环执行标签体,对标签体循环处理,(存在于javax.servlet.jsp.tagext.IterationTag接口中)
B.Tag.SKIP_BODY
六、创建含有字段的标签:
1.创建标签处理器类FieldTag
packagecom.able.tag;
importjava.io.IOException;
importjavax.servlet.jsp.JspException;
importjavax.servlet.jsp.JspWriter;
importjavax.servlet.jsp.tagext.TagSupport;
publicclassFieldTagextendsTagSupport{
privatestaticfinallongserialVersionUID=1540529069962423355L;
privateStringfield;
privateIntegercount;
@Override
publicintdoEndTag()throwsJspException{
try{
JspWriterout=pageContext.getOut();
out.print(field);
out.print(count);
}catch(IOExceptione){
e.printStackTrace();
}
returnsuper.doEndTag();
}
publicStringgetField(){
returnfield;
}
publicvoidsetField(Stringfield){
this.field=field;
}
publicIntegergetCount(){
returncount;
}
publicvoidsetCount(Integercount){
this.count=count;
}
}
2.在tag.tld文件中天剑tag标签
<tag> <!--定义标签名--> <name>field</name> <!--定义标签处理类--> <tag-class>com.able.tag.FieldTag</tag-class> <!--定义标签体为空--> <body-content>empty</body-content> <attribute> <name>field</name> <required>true</required><!--是否必須赋值--> <rtexprvalue>true</rtexprvalue><!--表示是否接受jsp语法或者el语言或其他动态语言,默认false--> </attribute> <attribute> <name>count</name> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
3.jsp中定义标签:
<tm:fieldfield="11"count="22"/>
七、如何创建标签处理类
1、引入必需的资源
importjavax.servlet.jsp.*;importjavax.servlet.http.*;importjava.util.*;importjava.io.*;
2、继承TagSupport类并覆盖doStartTag()/doEndTag()方法
3、从ServletContext对象中获取java.util.Properties对象
4、从Properties对象中获取key对应的属性值
5、对获取的属性进行相应的处理并输出结果
创建标签库描述文件(TagLibraryDescriptor)
1、标签库描述文件,简称TLD,采用XML文件格式,定义了用户的标签库。TLD文件中的元素可以分成3类:
A.标签库元素
B.标签元素
C.标签属性元素
2、标签库元素用来设定标签库的相关信息,它的常用属性有:
A.shortname:指定TagLibrary默认的前缀名(prefix);
B.uri:设定TagLibrary的惟一访问表示符。
3、标签元素用来定义一个标签,它的常见属性有:
A.name:设定Tag的名字;
B.tagclass:设定Tag的处理类;
C.bodycontent:设定标签的主体(body)内容。
1)empty:表示标签中没有body;
2)JSP:表示标签的body中可以加入JSP程序代码;
3)tagdependent:表示标签中的内容由标签自己去处理。
4、标签属性元素用来定义标签的属性,它的常见属性有:
A.name:属性名称;
B.required:属性是否必需的,默认为false;
C.rtexprvalue:属性值是否可以为request-time表达式,也就是类似于<%=…%>的表达式。
八、在Web应用中使用标签
1、如果Web应用中用到了自定义JSP标签,则必须在web.xml文件中加入元素,它用于声明所引用的标签所在的标签库
/sometaglib
/WEB-INF/someTLD.tld
2、设定TagLibrary的惟一标示符,在Web应用中将根据它来引用TagLibray;
3、指定和TagLibrary对应的TLD文件的位置;
4、在JSP文件中需要加入<!--taglib%>指令来声明对标签库的引用。
5、prefix表示在JSP网页中引用这个标签库的标签时的前缀,uri用来指定TagLibrary的标识符,它必须和web.xml中的属性保持一致。
九、案例:
4.1.创建标签描述符文件
在WEB-INF文件下创建*.tld标签描述符文件:如
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>eRedLabJSPTagLibrary</shortname>
<uri>/testTag</uri>
<info>自定义标签测试</info>
<tag>
<name>hello</name>
<tagclass>com.eredlab.taglib.test.TestTld</tagclass>
<bodycontent>empty</bodycontent>
<info>自定义标签测试</info>
<attribute>
<name>begin</name>
<required>true</required>
</attribute>
<attribute>
<name>end</name>
<required>true</required>
</attribute>
</tag>
</taglib>
4.2.创建标签处理器
/**
*@desc自定义标签测试类实现一个简单的HelloWorld标签
*@author 夏中伟
*@versioneRedLab2007-9-10
*/
publicclassTestTldextendsTagSupport{
//标签属性begin
privateStringbegin=null;
//标签属性end
privateStringend=null;
//构造函数
publicTestTld(){
}
/*标签初始方法*/
publicintdoStartTag()throwsJspTagException{
returnsuper.EVAL_BODY_INCLUDE;
}
/*标签结束方法*/
publicintdoEndTag()throwsJspTagException{
JspWriterout=pageContext.getOut();
Stringsum=begin+end;
try{
//标签的返回值
out.println(sum);
}catch(IOExceptione){
e.printStackTrace();
}
returnsuper.SKIP_BODY;
}
/*释放资源*/
publicvoidrelease(){
super.release();
}
/********************************************
属性get()、set()方法
*******************************************/
}
在Web.XML中加载标签描述符文件.
<!--加载标签描述符文件-->
<taglib>
<taglib-uri>/WEB-INF/test.tld</taglib-uri>
<taglib-location>/WEB-INF/test.tld</taglib-location>
</taglib>
5.2.在JSP中使用此标签
<%@tagliburi="/testTag"prefix="mytag"%>
<mytag:helloend="夏中伟!"begin="自定义标签输出流:Hello,"/>
<mytag:helloend="World!"begin="Hi,"/>
WEB页面输出结果如下:
自定义标签输出流:Hello,夏中伟!Hi,World!
循环标签体类:ForEach.java
1importjava.util.Collection;
2importjava.util.Iterator;
3
4importjavax.servlet.jsp.JspException;
5importjavax.servlet.jsp.tagext.BodyContent;
6importjavax.servlet.jsp.tagext.BodyTagSupport;
7
8publicclassForEachextendsBodyTagSupport
9{
10privateStringid;
11privateStringcollection;
12privateIteratoriter;
13
14publicvoidsetCollection(Stringcollection)
15{
16this.collection=collection;
17}
18publicvoidsetId(Stringid)
19{
20this.id=id;
21}
22
23//遇到开始标签执行
24publicintdoStartTag()throwsJspException
25{
26Collectioncoll=(Collection)pageContext.findAttribute(collection);
27//表示如果未找到指定集合,则不用处理标签体,直接调用doEndTag()方法。
28if(coll==null||coll.isEmpty())returnSKIP_BODY;
29
30iter=coll.iterator();
31pageContext.setAttribute(id,iter.next());
32//表示在现有的输出流对象中处理标签体,但绕过setBodyContent()和doInitBody()方法
33//这里一定要返回EVAL_BODY_INCLUDE,否则标签体的内容不会在网页上输出显示
34returnEVAL_BODY_INCLUDE;
35}
36
37//在doInitBody方法之前执行,在这里被绕过不执行
38@Override
39publicvoidsetBodyContent(BodyContentarg0)
40{
41System.out.println("setBodyContent");
42super.setBodyContent(arg0);
43}
44//此方法被绕过不会被执行
45@Override
46publicvoiddoInitBody()throwsJspException
47{
48System.out.println("doInitBody");
49super.doInitBody();
50}
51
52//遇到标签体执行
53publicintdoAfterBody()throwsJspException
54{
55if(iter.hasNext())
56{
57pageContext.setAttribute(id,iter.next());
58returnEVAL_BODY_AGAIN;//如果集合中还有对像,则循环执行标签体
59}
60returnSKIP_BODY;//迭代完集合后,跳过标签体,调用doEndTag()方法。
61}
62
63//遇到结束标签执行
64publicintdoEndTag()throwsJspException
65{
66System.out.println("doEndTag");
67returnEVAL_PAGE;
68}
69
70}
获取VO属性类:GetProperty.java
1importjava.lang.reflect.Method;
2
3importjavax.servlet.jsp.JspException;
4importjavax.servlet.jsp.tagext.BodyTagSupport;
5
6publicclassGetPropertyextendsBodyTagSupport
7{
8
9privateStringname;
10privateStringproperty;
11
12publicvoidsetName(Stringname)
13{
14this.name=name;
15}
16
17publicvoidsetProperty(Stringproperty)
18{
19this.property=property;
20}
21
22@SuppressWarnings("unchecked")
23publicintdoStartTag()throwsJspException
24{
25try
26{
27Objectobj=pageContext.findAttribute(name);
28
29if(obj==null)returnSKIP_BODY;
30
31Classc=obj.getClass();
32//构造GET方法名字get+属性名(属性名第一个字母大写)
33StringgetMethodName="get"+property.substring(0,1).toUpperCase()
34+property.substring(1,property.length());
35MethodgetMethod=c.getMethod(getMethodName,newClass[]{});
36
37pageContext.getOut().print(getMethod.invoke(obj));
38System.out.print(property+":"+getMethod.invoke(obj)+"t");
39}catch(Exceptione)
40{
41e.printStackTrace();
42}
43returnSKIP_BODY;
44}
45
46publicintdoEndTag()throwsJspException
47{
48returnEVAL_PAGE;
49}
50}
51
52表达式直接访问此类中静态的方法:ELFunction.java
53publicclassELFunction
54{
55publicstaticintadd(inti,intj)
56{
57returni+j;
58}
59}
写一个测试用的VO类:UserVo.java
1publicclassUserVo
2{
3privateStringname;
4privateStringpassword;
5
6publicStringgetName()
7{
8returnname;
9}
10publicvoidsetName(Stringname)
11{
12this.name=name;
13}
14publicStringgetPassword()
15{
16returnpassword;
17}
18publicvoidsetPassword(Stringpassword)
19{
20this.password=password;
21}
22}
建好TLD文件tag.tld,放在WEB-INF目录下
1<?xmlversion="1.0"encoding="utf-8"?>
2<taglibversion="2.0"
3xmlns="http://java.sun.com/xml/ns/j2ee"
4xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5xmlns:shcemalocation="http://java.sun.com/xml/ns/j2ee
6http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
7
8<description>自定义标签</description>
9<display-name>JSTLcore</display-name>
10<tlib-version>1.1</tlib-version>
11<short-name>firstLabel</short-name>
12<uri>http://java.sun.com/jsp/jstl/core</uri>
13
14<!--创建自定义迭代标签-->
15<tag>
16<name>forEach</name>
17<tag-class>exercise.taglib.ForEach</tag-class>
18<!--如果没有标签体,设置empty,如果有标签休必须设置JSP-->
19<body-content>JSP</body-content>
20<attribute>
21<name>id</name>
22<required>true</required><!--标识属性是否是必须的-->
23<rtexprvalue>true</rtexprvalue><!--标识属性值是否可以用表达式语言-->
24</attribute>
25<attribute>
26<name>collection</name>
27<required>true</required>
28<rtexprvalue>true</rtexprvalue>
29</attribute>
30</tag>
31
32<!--创建自定义获得属性标签-->
33<tag>
34<name>getProperty</name>
35<tag-class>exercise.taglib.GetProperty</tag-class>
36<body-content>empty</body-content>
37<attribute>
38<name>name</name>
39<required>true</required>
40<rtexprvalue>true</rtexprvalue>
41</attribute>
42<attribute>
43<name>property</name>
44<required>true</required>
45<rtexprvalue>true</rtexprvalue>
46</attribute>
47</tag>
48
49<!--配置一个表达式调用的函数-->
50<function>
51<name>add</name><!--配置一个标签,在JSP页面通过引用前缀调用-->
52<function-class>exercise.taglib.ELFunction</function-class><!--实现类-->
53<function-signature>intadd(int,int)</function-signature><!--静态的方法:包括返回类型,方法名,入参的类型-->
54</function>
55</taglib>
在web.xml文件中配置自定义标签
<jsp-config>
<taglib>
<taglib-uri>firstTag</taglib-uri>
<taglib-location>/WEB-INF/tag.tld</taglib-location>
</taglib>
</jsp-config>
在jsp文件中使用标签:tag.jsp
<%@pagelanguage="java"import="java.util.*"pageEncoding="utf-8"%>
<%@tagliburi="firstTag"prefix="my"%>
<jsp:useBeanid="userVo1"class="exercise.vo.UserVo"scope="request">
<jsp:setPropertyname="userVo1"property="name"value="Hackiller"/>
<jsp:setPropertyname="userVo1"property="password"value="123"/>
</jsp:useBean>
<jsp:useBeanid="userVo2"class="exercise.vo.UserVo"scope="request">
<jsp:setPropertyname="userVo2"property="name"value="YangYang"/>
<jsp:setPropertyname="userVo2"property="password"value="456"/>
</jsp:useBean>
<%
Listlist=newArrayList();
list.add(userVo1);
list.add(userVo2);
pageContext.setAttribute("voList",list);
%>
<html>
<head>
<title>MyJSP'tag.jsp'startingpage</title>
</head>
<body>
<h2align="center">ThisismyJSPpage:测试taglib.</h2>
<hr>
<h2>自定义迭代标签:</h2>
<table>
<tr><td>姓名</td><td>密码</td></tr>
<my:forEachcollection="voList"id="uservo">
<tr>
<td><my:getPropertyname="uservo"property="name"/></td>
<td><my:getPropertyname="uservo"property="password"/></td>
</tr>
</my:forEach>
</table>
<hr>
<h2>表达式调用类的静态方法:</h2>
2+5=${my:add(2,5)}
</body>
</html>
以上就是小编为大家带来的jsp中自定义Taglib详解全部内容了,希望大家多多支持毛票票~