JSTL标签库只提供了简单的输出等功能,没有实现任何的HTML代码封装,并且某些复杂类型转换,或者逻辑处理的时候,JSTL标签库完成不了,需要自定义标签!
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() {
}
}
@Override
public void setPageContext(PageContext pageContext) {
}
private PageContext pageContext = null;
@Override
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
}
@Override
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>
看完上面的程序,大部分人都是懵逼的。因为还不知道它具体是怎么用的,调用顺序是什么。
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();
}
@Override
public int doEndTag() throws JspException {
return SKIP_PAGE;
}
<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>
大部分时候我们都不需要实现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;
}
}
<tag>
<name>showMethod</name>
<tag-class>tag.Demo1</tag-class>
<body-content>empty</body-content>
</tag>
上面我们编写的自定义标签都没有附带属性的,我们在使用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;
}
}
<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>
public 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;
}
}
<tag>
<name>foreverEval</name>
<tag-class>tag.Demo1</tag-class>
<body-content>tagdependent</body-content>
</tag>
//定义一个变量,规定标签体循环的次数
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;
}
前面我们已经使用到了带标签体的自定义标签了,前面的都是只能直接输出而得不到标签体的内容,既然得不到标签体的内容,就更别说修改标签体了!
public interface BodyTag extends IterationTag {
/** @deprecated */
int EVAL_BODY_TAG = 2;
int EVAL_BODY_BUFFERED = 2;
void setBodyContent(BodyContent var1);
void doInitBody() throws JspException;
}
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();
}
}
protected BodyContent bodyContent;
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;
}
}
//将数据转变成Reader对象
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();
}
}
<tag>
<name>BodyContentToLowerCase</name>
<tag-class>tag.Demo1</tag-class>
<body-content>tagdependent</body-content>
</tag>
如果文章有错的地方欢迎指正,大家互相交流。