坚持每天写博文,积累下开发中的点点滴滴
继承TagSupport:
首先创建一个普通java类MyTagText继承TagSupport,该类为某一标签定义操作。
重写父类的setPageContext方法,用于得到当前jsp页面的pageContext对象。
重写父类的doStartTag方法,定义标签具体操作
public class MyTagText extends TagSupport{
private PageContext pageContext;
//重写父类的setPageContext方法,用于得到当前jsp页面的pageContext对象。
@Override
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
}
//重写父类的doStartTag方法,里面写上你定义的标签的java操作
//这里我定义的标签用作向浏览器输出一大段信息:
@Override
public int doStartTag() throws JspException {
try {
pageContext.getResponse().getWriter().write("AAAAAAAAA");
} catch (Exception e) {
e.printStackTrace();
}
return super.doStartTag();
}
//这样就完成一个标签处理程序了.写完程序我们还需要注册它。
}
我们需要在tld文件中注册
在你的web应用目录下,找到WEB-INF文件夹,在里面新建一个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</tlib-version><!-- 代表标签库的版本号 -->
<jsp-version>1.2</jsp-version><!-- 代表jsp的版本 -->
<short-name>mtt</short-name><!-- 你的标签库的简称 -->
<uri>http://vmaxtam.com/mytag</uri><!-- 你标签库的引用uri -->
<tag>
<name>mytab</name><!-- 你定义的标签的名称 -->
<tag-class>CustomTag.MyTagText</tag-class><!-- 对应的标签处理程序:包名+类名 -->
<body-content>JSP</body-content><!-- 标签体内容的格式 -->
</tag>
</taglib>
现在可以在JSP中使用了记得导入标签:
<%@taglib uri="http://vmaxtam.com/mytag" prefix="mmt" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@taglib uri="http://vmaxtam.com/mytag" prefix="mmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<mmt:mytab></mmt:mytab>
</body>
</html>
效果如下:
参考:https://www.cnblogs.com/vmax-tam/p/4145334.html 作者:白Rime
自定义标签的原理
1)当服务器打开时,就会加载WEB-INF下的资源文件,包括web.xml 和 tld文件,把它们加载到内存
2)我们在浏览器输入http://localhost:8080/TestArea/testit.jsp来访问jsp页面
3)服务器读取testit.jsp里的内容,当读到
<%@taglib uri="http://vmaxtam.com/mytag" prefix="mmt" %>
这一句的时候,就会在内存中找是否存在uri为http://vmaxtam.com/mytag的tld文件,找不到就会报错
4)继续读取jsp页面,读到<mmt:mytag>这个标签的时候,就会通过uri去找到tld文件,在tld文件中找到mytab是否被定义,是的话就得到它的tag-class的内容,然后去找到它对应的标签处理程序
5)实例化标签处理程序,利用生成的对象调用它里面的方法
这里服务器对标签处理程序里的方法也有一定的调用顺序 A)void setPageContext(PageContext pc) --传入pageContext对象
B)void setParent(Tag t) --如果有父标签,传入父标签对象,如果没有,则传入null
C)int doStartTag() --开始执行标签时调用。
D)int doEndTag() --结束标签时调用
E)void release() --释放资源
如果你没有重写上面的方法,系统将会调用它的父类里的方法~
为什么会是这个顺序调用,是有证据的,下面我们来看看jsp被翻译为java源文件里的截取:
private boolean _jspx_meth_itcast_005fshowIp_005f0(PageContext _jspx_page_context) throws Throwable { PageContext pageContext = _jspx_page_context; JspWriter out = _jspx_page_context.getOut(); // itcast:showIp 1) 实例化ShowIpTag对象 gz.itcast.tag.ShowIpTag _jspx_th_itcast_005fshowIp_005f0 = (gz.itcast.tag.ShowIpTag) _005fjspx_005ftagPool_005fitcast_005fshowIp_005fnobody.get(gz.itcast.tag.ShowIpTag.class); 2)调用setPageContext方法 _jspx_th_itcast_005fshowIp_005f0.setPageContext(_jspx_page_context); 3)调用setParent方法 _jspx_th_itcast_005fshowIp_005f0.setParent(null); 4)调用doStartTag方法 int _jspx_eval_itcast_005fshowIp_005f0 = _jspx_th_itcast_005fshowIp_005f0.doStartTag(); 5)调用doEndTag方法 if (_jspx_th_itcast_005fshowIp_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) { _005fjspx_005ftagPool_005fitcast_005fshowIp_005fnobody.reuse(_jspx_th_itcast_005fshowIp_005f0); return true; } _005fjspx_005ftagPool_005fitcast_005fshowIp_005fnobody.reuse(_jspx_th_itcast_005fshowIp_005f0); return false; }
自定义标签可以可控制标签体内的文本 和 结束标签后的文本是否输出~
@Override//遇到开始标签时执行的方法 public int doStartTag() throws JspException { //return Tag.SKIP_BODY; //标签体内容不向浏览器输出 return Tag.EVAL_BODY_INCLUDE;//标签体内容向浏览器输出 } @Override//遇到结束标签后执行的方法 public int doEndTag() throws JspException { //return Tag.EVAL_PAGE;//结束标签后的内容输出到浏览器 return Tag.SKIP_PAGE;//结束标签后的内容不输出到浏览器 }
那么如何重复输出标签体内的文本内容呢?TagSupper还提供了一个doAftetBody方法,我们只需要这样做:
int i = 4; @Override//每输出一次标签体的内容都会调用一次这个方法 public int doAfterBody() throws JspException { while(true) { if(i>0) { i--; return IterationTag.EVAL_BODY_AGAIN;//再执行一次便签体内的内容 }else{ break; } } return Tag.SKIP_BODY;//不输出标签体的内容 }