1. 自定义标签运行原理
自定义标签是用户定义的JSP语言元素。当JSP页面包含一个自定义标签时将被转化为servlet,标签转化为对被
称为tag handler的对象的操作,即当servlet执行时Web container调用那些操作。
2. 两种标签
可以定义两种类型的标签:
(1) javax.servlet.jsp.tagext.Tag
(2) javax.servlet.jsp.tagext.BodyTag
有标签体的标签必须实现 BodyTag 接口, 无标签体的简单标签可以实现 Tag 接口。
3. 标签处理程序
int doStartTag() throws JspException---处理开始标签
int doEndTag() throws JspException---处理结束标签
Tag getParent()/void setParent(Tag t)---获得/设置标签的父标签
void setPageContext(PageContext pc)--- pageContext 属性的 setter 方法
void release() 释放获得的所有资源
doStartTag()和doEndTag()方法的返回值说明:
SKIP_BODY 表示不用处理标签体,直接调用doEndTag()方法。
SKIP_PAGE 忽略标签后面的jsp(SUN企业级应用的首选)内容。
EVAL_PAGE 处理标签后,继续处理jsp(SUN企业级应用的首选)后面的内容。
EVAL_BODY_BUFFERED 表示需要处理标签体,且需要重新创建一个缓冲(调用setBodyContent方法)。
EVAL_BODY_INCLUDE 表示在现有的输出流对象中处理标签体,但绕过setBodyContent()和doInitBody()方法
EVAL_BODY_AGAIN 对标签体循环处理。(存在于javax.servlet.jsp.tagext.IterationTag接口中)
实现javax.servlet.jsp.tagext.Tag接口或扩展javax.servlet.jsp.tagext.TagSupport类:
TagSupport 类定义了 get/setParent() 和 setPageContext(),这与所有标签处理程序几乎相同。get/setParent()
方法允许标签嵌套。
TagSupport 类还定义了一个可以被子类使用的 pageContext 实例变量 (protected PageContext pageContext),
这个变量是由 setPageContext() 方法设置的。
在创建自定义标签之前,需要创建一个 标签处理程序。标签处理程序是一个执行自定义标签操作的 Java 对象。
在使用自定义标签时,要导入一个 标签库 —— 即一组标签/标签处理程序对。通过在 Web 部署描述符中声明库导
入它,然后用指令 taglib 将它导入 JSP 页。
如果 JSP 容器在转换时遇到了自定义标签,那么它就检查 标签库描述符(tag library descriptor) (TLD) 文件
以查询相应的标签处理程序。TLD 文件对于自定义标签处理程序,就像 Web 部署描述符对于 servlet 一样。
在运行时,JSP 页生成的 servlet 得到对应于这一页面所使用的标签的标签处理程序的一个实例。生成的 servlet 用
传递给它的属性初始化标签处理程序。
标签处理程序实现了 生存周期 方法。生成的 servlet 用这些方法通知标签处理程序应当启动、停止或者重复自定义
标签操作。生成的 servlet 调用这些生存周期方法执行标签的功能。
4. TLD 文件
TLD文件的根元素是 taglib。
taglib 描述了一个 标签库 —— 即一组标签/标签处理程序对。
因为使用的是 JSP 版本 1.2,所以在这个例子中需要 tlib-version 和 short-name 元素。
tlib-version 元素对应于标签库版本。
jsp-version 对应于标签库所依赖的 JSP 技术的版本。
short-name 元素定义了 IDE 和其他开发工具可以使用的标签库的简单名。
taglib 元素包含许多 tag 元素,标签库中每一个标签有一个 tag 元素。
5. 案例实战
(1) TLD文件:utilTag.tld
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>util</short-name>
<uri>http://com.zskx.pem/tag/util-1.0</uri>
<tag>
<name>domainUrl</name>
<tag-class>com.dmwdp.network.biz.commons.taglib.DomainUrlTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>imgUrl</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
(2) web.xml配置
......
<jsp-config>
<taglib>
<taglib-uri>util</taglib-uri>
<taglib-location>/WEB-INF/taglib/utilTag.tld</taglib-location>
</taglib>
</jsp-config>
......
(3) 标签处理类
public class DomainUrlTag extends TagSupport {
private static final Logger LOGGER = Logger.getLogger(DomainUrlTag.class);
private static final long serialVersionUID = 8662373418251060423L;
private String imgUrl;
public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
}
public DomainUrlTag() {
}
@Override
public int doStartTag() throws JspTagException {
//表示在现有的输出流对象中处理标签体,但绕过setBodyContent()和doInitBody()方法
return EVAL_BODY_INCLUDE;
}
@Override
public int doEndTag() throws JspException {
if (StringUtils.isBlank(imgUrl)) {
return EVAL_PAGE;
}
String[] imgServers = ImagePropertiesReader.getImageServerURLs();
int imgUrlCount = imgServers.length;
int serverNum = Math.abs((imgUrl.hashCode() % imgUrlCount));
String resultUrl = null;
for (int i = 0; i < imgUrlCount; i++) {
if (serverNum == i) {
resultUrl = imgServers[i];
break;
}
}
outPutResultUrl(resultUrl);
return EVAL_PAGE;
}
private void outPutResultUrl(String resultUrl) {
if (StringUtils.isBlank(resultUrl)) {
return;
}
try {
pageContext.getOut().write(resultUrl);
} catch (IOException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Customize Tag error", e);
}
}
}
}
(4) 页面使用
<%@ taglib prefix="util" uri="http://com.zskx.pem/tag/util-1.0" %>
<link rel="shortcut icon" href="<util:domainUrl imgUrl='/pem.ico'/>/dmwdp.ico" />
(5) ImagePropertiesReader.java
public class ImagePropertiesReader {
private static final Logger LOGGER = Logger.getLogger(ImagePropertiesReader.class);
private static Properties props = new Properties();
private ImagePropertiesReader() {
}
static {
try {
final InputStream tempIn = ImagePropertiesReader.class.getResourceAsStream("/image.properties");
props.load(tempIn);
} catch (Exception e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("ImagePropertiesReader error", e);
}
}
}
public static String[] getImageServerURLs() {
String imgUrlStr = props.getProperty(Constant.DMWDP_IMAGE_SERVER_URLS);
return imgUrlStr.split(",");
}
}