一般我们说自定义标签是指JSP自定义标签。自定义标签在功能上逻辑上与javaBean 类似,都封装Java 代码。自定义标签是可重用的组件代码,并且允许开发人员为复杂的操作提供逻辑名称。
JSP开发人员使用标签库创建标签.标签库是按照功能或实现进行分组的自定义标签的集合。
网络上常见的CMS内容管理系统都是采用模板的形式来实现,基本上所有的CMS系统都有一套自己的模板标签书写方法,简称自定义标签。
传统方式
自定义标签
传统方式(jsp1.1):实现Tag接口
简单方式(jsp2.0):实现SimpleTag接口
步骤: a编写标签处理类 b编写标签描述符 c导入并使用
编写标签处理类
传统方法:实现javax.servlet.jsp.tagext.Tag接口: doStartTag()
简单方法:实现javax.servlet.jsp.tagext.SimpleTag接口: doTag()
如果jsp在编译时发现了自定义标签,就会交给doStartTag()或doTag()
编写标签描述符t(Tag)l(library)d(descriptor)
编写建议:可以仿照 一个其他标签语言(el jstl) 的tld文件
<!--标签库的头文件-->
<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">
<description>标签库描述</description>
<tlib-version>1.0</tlib-version>
<display-name>全称</display-name>
<short-name>简称</short-name>
<uri>标签库的uri</uri>
<!--自定义标签的相关信息-->
<tag>
<description>标签描述</description>
<name>标签名</name>
<tag-class>标签库的实现类</tag-class>
<body-content>标签体的类型</body-content>
</tag>
</taglib>
scriptlet:<% … %>(小脚本) <%! … %> <%= … %>,即scriptless为除了这3个外的元素
导入并使用:
myTag。tld导入WEB-INF或子目录下(非lib和classes)
使用:引入具体要使用的tld文件
<%@ taglib uri="xxx", prefix = "x"%>
uri:每个tld文件的 唯一描述符
prefix:使用tld标签时的前缀
具体使用:
空标签(没有标签体的标签):<d:foreach></d:foreach> <d:foreach/>
带标签体:<d:foreach>xxx</d:foreach>
带属性:<d:foreach collection = "${students}">xxx</d:foreach> <d:foreach 属性名= "属性值">xxx</d:foreach>
实际开发步骤:
编写标签处理类
先确保项目有tomcat环境
Tag接口
doStartTag:标签处理类得到核心方法(标签体的执行逻辑)
该方法有以下两个返回值即(0,1)
int EVAL_BODY_INCLUDE = 1; 表示该标签体会被执行
int SKIP_BODY = 0;表示该标签体不会被执行
doEndTag:标签执行完毕之后的方法,例如可以让标签在执行完毕之后,再执行一次
int SKIP_PAGE = 5;后面jsp页面内容不被执行
int EVAL_PAGE = 6;后面jsp页面内容继续执行
Tag接口中所有方法的执行顺序:
再运行时(jsp会被翻译成servlet(java))当jsp容器(Tomcat,jetty)在将jsp翻译成servlet的时候,
如果遇到jsp中有标签,就会依次执行serPageContext-setParent-doStartTag-doEndTag-release
javax.servlet.jap.tagext.IterationTag接口:(时Tag的子接口)
如果有循环:IterationTag 没有循环:Tag
doAfterBody:当标签体执行完毕后的操作,通过返回值决定:
(EVAL_BODY_AGAIN= 2)重复执行
(SKIP_BODY=0)不再执行
BobyTag接口:如果在标签体被显示之前,进行一些其他的“额外”操作 例如:输出前把小写改为大写
int EVAL_BODY_BUFFERED = 2, doStartTag的第三个返回值代表一个缓冲区(Body Content)
BodyContext是abstract 具体使用时需要使用实现类BodyContentImpl(要引入jasper.jar,在配置comcat的comfige中添加)
如果 doStartTag 的返回值 是 EVAL_BODY_BUFFFERED,则服务器会自动将标签体需要显示的内容放入缓冲区中(BodyContent)
因此,如果要更改最终显示结果,只需要从缓冲区中获取原来的数据,进行修改即可
如何获取修改;详见BodyContent中的方法(通过getxxx获取原来的数据,修改后,输出getEncloseingWriter)
目标:遍历3次
<xXX>hello<xxx>执行一次,重复两次
编写标签描述符(mytag.tld)
导入并使用
<%@ taglib uri="http://www.yuanqi.com" prefix="c"%>
<c:mytag num="4">hello</c:mytag>
mytag.tld
<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">
<description>这是我的迭代器标签库</description>
<tlib-version>1.0</tlib-version>
<short-name>mytaglib</short-name>
<uri>http://www.yuanqi.com</uri>
<!--自定义标签的相关信息-->
<tag>
<description>这是我的迭代器标签</description>
<name>mytag</name>
<tag-class>tag.MyIteration</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>num</name>
<required>true</required><!--是否必须赋值-->
</attribute>
</tag>
<tag>
<name>toupper</name>
<tag-class>tag.ToUpperCast</tag-class>
<body-content>JSP</body-content>
</tag>
<tag>
<name>s-tag</name>
<tag-class>tag.SimpleTagIteration</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>num</name>
<required>true</required>
</attribute>
</tag>
<tag>
<name>s-login</name>
<tag-class>tag.LoginTag</tag-class>
<body-content>scriptless</body-content>
</tag>
</taglib>
jsp
<%@ taglib uri="http://www.yuanqi.com" prefix="c"%>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<c:mytag num="4">hello</c:mytag>
<c:toupper>hello</c:toupper>
$END$
<c:s-tag num="3">simple<br/></c:s-tag>
myiteration.java
package tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class MyIteration extends TagSupport {
private int num;
public void setNum(int num){
this.num = num;
}
@Override
public int doStartTag() throws JspException {
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
num--;
return num == 0?SKIP_BODY:EVAL_BODY_AGAIN;
}
}
touppercast,java
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.io.IOException;
public class ToUpperCast extends BodyTagSupport {
@Override
public int doStartTag() throws JspException {
return EVAL_BODY_BUFFERED;
}//该父类默认返回EVAL_BODY_BUFFERED,故该方法可不重写
@Override
public int doEndTag() throws JspException {
try {
String content = getBodyContent().getString();
content = content.toUpperCase();
bodyContent.getEnclosingWriter().write(content);
} catch (IOException e) {
e.printStackTrace();
}
return super.doEndTag();
}
}