前言
只有光头才能变强。
文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y
为什么要使用自定义标签?
JSTL标签库只提供了简单的输出等功能,没有实现任何的HTML代码封装,并且某些复杂类型转换,或者逻辑处理的时候,JSTL标签库完成不了,需要自定义标签!
编写自定义标签的步骤:
编写一个实现Tag接口的Java类【标签处理器类】
在WEB-INF目录下创建tld(Tag Library Descriptor)文件,在tld文件中对标签处理类(实现Tag接口的Java类)进行描述
快速入门
public class showIp implements Tag { @Override public void setPageContext(PageContext pageContext) { } @Override public void setParent(Tag tag) { } @Override public Tag getParent() { return null; } @Override public int doStartTag() throws JspException { return 0; } @Override public int doEndTag() throws JspException { return 0; } @Override public void release() { }}class showIp implements Tag {
@Override
public void setPageContext(PageContext pageContext) {
}
@Override
public void setParent(Tag tag) {
}
@Override
public Tag getParent() {
return null;
}
@Override
public int doStartTag() throws JspException {
return 0;
}
@Override
public int doEndTag() throws JspException {
return 0;
}
@Override
public void release() {
}
}
@Overridepublic void setPageContext(PageContext pageContext) {}
public void setPageContext(PageContext pageContext) {
}
private PageContext pageContext = null;@Overridepublic void setPageContext(PageContext pageContext) { this.pageContext = pageContext;}null;
@Override
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
}
@Overridepublic int doStartTag() throws JspException { //获取到request对象 HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest(); //获取到客户机的ip地址 String ip = httpServletRequest.getRemoteAddr(); //获取输出到浏览器的对象 JspWriter jspWriter = pageContext.getOut(); //下面的异常只能捕获,因为子类的异常不能比父类多 try { jspWriter.write(ip); } catch (IOException e) { e.printStackTrace(); } return 0;}
public int doStartTag() throws JspException {
//获取到request对象
HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest();
//获取到客户机的ip地址
String ip = httpServletRequest.getRemoteAddr();
//获取输出到浏览器的对象
JspWriter jspWriter = pageContext.getOut();
//下面的异常只能捕获,因为子类的异常不能比父类多
try {
jspWriter.write(ip);
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
<?xml version="1.0" encoding="ISO-8859-1"?><taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <tlib-version>1.0</tlib-version> <short-name>zhongfucheng</short-name> <uri>/zhongfucheng</uri> <!-- Invoke 'Generate' action to add tags or functions --> <tag> <name>viewIp</name> <tag-class>tag.showIp</tag-class> <body-content>empty</body-content> </tag></taglib>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<tlib-version>1.0</tlib-version>
<short-name>zhongfucheng</short-name>
<uri>/zhongfucheng</uri>
<!-- Invoke 'Generate' action to add tags or functions -->
<tag>
<name>viewIp</name>
<tag-class>tag.showIp</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/cf9ad57e9e2fa08a4f4401c49ad76b08.png)
标签处理类详细说明
看完上面的程序,大部分人都是懵逼的。因为还不知道它具体是怎么用的,调用顺序是什么。
public interface Tag extends JspTag { int SKIP_BODY = 0; int EVAL_BODY_INCLUDE = 1; int SKIP_PAGE = 5; int EVAL_PAGE = 6; void setPageContext(PageContext var1); void setParent(Tag var1); Tag getParent(); int doStartTag() throws JspException; int doEndTag() throws JspException; void release();}interface Tag extends JspTag {
int SKIP_BODY = 0;
int EVAL_BODY_INCLUDE = 1;
int SKIP_PAGE = 5;
int EVAL_PAGE = 6;
void setPageContext(PageContext var1);
void setParent(Tag var1);
Tag getParent();
int doStartTag() throws JspException;
int doEndTag() throws JspException;
void release();
}
@Overridepublic int doEndTag() throws JspException { return SKIP_PAGE;}
public int doEndTag() throws JspException {
return SKIP_PAGE;
}
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/1752ca6cd3ddc650021268f51410390a.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f07dcf5797079ef54f7c5bb7e720d381.png)
tld文件详细说明
<tlib-version>1.0</tlib-version><short-name>myshortname</short-name><uri>http://mycompany.com</uri><tag> <name></name> <tag-class></tag-class> <body-content></body-content></tag></tlib-version>
<short-name>myshortname</short-name>
<uri>http://mycompany.com</uri>
<tag>
<name></name>
<tag-class></tag-class>
<body-content></body-content>
</tag>
TagSupport类
大部分时候我们都不需要实现Tag接口来编写自定义标签,TagSupport是Tag的一个模板类,实现了pageContext,parent的getter、setter方法以及一些其他的功能。我们要做的就是重写doStartTag()和doEndTag()方法
public class Demo1 extends TagSupport { @Override public int doStartTag() throws JspException { //获取到request对象 HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest(); String method = httpServletRequest.getMethod(); JspWriter jspWriter = pageContext.getOut(); try { jspWriter.write(method); } catch (IOException e) { e.printStackTrace(); } return 0; }}class Demo1 extends TagSupport {
@Override
public int doStartTag() throws JspException {
//获取到request对象
HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest();
String method = httpServletRequest.getMethod();
JspWriter jspWriter = pageContext.getOut();
try {
jspWriter.write(method);
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
}
<tag> <name>showMethod</name> <tag-class>tag.Demo1</tag-class> <body-content>empty</body-content></tag>
<name>showMethod</name>
<tag-class>tag.Demo1</tag-class>
<body-content>empty</body-content>
</tag>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f70718aa094f03f2debb4b24043b1964.png)
带属性的标签
上面我们编写的自定义标签都没有附带属性的,我们在使用core标签库的时候,标签一般都带有属性。
其实JSTL标签库的原理就是自定义标签,把自定义标签搞明白了,对JSTL标签库的使用就有更好的理解了!
public class Demo1 extends TagSupport { //创建成员对象,对应的setter、getter方法 private String format = null; @Override public int doStartTag() throws JspException { //创建日期格式化对象 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); //格式化日期并向浏览器输出 try { pageContext.getOut().write(simpleDateFormat.format(new Date())); } catch (IOException e) { e.printStackTrace(); } return 0; } public String getFormat() { return format; } public void setFormat(String format) { this.format = format; }}class Demo1 extends TagSupport {
//创建成员对象,对应的setter、getter方法
private String format = null;
@Override
public int doStartTag() throws JspException {
//创建日期格式化对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
//格式化日期并向浏览器输出
try {
pageContext.getOut().write(simpleDateFormat.format(new Date()));
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
}
<tag> <name>formatDate</name> <tag-class>tag.Demo1</tag-class> <body-content>empty</body-content> <attribute> <name>format</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute></tag>
<name>formatDate</name>
<tag-class>tag.Demo1</tag-class>
<body-content>empty</body-content>
<attribute>
<name>format</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/e59515823910a6d7602022a478336923.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/3c52724c4d5dcd1712f75f998972c423.png)
标签的继承关系
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/65082b03d4a8a187950f890540a11614.png)
IterationTag说明
public interface IterationTag extends Tag { int EVAL_BODY_AGAIN = 2; int doAfterBody() throws JspException;}interface IterationTag extends Tag {
int EVAL_BODY_AGAIN = 2;
int doAfterBody() throws JspException;
}
public class Demo1 extends TagSupport { @Override public int doStartTag() throws JspException { try { pageContext.getOut().write("hello"); } catch (IOException e) { e.printStackTrace(); } //执行标签体 return EVAL_BODY_INCLUDE; } @Override public int doAfterBody() throws JspException { //标签体不断循环,直到doAfterBody()返回的是SKIP_BODY return EVAL_BODY_AGAIN; }}class Demo1 extends TagSupport {
@Override
public int doStartTag() throws JspException {
try {
pageContext.getOut().write("hello");
} catch (IOException e) {
e.printStackTrace();
}
//执行标签体
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
//标签体不断循环,直到doAfterBody()返回的是SKIP_BODY
return EVAL_BODY_AGAIN;
}
}
<tag> <name>foreverEval</name> <tag-class>tag.Demo1</tag-class> <body-content>tagdependent</body-content></tag>
<name>foreverEval</name>
<tag-class>tag.Demo1</tag-class>
<body-content>tagdependent</body-content>
</tag>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f2300f4bbdb9d73069cb72207d8f3725.png)
//定义一个变量,规定标签体循环的次数int x = 0;@Overridepublic int doStartTag() throws JspException { try { pageContext.getOut().write("hello"); } catch (IOException e) { e.printStackTrace(); } //执行标签体 return EVAL_BODY_INCLUDE;}@Overridepublic int doAfterBody() throws JspException { x++; if (x >= 10) { return SKIP_BODY; } //标签体不断循环,直到doAfterBody()返回的是SKIP_BODY return EVAL_BODY_AGAIN;}
int x = 0;
@Override
public int doStartTag() throws JspException {
try {
pageContext.getOut().write("hello");
} catch (IOException e) {
e.printStackTrace();
}
//执行标签体
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
x++;
if (x >= 10) {
return SKIP_BODY;
}
//标签体不断循环,直到doAfterBody()返回的是SKIP_BODY
return EVAL_BODY_AGAIN;
}
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/c03c63d55ca3ef7cab3c2653ce027fd5.png)
BodyTag说明
前面我们已经使用到了带标签体的自定义标签了,前面的都是只能直接输出而得不到标签体的内容,既然得不到标签体的内容,就更别说修改标签体了!
public interface BodyTag extends IterationTag { /** @deprecated */ int EVAL_BODY_TAG = 2; int EVAL_BODY_BUFFERED = 2; void setBodyContent(BodyContent var1); void doInitBody() throws JspException;}interface BodyTag extends IterationTag {
/** @deprecated */
int EVAL_BODY_TAG = 2;
int EVAL_BODY_BUFFERED = 2;
void setBodyContent(BodyContent var1);
void doInitBody() throws JspException;
}
BodyTagSupport说明
public class BodyTagSupport extends TagSupport implements BodyTag { protected BodyContent bodyContent; public BodyTagSupport() { } public int doStartTag() throws JspException { return 2; } public int doEndTag() throws JspException { return super.doEndTag(); } public void setBodyContent(BodyContent b) { this.bodyContent = b; } public void doInitBody() throws JspException { } public int doAfterBody() throws JspException { return 0; } public void release() { this.bodyContent = null; super.release(); } public BodyContent getBodyContent() { return this.bodyContent; } public JspWriter getPreviousOut() { return this.bodyContent.getEnclosingWriter(); }}class BodyTagSupport extends TagSupport implements BodyTag {
protected BodyContent bodyContent;
public BodyTagSupport() {
}
public int doStartTag() throws JspException {
return 2;
}
public int doEndTag() throws JspException {
return super.doEndTag();
}
public void setBodyContent(BodyContent b) {
this.bodyContent = b;
}
public void doInitBody() throws JspException {
}
public int doAfterBody() throws JspException {
return 0;
}
public void release() {
this.bodyContent = null;
super.release();
}
public BodyContent getBodyContent() {
return this.bodyContent;
}
public JspWriter getPreviousOut() {
return this.bodyContent.getEnclosingWriter();
}
}
protected BodyContent bodyContent;public JspWriter getPreviousOut() { return this.bodyContent.getEnclosingWriter();}
public JspWriter getPreviousOut() {
return this.bodyContent.getEnclosingWriter();
}
public abstract class BodyContent extends JspWriter { private JspWriter enclosingWriter; protected BodyContent(JspWriter e) { super(-2, false); this.enclosingWriter = e; } public void flush() throws IOException { throw new IOException("Illegal to flush within a custom tag"); } public void clearBody() { try { this.clear(); } catch (IOException var2) { throw new Error("internal error!;"); } } public abstract Reader getReader(); public abstract String getString(); public abstract void writeOut(Writer var1) throws IOException; public JspWriter getEnclosingWriter() { return this.enclosingWriter; }}abstract class BodyContent extends JspWriter {
private JspWriter enclosingWriter;
protected BodyContent(JspWriter e) {
super(-2, false);
this.enclosingWriter = e;
}
public void flush() throws IOException {
throw new IOException("Illegal to flush within a custom tag");
}
public void clearBody() {
try {
this.clear();
} catch (IOException var2) {
throw new Error("internal error!;");
}
}
public abstract Reader getReader();
public abstract String getString();
public abstract void writeOut(Writer var1) throws IOException;
public JspWriter getEnclosingWriter() {
return this.enclosingWriter;
}
}
//将数据转变成Reader对象public abstract Reader getReader();//将数据转变成String对象public abstract String getString();
public abstract Reader getReader();
//将数据转变成String对象
public abstract String getString();
public class Demo1 extends BodyTagSupport { @Override public int doStartTag() throws JspException { //想要获取到标签体的内容,就要返回EVAL_BODY_BUFFERED变量 return EVAL_BODY_BUFFERED; } @Override public int doEndTag() throws JspException { //获取到标签体的内容 String value = bodyContent.getString(); //将标签体的内容转成小写并输出 try { this.getPreviousOut().write(value.toLowerCase()); } catch (IOException e) { e.printStackTrace(); } return super.doEndTag(); }}class Demo1 extends BodyTagSupport {
@Override
public int doStartTag() throws JspException {
//想要获取到标签体的内容,就要返回EVAL_BODY_BUFFERED变量
return EVAL_BODY_BUFFERED;
}
@Override
public int doEndTag() throws JspException {
//获取到标签体的内容
String value = bodyContent.getString();
//将标签体的内容转成小写并输出
try {
this.getPreviousOut().write(value.toLowerCase());
} catch (IOException e) {
e.printStackTrace();
}
return super.doEndTag();
}
}
<tag> <name>BodyContentToLowerCase</name> <tag-class>tag.Demo1</tag-class> <body-content>tagdependent</body-content></tag>
<name>BodyContentToLowerCase</name>
<tag-class>tag.Demo1</tag-class>
<body-content>tagdependent</body-content>
</tag>
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/448d76fb696ba167940bbb98a38061ba.png)
最后
乐于输出干货的Java技术公众号:Java3y。公众号内有200多篇原创技术文章、海量视频资源、精美脑图,不妨来关注一下!
![640](https://i-blog.csdnimg.cn/blog_migrate/4d6c064f75740d9ba93b0ebd0a25a4de.png)