今天中午晚上,弄了7个小时左右的自定义标签库,本来就是为实现一个转换,想用原来马工定义的那个,可是,后来出现问题后,就在网上艘资料,慢慢得真的成了那种标准的标签库了,下面我将记录定义标签库的方法,以及自己遇到的一个问题。
用自定义标签库,我们可以提高WEB应用的模块性、复用性、科维护性等等。相信对于标准标签库和Struts提供的标签库,我们是可以使用自如了,但是对于如何针对自己的应用来定制标签库,可能还是不太了解。下面介绍一下如何设计自定义标签库:
【 补充个人总结】:tld标签的描述文件
标签的描述文件是一个描述整个标签库标记信息和标签库中每个标签处理器以及其属性的XML文档。可以包含如下的一些元素。
1. tlibversion:标签库版本号,是一个点式十进制数(例如1.0),最多为4组小数点分隔的数字组成。
2. jspversion:标签库所需的JSP规范最低版本,例如JSP1.1。
3. shortname:标签库的缩写名,JSP可以使用该名字作为库中标签的缺省前缀。
4. uri:标签库唯一URI的元素。
5. info:标签库描述信息。
6. tag:加入标签,描述组成库的每个标签。
在tag元素中包含标签及其属性的信息:
1. name:与标签库的名字前缀一起使用的标签的名字, 是JSP容器唯一的标签标识。
2. tagclass:实现标签的标签处理器类的全名。
3. teiclass:标签附加信息(TEI)类的全名,TEI类给出关于标签处理器创建变量及有效性验证的信息。
4. bodycontent:描述标签处理器如何使用标签体的内容,有三种取值:
l empty:表示标签体必须为空;
l JSP:表示脚本元素和模板及其它标签一样被评估。
l tagdependent:内容被原封不动写入BodyContent,其它脚本元素以源码形式出现,而不被JSP容器解释。
5. info:标签的描述性信息。
6. attribute:使用标签时被编码的属性信息,用于定义标签的属性。
“attribute”元素中又可以包含下面几个元素:
1. name:属性的名字。
2. required:属性是否必须。
3. rtexprvalue:属性值能否用表达式指定
7.variable 元素
1.name-given:变量名为常量
2.name-from-attribute:一个属性的名字,其转换时(translation-time)值将给出属性的名字
必须有name-given或者name-from-attribute之中的一个。下列子元素是可选的
3.variable-class—变量的完全限定名。默认为java.lang.String。
4.declare—变量是否引用新对象。默认为True。
5.scope—定义的脚本变量的作用域。默认为NESTED如下表格:
值 可用性 方法
NESTED 开始和结束标签之间 在实现BodyTag的标签handler的doInitBody 和doAfterBody方法中,否则,在 doStartTag中
AT_BEGIN 从开始标签到页面的结束 在实现BodyTag的标签handler的doInitBody 和doAfterBody方法中,否则,在 doStartTag和doEndTag中
AT_END
在结束标签之后直到页面的结束 在doEndTag中
在function元素中包含标签及其属性的信息:
1. name:与标签库的名字前缀一起使用的标签的名字, 是JSP容器唯一的标签标识。
2. function-class:实现标签的标签处理器类的全名。
3. function-signature:指定标签库中所使用的方法,与类中的方法名称返回值必须相同,必须为全名 。
JSP自定义标签各种方法的返回值.
image
另外一种网上的说法是:
SKIP_BODY : 跳过了开始和结束标签之间的代码,一般是在doStartTag中使用,不处理标签体,直接调用 doEndTagO方法。
EVAL_BODY_INCLUDE :处理嵌套的标签,一般是在doStartTag中使用,由负责处理标签正文的tag接口提供
EVAL_BODY_BUFFERED :对包含的内容进行解析 一般是在doStartTag中使用,由负责处理标签正文的bodyTag接口提供,目的是通知jsp容器作好读取正文的工作(创建一个body-content包装正文和获取存放操作结果的out对象,便于以后的操作和输出).
EVAL_BODY_AGAIN:处理标签正文, 对标签体循环处理。嵌套标签的iteratorTag接口的使用
SKIP_PAGE :忽略标签后面的 JSP 页面,一般是在doEndTag中使用
EVAL_PAGE :处理标签结束,直接处理页面内容。继续执行下面的页, 一般是在doEndTag中使用
在web.xml中定义taglib地址
<jsp-config>
<!--定义标签库-->
<taglib>
<!--确定标签库的URI-->
<taglib-uri>http://lauedward.spaces.live.com/</taglib-uri>
<!-- 确定标签库定义文件的位置 -->
<taglib-location>/WEB-INF/test.tld</taglib-location>
</taglib>
</jsp-config>
如果不设定这个的话也可以直接在jsp中直接引用本地路径tld的地址即可调用
至此
下面介绍如何创建一个自定义标签。
一.编写java类继承TagSupport或TagSupport
1) 提供属性的set方法,
此后这个属性就可以在jsp页面设置。以jstl标签为例 <c:out value=""/>,这个value就是jsp数据到tag之间的入口。所以tag里面必须有一个setValue方法,具体的属性可以不叫value。例如setValue(String data){this.data = data;}
这个“value”的名称是在tld里定义的。取什么名字都可以,只需tag里提供相应的set方法即可。
2)处理 doStartTag 或 doEndTag
这两个方法是 TagSupport提供的。 还是以<c:out value=""/>为例,当jsp解析这个标签的时候,在“<”处触发 doStartTag 事件,在“>”时触发 doEndTag 事件。通常在 doStartTag 里进行逻辑操作,在 doEndTag 里控制输出。
下面是一个简单的例子
Java代码
package com.test.tag;
import java.io.IOException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class PermissionBodyTag extends BodyTagSupport {
boolean permission;
public boolean isPermission() {
return permission;
}
public void setPermission(boolean permission) {
this.permission = permission;
}
public int doStartTag() throws JspTagException {
if (permission) {
return EVAL_BODY_INCLUDE;
} else {
return SKIP_BODY;
}
}
public int doEndTag() throws JspTagException {
System.out.println("doEndTag");
try {
if (bodyContent != null) {
bodyContent.writeOut(bodyContent.getEnclosingWriter());
}else{
}
} catch (IOException e) {
throw new JspTagException("IO ERROR:" + e.getMessage());
}
return EVAL_PAGE;
}
public void doInitBody() throws JspTagException {
}
public void setBodyContent(BodyContent bodyContent) {
this.bodyContent = bodyContent;
}
}
二.编写tld文件
标签文件其实只是一个XML格式的说明文件,内容也很简单。
创建tagTest-html.tld文件在这个标签文件中,我们将我们创建的标签取名 tagTest,并声明了类型和参数(permission)。将该文件保存在 /WEB-INF 下面。
Java代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
<tlibversion>1.2</tlibversion>
<jspversion>1.1</jspversion>
<shortname>tagTest</shortname>
<uri>/taiji</uri>
<tag>
<name>permission</name>
<tagclass>com.test.tag.PermissionBodyTag</tagclass>
<bodycontent>JSP</bodycontent>
<attribute>
<name>permission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
三.加到web.xml中
当然,我们还需要将我们自定义的标签添加到 web.xml 中,否则还是无法使用。
Java代码
<taglib>
<taglib-uri>/tagTest </taglib-uri>
<taglib-location>/WEB-INF/tagTest-html.tld</taglib-location>
</taglib>
四.在jsp页面导入tld
Java代码
<%@ taglib uri="/tagTest " prefix="tagTest "%>
<%@ taglib uri="/tagTest " prefix="tagTest "%>
这样,你的jsp页面就可以使用自己的tag了。用这个标签就可以根据传人的boolean值来决定标签包的jsp内容是否输出
Java代码
<tagTest:permission permission="<% java code%>">
//需有权限输出,用户才能看到的内容
</tagTest:permission>
<tagTest:permission permission="<% java code%>">//需有权限输出,用户才能看到的内容</tagTest:permission>
1、标签库的调用过程
只有熟悉了标签库在WEB容器中是怎么调用的,我们才能更好的理解标签库的用途,方法的描述,更快的熟悉类库,很快的设计标签库。
当自定义标签库的开始标记被遇到的时候,WEB容器就初始化这个标签库对应的处理器(Handler),然后调用处理器的doStartTag方法。当结 束标记被碰到时,处理器的doEndTag方法就会被调用,另外一些方法的调用时发生在处理器和tag交互的时候。为了实现一个标记处理器 (Handler),你必须实现这三个阶段对应的方法,具体描述如下表:
Tag Handler Type |
Methods |
Simple |
doStartTag、doEndTag、release |
Attributes |
doStartTag、doEndTag、set/getAttribute1...N |
Body(No interaction) |
doStartTag、doEndTag、release |
Body(Interaction) |
doStratTag、doEndTag、release、doInitBody、doAfterBody |
要创建一个新的处理器,你必须要继承TagSupport或者BodyTagSupport来做为处理器的基类。
2、标记库描述器(Tag Library Descriptor)
标记库描述器是一个描述标签库的XML文档(TLD),一个TLD文档包含的信息主要是整个库的信息和每个标签的具体信息。它主要是被JSP容器用来验证标签。下面的这些TLD元素就是通常要被定义的:
- < taglib >
-
-
- < tlibversion > - The tag library's version
- < jspversion > - The JSP specification version the tag library depends on
- < shortname > - A simple default name that could be used by a JSP page authoring tool to create names with a mnemonic value; for example, shortname may be used as the preferred prefix value in taglib directives and/or to create prefixes for IDs.
- < uri > - A URI that uniquely identifies the tag library
- < info > - Descriptive information about the tag library
- < tag >
- ...
- </ tag >
- ...
- </ taglib >
-
下面是Struts html标签库的部分代码:
- <? xml version = "1.0" encoding = "UTF-8" ?>
- <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd" >
- < taglib >
- < tlibversion > 1.2 </ tlibversion >
- < jspversion > 1.1 </ jspversion >
- < shortname > html </ shortname >
- < uri > http://struts.apache.org/tags-html </ uri >
- < tag >
- < name > base </ name >
- < tagclass > org.apache.struts.taglib.html.BaseTag </ tagclass >
- < bodycontent > empty </ bodycontent >
- < attribute >
- < name > target </ name >
- < required > false </ required >
- < rtexprvalue > true </ rtexprvalue >
- </ attribute >
- < attribute >
- < name > server </ name >
- < required > false </ required >
- < rtexprvalue > true </ rtexprvalue >
- </ attribute >
- </ tag >
- <!--
- ...
- -->
- </ taglib >
其实在开发时可以直接把上面的恶代码拷过来,针对自己开发的标签来改改就可以了!(强烈建议)
3、下面就通过创建一个简单的标签(simple Tags)来熟悉整个设计过程
>先来设计Handler
- import javax.servlet.jsp.JspException;
- import javax.servlet.jsp.tagext.TagSupport;
-
- public SimpleTag extends Tag Support {
- public int doStartTag() throws JspException {
- try {
- pageContext.getOut().print( "Hello." );
- } catch (Exception ex) {
- throw new JspTagException( "SimpleTag: " +
- e.getMessage());
- }
- //由于简单的没有bady,所以返回SKIP_BODY
- return SKIP_BODY;
- }
- public int doEndTag() {
- return EVAL_PAGE;
- }
- }
>TLD
- < tag >
- < name > simple </ name >
- < tagclass > SimpleTag </ tagclass >
- < bodycontent > empty </ bodycontent >
- </ tag >
>页面调用
- < taglibName:simple />
摘自:http://blog.sina.com.cn/s/blog_780a632b0100wub7.html
第二篇博文:
用发和标准标签库一样.唯一不同的是,自定义标签需要自己实现哈哈!
自定义标签库分为传统标签,简单标签,和标签文件.三者区别在于一个比一个简单.实现细节大致相同.实现原理也大致相同.下面简单说说实现过程.
Tag接口:普通标签体接口.继承与JspTag.
- 把pageContext传给自己实现的标签类.
- 设置标签的属性.(标签体被镶套,则调用setParent方法设置父标签)
- 执行doStartTag方法.然后根据这个方法的返回值判断程序的走向
-
- EVAL_BODY_INCLUDE :把标签体输出到流中.
- SKIP_BODY:忽略标签体
- 执行doEndTag方法.返回两种值 EVAL_PAGE 和 SKIP_PAGE 表示执行剩下的jsp代码还是忽略剩下的jsp代码.
- 容器缓存标签实例.遇到同样的标签,则重复使用缓存的标签体.释放标签体.调用release()方法.
IterationTag接口:用于循环实现的接口,这个接口继承于Tag接口.新增了一个方法doAfterBody()和一个返回值的常量EVAL_BODY_AGAIN.
- 把pageContext传给自己实现的标签类.
- 设置标签的属性.(标签体被镶套,则调用setParent方法设置父标签)
- 执行doStartTag方法.然后根据这个方法的返回值判断程序的走向.
-
- EVAL_BODY_INCLUDE :执行标签体
- SKIP_BODY:忽略标签体
- 如果上一部返回EVAL_BODY_INCLUDE,那么执行这一步.调用的方法是doAfterBody().返回:(注意,不管返回是什么,这个标签已经执行了一次.类似于do..while循环)
-
- EVAL_BODY_AGAIN:表示重复执行标签体.
- SKIP_BODY:不执行标签体.进入下一步.
- 容器缓存标签实例.遇到同样的标签,则重复使用缓存的标签体释放标签体.调用release()方法.
BodyTag接口:继承于IterationTag接口,新增两个方法
- setBodyContent():设置bodyContent属性.对于空标签,该方法不会被调用.如果doStartTag()方法返回为SKIP_BODY或者EVAL_BODY_INCLUDE也不会被调用
- doInitBody():在setBodyContent()方法调用后,标签体第一次被执行之前,该方法调用.
- EVAL_BODY_BUFFERED返回值.只有实现了BodyTag接口,并且在doStartTag()方法中才能返回该值.
执行流程:
- 把pageContext传给自己实现的标签类.
- 设置标签的属性.(标签体被镶套,则调用setParent方法设置父标签)
- 执行doStartTag方法.然后根据这个方法的返回值判断程序的走向.
-
- EVAL_BODY_INCLUDE :执行标签体.
- SKIP_BODY:忽略标签体
- EVAL_BODY_BUFFERED:标签体不为空,进入下一步.
- 调用setBodyContent(),如果第一次执行再调用doInitBody().
- 调用doAfterBody().
-
- EVAL_BODY_AGAIN:表示重复执行标签体
- SKIP_BODY:不执行标签体.进入下一步.
- 容器缓存标签实例.遇到同样的标签,则重复使用缓存的标签体.
- 释放标签体.调用release()方法.
api已经有抽象类大致实现了以上步骤,只需重写几个自己需要的方法即可.TagSupport实现了IterationTag接口,BodyTagSupport实现了BodyTag接口.
简单标签则SimpleTagSupport实现继承于JspTag的SimpleTag接口.只需重写doTag方法就可完成简单的功能.
想要使用自己写好的标签还需要定义tld标签描述文件,然后在jsp页面引用.
标签以jar包形式出现,则标签必须放到META-INF目录或其子目录下.如果标签直接部署在web程序中,则标签描述文件必须在WEB-INF目录或其子目录下.
标签文件以 .tag 文件形式出现.以<% %>形式来完成功能,并且不用部署,写好后直接在jsp页面引用即可.
一、Java文件:
- package firsttag;
-
- import java.io.IOException;
-
- import javax.servlet.jsp.JspTagException;
- import javax.servlet.jsp.PageContext;
- import javax.servlet.jsp.tagext.Tag;
-
- public class HelloTag implements Tag {
- private PageContext pageContext;
- private Tag parent;
-
- public HelloTag() {
- super ();
- }
-
-
-
-
-
-
- public void setPageContext( final PageContext pageContext) {
- this .pageContext = pageContext;
- }
-
-
-
-
-
-
- public void setParent( final Tag parent) {
- this .parent = parent;
- }
-
-
-
-
-
-
- public int doStartTag() throws JspTagException {
-
- try {
- pageContext.getOut().println("Hello World!你好, 世界!<br/>" );
- } catch (java.io.IOException e) {
- throw new JspTagException( "IO Error: " + e.getMessage());
- }
- return SKIP_BODY;
- }
-
-
-
-
-
-
- public int doEndTag() throws JspTagException {
-
- try {
- pageContext.getOut().write("Hello Java World!你好,Java 世界!" );
- } catch (IOException e) {
-
- e.printStackTrace();
- }
- return EVAL_PAGE;
- }
-
-
-
-
-
-
- public void release() {
- }
-
- public Tag getParent() {
- return parent;
- }
- }
二、tld文件:
- <?xml version="1.0" encoding="ISO-8859-1" ?>
- <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 web-jsptaglibrary_2_0.xsd"
- version="2.0">
- <tlib-version>1.0</tlib-version>
- <jsp-version>2.0</jsp-version>
- <description>this si....</description>
- <short-name>myT</short-name>
- <uri>http://leisure/taglib</uri>
-
- <tag>
- <description>Extends TagSupport</description>
- <name>hello</name>
- <tag-class>firsttag.HelloTag</tag-class>
- <body-content>jsp</body-content>
- </tag>
-
- </taglib>
三、JSP文件:
- <%@ taglib uri="/mytld.tld" prefix="mytag"%>
- <%@ page contentType="text/html ; charset=gb2312"%>
-
- <html>
- <head>
- <title>first cumstomed tag</title>
- </head>
- <body>
- <p>
- 以下的内容从Taglib中显示:
- </p>
- <mytag:hello/>
- </body>
- </html>
摘自:http://blog.csdn.net/imust_can/article/details/6951147