先看一个例子来作为开胃菜吧。
示例一
jsp页面:
<%@taglib prefix="my" uri="/mytag"%> <html> <head> <title>hello</title> </head> <body> <my:hello/> </body> </html>
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <jsp-config> <taglib> <taglib-uri>/mytag</taglib-uri> <taglib-location>/WEB-INF/mytags.tld</taglib-location> </taglib> </jsp-config> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
<?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <tlib-version>1.0</tlib-version> <short-name>chen</short-name> <display-name>my tag</display-name> <description>this is from mr.chen</description> <tag> <name>hello</name> <tag-class>traditional.HelloTag</tag-class> <body-content>empty</body-content> </tag> </taglib>
package traditional; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; /* * 功能:<my:hello/>输出hello字符 * */ public class HelloTag implements Tag{ private PageContext pc; private Tag parent; @Override public int doEndTag() throws JspException{ // TODO Auto-generated method stub JspWriter out = pc.getOut(); try { out.write("hello"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return Tag.EVAL_PAGE; } @Override public int doStartTag() throws JspException { // TODO Auto-generated method stub return Tag.SKIP_BODY; } @Override public Tag getParent() { // TODO Auto-generated method stub return parent; } @Override public void release() { // TODO Auto-generated method stub } @Override public void setPageContext(PageContext pc) { // TODO Auto-generated method stub this.pc = pc; } @Override public void setParent(Tag tag) { // TODO Auto-generated method stub this.parent = tag; } }
接下来看看一个带属性的max标签的例子:
示例二
package traditional;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
public class MaxTag extends TagSupport{
/**
*
*/
private static final long serialVersionUID = 4446743607084515654L;
private int num1;
private int num2;
public int doEndTag() throws JspException{
int i = num1>num2?num1:num2;
JspWriter out = this.pageContext.getOut();
try {
out.print(i);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Tag.EVAL_PAGE;
}
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
}
tld文件:
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="3.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>chen</short-name>
<display-name>my tag</display-name>
<description>this is from mr.chen</description>
<tag>
<name>hello</name>
<tag-class>traditional.HelloTag</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>max</name>
<tag-class>traditional.MaxTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>num1</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>num2</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
<%@taglib prefix="my" uri="/mytag"%>
<%
int a = Integer.parseInt(request.getParameter("num1"));
int b = Integer.parseInt(request.getParameter("num2"));
%>
<html>
<head>
<title>max</title>
</head>
<body>
<my:max num1="<%=a %>" num2="<%=b %>"/>
</body>
</html>
示例三
再看一个处理标签体的例子:
package traditional; import java.io.IOException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyTag; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.IterationTag; import javax.servlet.jsp.tagext.Tag; public class GreetTag extends BodyTagSupport{ /** * */ private static final long serialVersionUID = -5083245804167668973L; private int count = 0; public int doStartTag(){ return BodyTag.EVAL_BODY_BUFFERED; } public int doAfterBody(){ if(count < 3){ count++; return IterationTag.EVAL_BODY_AGAIN; } else{ return Tag.SKIP_BODY; } } public int doEndTag(){ JspWriter out = this.bodyContent.getEnclosingWriter(); try { out.println(this.bodyContent.getString()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return Tag.EVAL_PAGE; } }
<tag> <name>greet</name> <tag-class>traditional.GreetTag</tag-class> <body-content>JSP</body-content> </tag>
<%@page pageEncoding="GBK" %> <%@taglib prefix="my" uri="/mytag"%> <html> <head> <title>greet</title> </head> <body> <my:greet> 欢迎访问 </my:greet> </body> </html>
看完了几个例子,接下来细细分析JSP自定义标签,这里面大有文章,哈哈。
自定义标签实际上是实现了特定接口的类,封装了一些常用的功能,在运行时被相应的代码替换。要编写自己的标签,关键就是编写标签处理器类,一个标签对应一个标签处理器类。以下是在javax.servlet.jsp.tagext包下的标签库的主要类的关系:
使用左边编写的标签为传统标签,JSP2.0后可以使用简单标签,即SimpleTag。
Tag接口,实现了Tag接口的标签处理器类的执行流程如下:
Tag接口
定义了以下常量:
EVAL_BODY_INCLUDE:作为doStartTag()的返回值,代表输出标签体到JSP页面
SKIP_BODY:作为doStartTag()的返回值,代表跳过标签体
EVAL_PAGE:作为doEndTag()的返回值,代表继续执行余下的页面
SKIP_PAGE:作为doEndTag()的返回值,代表跳过余下的页面
IterationTag接口
增加了一个方法:doAfterTag()用于迭代处理标签体的内容,新增了一个常量:EVAL_BODY_AGAIN,作为doAfterTag()的返回值代表重复执行
BodyTag接口
可以获得标签体执行后的内容做其他的处理
增加了两个方法:
setBodyContent(BodyContent bc)
doInitBody():setBodyContent()执行后被调用
增加了一个常量:
EVAL_BODY_BUFFERED:作为doStartTag返回值,会创建一个BodyContent对象来代表标签体执行后的结果
ok,写完了标签处理器类后还应该写tld文件(标签库描述符),将它放在jar的META-INF下或web应用的WEB-INF下。再在web.xml下填写映射就可以在jsp页面中使用<hello/>了
特别特别注意:
在tomcat4.1之后的版本中默认开启了标签缓冲池(websphere和weblogic并不会这么做),所以执行完标签后并不会执行release()方法(_jspDestroy()时才释放),也就是说同一个jsp页面自定义标签不管使用多少次只会存在一个实例,但也并不是每一个标签都会为其创建一个缓冲池,要根据参数来判断,例如:
<cc:UserInfoTag user=”…” />
<cc:UserInfoTag />
上面例子中由于参数不同就会创建两个标签缓冲池。
ok,以上是传统标签的开发,SimpleTag的开发,后面再写吧。