一、简介
自定义标签的作用主要是用来替换JSP中的Java脚本。属于JSP技术。
二、自定义标签的开发步骤:
1.编写一个实现Tag接口的Java类(标签处理器类)。
2.编写标签库描述符(tld)文件,在tld文件中把标签处理器类进行描述在tld文件放入应用的web-inf文件中。如输入客户端ip地址的例子具体步骤示例如下:
1>定义一个类,实现javax.servlet.jsp.tagext.Tag接口(通过继承Tag接口的实现类也可)。
public class ShowRemoteIpTag extends TagSupport {
public int doStartTag() throws JspException {
String remoteIp = pageContext.getRequest().getRemoteAddr();
try {
pageContext.getOut().print("您的IP是是:"+remoteIp);
} catch (IOException e) {
e.printStackTrace();
}
return super.doStartTag();
}
}
2、在WEB-INF目录下建立一个扩展名为tld的XML文件(XML的内容参考Tomcat中的示例)fk.tld文件内容如下:
my taglib study.
1.0
fk
http://www.test.com/jsp/fk
Show Remote Ip
showRemoteIp
com.fk.tag.ShowRemoteIpTag
empty
forEach
com.fk.tag.example.ForEachSimpleTag
scriptless
items
true
true
var
true
false
某一List对象是否包含某一Object对象
contains
com.fk.util.ListContainsLabel
java.lang.Boolean contains(java.util.List,java.lang.Object)
3、在web.xml中建立tld文件的存放位置和uri的对应关系。
注:此步骤是可选的,前提是tld文件放在了WEB-INF目录下(建议使用此方式)。
http://www.test.com/jsp/fk
/WEB-INF/fk.tld
三、Tag接口详解(接口中的方法大部分都是容器调用的,继承了JspTag接口)
int doStartTag():容器调用。遇到开始标签时调用。
返回值可为:
Tag.SKIP_BODY:指示标签主体内容不执行
Tag.EVAL_BODY_INCLUDE:指示标签主体内容执行
int doEndTag():容器调用。遇到结束标签时调用。
返回值可为:
Tag.SKIP_PAGE:忽略结束标签之后的JSP内容
Tag.EVAL_PAGE:结束标签后的JSP内容还要继续执行
Tag getParent():用户调用。得到父标签。没有父标签返回null
void release():容器调用。释放标签类占用的资源。
void setPageContext(PageContext pc):容器调用。传入当前页面的上下文对象
void setParent(Tag t):容器调用。传入当前标签的父标签对象。如果有的话。
四、IterationTag接口:增加了重复执行主体内容的方法。(IterationTag接口继承了Tag接口,TagSupport类实现了IterationTag接口)
int doAfterBody():主体执行后,结束标签执行前,容器调用
返回值:
Tag.SKIP_BODY:指示标签主体内容不执行
IterationTag.EVAL_BODY_AGAIN:再次调用doAfterBody方法
注:成员变量的问题。
五、BodyTag:增加了获取主体内容的方法
void doInitBody() :容器调用
void setBodyContent(BodyContent b):容器调用,传递标签的主体内容
注意:以上2个方法都是由容器调用。要求doStartTag()方法必须返回BodyTag.EVAL_BODY_BUFFERED
六、传统标签返回值图、标签类继承及传统标签的执行流程
七、简单标签
SimpleTag接口详解
void setJspContext(JspContext pc) :设置当前JSP的上下文件。容器调用
void setParent(JspTag parent) :设置父标签对象。如果有的话。容器调用
void setJspBody(JspFragment jspBody) :设置主体内容。容器调用
若实现此接口类,有相关的setter属性,容器会自动调用自定义的setter方法。
void doTag():遇到标签就执行。容器调用。---------处理自定义标签功能的方法
用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以 抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中 位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回 Tag.SKIP_PAGE常量的情况。
JspTag getParent():自己调用。得到父标签。没有返回null
注意:每次调用都会重新实例化,简单标签不会驻留内存,而传统标签会驻留内存(像Servlet一样,第一次访问时容器创建实例化后就驻留了)。
//url地址过滤,若不是本站过来的url将被传到toPage值的文件中去。
public void doTag() throws JspException, IOException {
PageContext pc = (PageContext)getJspContext();
HttpServletRequest request = (HttpServletRequest)pc.getRequest();
String referer = request.getHeader("Referer");//Referer
HttpServletResponse response = (HttpServletResponse)pc.getResponse();
if(null == referer ||!referer.startsWith(siteUrl)){ //若不是指定的url开头地址则转过去,否则继续浏览呢,siteUrl为标签另一属性本站的基地址。
if(toPage.startsWith("/")){
response.sendRedirect(toPage);
}else{
String path = request.getRequestURL().toString();
String prePath = path.substring(0, path.lastIndexOf("/"));
response.sendRedirect(prePath+"/"+toPage);
}
}
}
显示类如下,模拟foreach功能:
public class ForEachSimpleTag extends SimpleTagSupport {
private Object items;
private String var;
private Collection collection ;
public void setItems(Object items) {
if(items instanceof List){
collection = (List)items;
}
if(items instanceof Set){
collection = (Set)items;
}
if(items instanceof Map){
collection = ((Map)items).entrySet();
}
if(items.getClass().isArray()){
int len = Array.getLength(items);//获取数组的长度
for(int i=0;i
八、tld文件的主要元素
taglib:根元素
tlib-version:版本号
short-name:短名称
uri:名称空间
function:可定义函数
name:标签的名称如contains
function-class:标签的处理类如com.fk.util.ListContainsLabel
function-signature:标签的静态处理方法
如:java.lang.Boolean contains(java.util.List,java.lang.Object)
tag:定义一个标签
name:标签的名称
tag-class:标签的处理类。全名称
body-content:标签的主体内容类型。
可选值:
JSP:主体内容可以是任意内容。服务传统标签
scriptless:主体内容一般是非java脚本内容。服务简单标签
empty:没有主体内容
tagdepentend:指示主体内容当做普通字符串对待
attribute:定义标签的属性
name:属性名称
required:是否是必须属性
rtexprvalue:是否支持表达式(EL表达式或Java表达式)
(runtime expression value)