关于jsp自定义标签
2015-04-10 17:20
387 查看
本篇博客主要讲解关于如何自定义标签
声明:本篇博客为本人第二篇,如有什么错误希望博友指出,一起学习,本人感激不尽!
简单而且可重用的代码结构。比方说,在最新发布的JSPKit(在JSP Insider内)中,使用XML标签实现了对XML文档
的轻松访问。详情请戳这里(来自百度百科)
首先我们看一下TagSupport的结构
其中我们关注的几个方法
①doStartTag() 该方法表示开始处理标签
②doAfterBody()该方法在处理完开始标签后,用于处理标签体中的内容,由于此时我们并不能获取到标签体中的内容(要处理标签体中的内容请往下看),此方法在这里没有作用
③doEndTag() 处理结束标签,输出内容
自定义标签处理类
创建标签定义文件
最后在JSP中引入标签库
现在使用<test:simple value="testSimpleTag"/>就能在页面上显示testSimpleTag了
一个简单的JSP标签就开发好了.
接下来我们看看标签处理类内部的执行流程
①执行setPageContext方法,注入PageContext
当标签为单标签或双标签标签体为空时,此时显示的值只由后面第⑥步输出的值决定
当标签为双标签,且标签体有内容时,此时返回SKIP_BODY=0,显示的值为第⑥步输出的值,返回EVAL_BODY_INCLUDE=1或任意不为0的int的值时,显示的值为标签体+第⑥步输出的值.
⑤当标签为双标签且标签体有内容时,会执行doAfterBody 方法
当返回值为SKIP_BODY=0时或任意不等于2的int类型的值,此时会输出标签体中的内容,显示的值为标签体中的内容+第⑥步输出的内容.
当返回值为EVAL_BODY_AGAIN=2,此时同样会输出标签体中的内容,不同的是,此时会循环输出标签体中的内容,直至程序挂掉(特别注意)
⑥处理结束标签,执行doEndTag方法
这里也需要返回一个int类型的值,有两个预定义的返回值EVAL_PAGE=6与 SKIP_PAGE=5,这里同样是可以返回任意int类型的值.
当返回值为SKIP_PAGE=5时,JSP中此标签后面的内容将不做处理,即不会显示.
当返回值为EVAL_PAGE=6或任意值不等于5的int类型值时,JSP中此标签后的内容继续执行.
至此,一个简单自定义标签就处理结束.至于其他方法,本文不做深究.
首先看看BodyTagSupport的结构
其中我们关注的几个方法
①doStartTag() 处理开始标签
②doInitBody() 初始化标签体
③doAfterBody() 处理标签体
④doEndTag() 处理结束标签
相比不能处理标签体的TagSupport,我们关注的方法仅仅是多了一个初始化标签体的方法
首先还是创建标签处理类
接下来创建标签定义文件
经过简单标签的理解,能够处理带标签体的标签理解起来就轻松多了,但是此时的执行顺序稍有不同
①首先执行的是设置属性,本例中执行的是setKey方法
②然后执行的是doStartTag方法
当返回EVAL_BODY_INCLUDE=1时,将不再执行setBodyContent和doInitBody方法,此时显示的值为为标签体中的内容+doEndTag输出的内容
当返回SKIP_BODY=0时,将不再执行setBodyContent、doInitBody、doAfterBody,在doStartTag方法后直接跳到doEndTag方法,将不再显示标签体中的内容,显示为输出内容
当返回EVAL_BODY_BUFFERED=2或者任何不等于0、1的int类型的值时,会按照流程执行下去,显示内容为输出内容
③其次在执行setBodyContent方法,该方法有一个BodyContent参数,其中我们的标签体内容就封装在该对象中
④再执行doInitBody方法,该方法不需要返回内容,主要是用于对输出内容做一个预处理
⑤在执行doAfterBody方法,该方法需要返回返回一个int类型的值,此处与TagSupport中效果一致
⑥最后在执行doEndTag方法,此处返回值及效果与TagSupport中一致
至此,一个能处理标签体的标签就开发完成了.
最后补充下,当我们需要的一些参数不是固定的,参数个数也不是固定,此时不好枚举时,这种情况应该怎么解决呢? 此时我们就要用到动态属性这个东西了.
所谓动态属性,就是指属性名不确定,可有可无,个数不确定,最主要的是我们在定义文件中没有定义的属性.
我们要使用动态属性,首先标签处理类要实现javax.servlet.jsp.tagext.DynamicAttributes接口,并实现其中的setDynamicAttribute方法
下面是DynamicAttributes源码
然后在定义文件中加入
这样标签才支持动态属性,否则使用动态属性,会抛出org.apache.jasper.JasperException异常.
然后servlet才会循环调用setDynamicAttribute方法处理动态属性,此方法是在属性注入过后执行的.
此致,标签的书写就结束了!
感谢阅读!
声明:本篇博客为本人第二篇,如有什么错误希望博友指出,一起学习,本人感激不尽!
JSP标签库概念
JSP标签库,也称自定义标签库,可看成是一种通过JavaBean生成基于XML的脚本的方法。从概念上讲,标签就是很简单而且可重用的代码结构。比方说,在最新发布的JSPKit(在JSP Insider内)中,使用XML标签实现了对XML文档
的轻松访问。详情请戳这里(来自百度百科)
JSP标签库层次结构
开发自定义标签所涉及到的接口与类的层次结构(其中SimpleTag接口与SimpleTagSupport类是JSP2.0中新引入的)
JSP自定义标签
自定义一个简单标签
开发一个简单标签,我们只需要继承TagSupport或SimpleTagSupport即可,这里我们以继承TagSupport为例.首先我们看一下TagSupport的结构
其中我们关注的几个方法
①doStartTag() 该方法表示开始处理标签
②doAfterBody()该方法在处理完开始标签后,用于处理标签体中的内容,由于此时我们并不能获取到标签体中的内容(要处理标签体中的内容请往下看),此方法在这里没有作用
③doEndTag() 处理结束标签,输出内容
自定义标签处理类
package test; import java.io.IOException; import java.util.Enumeration; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; public class SimpleTag extends TagSupport { private String value; @Override // ③ 这里开始处理标签 public int doStartTag() throws JspException { return super.doStartTag(); } @Override // ④ 处理结束标签 public int doEndTag() throws JspException { try { pageContext.getOut().write(value); } catch (IOException e) { e.printStackTrace(); } return super.doEndTag(); } public int doAfterBody() throws JspException { return super.doAfterBody(); } public void release() { super.release(); } @Override // ② 默认parent tag 为空 public void setParent(Tag t) { super.setParent(t); } public Tag getParent() { return super.getParent(); } @Override // ① 设置pageContext public void setPageContext(PageContext pageContext) { super.setPageContext(pageContext); } public void setValue(String k, Object o) { super.setValue(k, o); } public Object getValue(String k) { return super.getValue(k); } public Enumeration<String> getValues() { return super.getValues(); } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }注:这个简单的标签,是不支持标签体,也就是说不管你有没有标签体,我们都不会处理.
创建标签定义文件
<?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3g.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <jsp-version>2.2</jsp-version> <!-- 标签默认前缀 --> <short-name>test</short-name> <!-- 引入标签URI --> <uri>http://www.test.com/tags/test</uri> <description> A replacement fixed string JSP tag libraries. </description> <tag> <!-- 标签名字 --> <name>simple</name> <!-- 标签处理类 --> <tag-class>test.SimpleTag</tag-class> <!-- ① empty 即标记体为空 ② scriptless 这个标记不能有脚本元素,但可以有模板文本和EL, 还可以是定制和标准动作 ③ tagdependent 标记体要看做是纯文本,所以不会计算EL,也不会出发标记/动作 ④ JSP 能放在JSP中的东西都能放在这个标记体中 --> <body-content>scriptless</body-content> <!-- 标签属性,可以有多个 --> <attribute> <!-- 属性名 --> <name>value</name> <!-- 是否必须 --> <required>true</required> <!-- Run-time Expression Value,是否支持JSP表达式 (脚本和el表达式)--> <rtexprvalue>true</rtexprvalue> <!-- 属性类型 --> <type>java.lang.String</type> </attribute> </tag> </taglib>然后在web.xml中配置标签
<jsp-config> <taglib> <taglib-uri>http://www.sctour.com/tags/test</taglib-uri> <taglib-location><![CDATA[/WEB-INF/tags/test.tld]]></taglib-location> </taglib> </jsp-config>
最后在JSP中引入标签库
<%@taglib uri="http://www.test.com/tags/test" prefix="test"%>
现在使用<test:simple value="testSimpleTag"/>就能在页面上显示testSimpleTag了
一个简单的JSP标签就开发好了.
接下来我们看看标签处理类内部的执行流程
①执行setPageContext方法,注入PageContext
<span style="white-space:pre"> </span>public void setPageContext(PageContext pageContext) { <span style="white-space:pre"> </span> super.setPageContext(pageContext); <span style="white-space:pre"> </span>}②执行setParent,设置当前标签的父标签
<span style="white-space:pre"> </span>public void setParent(Tag t) { <span style="white-space:pre"> </span> super.setParent(t); <span style="white-space:pre"> </span>}父标签,就是当前标签的外层标签(外层标签必须支持标签体,也就是需要处理标签体中的内容)
<span style="white-space:pre"> </span><sct:value key="88888888"> <span style="white-space:pre"> </span><test:simple value="testSimpleTag"/> <span style="white-space:pre"> </span></sct:value>③如果我们在标签中使用了属性,此时会调用标签处理类中的属性setter方法,本例调用的是setValue方法
public void setValue(String value) { this.value = value; }④属性注入过后,就开始处理标签了,此时调用doStartTag方法
public int doStartTag() throws JspException { return super.doStartTag(); }这里需要返回一个int类型的值,有两个返回值EVAL_BODY_INCLUDE=1和SKIP_BODY=0,实际上是可以返回任意int类型的值得,这里不推荐使用除前面定义好的两个值之外的.
当标签为单标签或双标签标签体为空时,此时显示的值只由后面第⑥步输出的值决定
当标签为双标签,且标签体有内容时,此时返回SKIP_BODY=0,显示的值为第⑥步输出的值,返回EVAL_BODY_INCLUDE=1或任意不为0的int的值时,显示的值为标签体+第⑥步输出的值.
⑤当标签为双标签且标签体有内容时,会执行doAfterBody 方法
public int doAfterBody() throws JspException { return super.doAfterBody(); }这里需要返回一个int类型的值,也有两个预定义的值EVAL_BODY_AGAIN=2与SKIP_BODY=0,这里同样是可以返回任意int类型的值.
当返回值为SKIP_BODY=0时或任意不等于2的int类型的值,此时会输出标签体中的内容,显示的值为标签体中的内容+第⑥步输出的内容.
当返回值为EVAL_BODY_AGAIN=2,此时同样会输出标签体中的内容,不同的是,此时会循环输出标签体中的内容,直至程序挂掉(特别注意)
⑥处理结束标签,执行doEndTag方法
public int doEndTag() throws JspException { try { pageContext.getOut().write(value);//这里输出的就是要显示的值 } catch (IOException e) { e.printStackTrace(); } return super.doEndTag(); }
这里也需要返回一个int类型的值,有两个预定义的返回值EVAL_PAGE=6与 SKIP_PAGE=5,这里同样是可以返回任意int类型的值.
当返回值为SKIP_PAGE=5时,JSP中此标签后面的内容将不做处理,即不会显示.
当返回值为EVAL_PAGE=6或任意值不等于5的int类型值时,JSP中此标签后的内容继续执行.
至此,一个简单自定义标签就处理结束.至于其他方法,本文不做深究.
接下来自定义一个处理带标签体的标签
当我们要处理标签体中的内容时,继承TagSupport不能帮助我们完成此功能,此时我们需要继承BodyTagSupport(实现BodyTag接口也可以,但我们会实现很多我们用不到的方法),TagSupport中有的功能,BodyTagSupport都有,BodyTagSupport继承自TagSupport.首先看看BodyTagSupport的结构
其中我们关注的几个方法
①doStartTag() 处理开始标签
②doInitBody() 初始化标签体
③doAfterBody() 处理标签体
④doEndTag() 处理结束标签
相比不能处理标签体的TagSupport,我们关注的方法仅仅是多了一个初始化标签体的方法
首先还是创建标签处理类
<pre name="code" class="java">import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyContent; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.DynamicAttributes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BodyTagTest extends BodyTagSupport implements DynamicAttributes { private static final long serialVersionUID = 1L; private Logger logger = LoggerFactory.getLogger(BodyTagTest.class); private String key; @Override public int doAfterBody() throws JspException { if (SCTourUtils.isEmpty(value) && bodyContent != null) { value = bodyContent.getString(); } /** * EVAL_BODY_AGAIN与SKIP_BODY 前者会再显示一次标签间的文字,后者则继续执行标签处理的下一步 */ return SKIP_BODY; } @Override public int doEndTag() throws JspException { // 当没有标签体 (单标签或标签体为空)时不会调用setBodyContent(BodyContent content)方法,此时bodyContent == null JspWriter writer = bodyContent == null ? pageContext.getOut() : bodyContent.getEnclosingWriter(); try { if (SCTourUtils.isEmpty(value)) { value = ""; } writer.println(value); } catch (IOException e) { logger.error("输出错误.", e); } finally { clear(); } /** * EVAL_PAGE与 SKIP_PAGE * 前者表示处理完标签后继续执行以下的JSP网页,后者是表示不处理接下来的JSP网页(标签后面的内容将不再处理和显示) */ return EVAL_PAGE; } @Override public void doInitBody() throws JspException { value = messageService.getContentValue(key, page); super.doInitBody(); } @Override public int doStartTag() throws JspException { return EVAL_BODY_BUFFERED; } @Override public void setBodyContent(BodyContent content) { super.setBodyContent(content); } private void clear() { this.key = null; this.bodyContent = null; this.id = null; value = null; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } }
接下来创建标签定义文件
<?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3g.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <jsp-version>2.2</jsp-version> <short-name>test</short-name> <uri>http://www.test.com/tags/body</uri> <description> A replacement fixed string JSP tag libraries. </description> <tag> <name>body</name> <tag-class>test.BodyTagTest</tag-class> <!-- ① empty 即标记体为空 <span style="white-space:pre"> </span> ② scriptless 这个标记不能有脚本元素,但可以有模板文本和EL, 还可以是定制和标准动作 ③ tagdependent 标记体要看做是纯文本,所以不会计算EL,也不会出发标记/动作 ④ JSP 能放在JSP中的东西都能放在这个标记体中 --> <body-content>scriptless</body-content> <attribute> <name>key</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> </tag> </taglib>接下来在web.xml中配置,与上面创建一样,此不再贴出来
经过简单标签的理解,能够处理带标签体的标签理解起来就轻松多了,但是此时的执行顺序稍有不同
①首先执行的是设置属性,本例中执行的是setKey方法
②然后执行的是doStartTag方法
public int doStartTag() throws JspException { return EVAL_BODY_BUFFERED; }方法需要返回一个int值,这里不再是两个预定义的值了,而是三个EVAL_BODY_INCLUDE=1、SKIP_BODY=0和EVAL_BODY_BUFFERED=2
当返回EVAL_BODY_INCLUDE=1时,将不再执行setBodyContent和doInitBody方法,此时显示的值为为标签体中的内容+doEndTag输出的内容
当返回SKIP_BODY=0时,将不再执行setBodyContent、doInitBody、doAfterBody,在doStartTag方法后直接跳到doEndTag方法,将不再显示标签体中的内容,显示为输出内容
当返回EVAL_BODY_BUFFERED=2或者任何不等于0、1的int类型的值时,会按照流程执行下去,显示内容为输出内容
③其次在执行setBodyContent方法,该方法有一个BodyContent参数,其中我们的标签体内容就封装在该对象中
④再执行doInitBody方法,该方法不需要返回内容,主要是用于对输出内容做一个预处理
⑤在执行doAfterBody方法,该方法需要返回返回一个int类型的值,此处与TagSupport中效果一致
⑥最后在执行doEndTag方法,此处返回值及效果与TagSupport中一致
至此,一个能处理标签体的标签就开发完成了.
最后补充下,当我们需要的一些参数不是固定的,参数个数也不是固定,此时不好枚举时,这种情况应该怎么解决呢? 此时我们就要用到动态属性这个东西了.
所谓动态属性,就是指属性名不确定,可有可无,个数不确定,最主要的是我们在定义文件中没有定义的属性.
我们要使用动态属性,首先标签处理类要实现javax.servlet.jsp.tagext.DynamicAttributes接口,并实现其中的setDynamicAttribute方法
下面是DynamicAttributes源码
<pre name="code" class="java"><span style="white-space:pre"> </span>public interface DynamicAttributes { /** * Called when a tag declared to accept dynamic attributes is passed * an attribute that is not declared in the Tag Library Descriptor. * * @param uri the namespace of the attribute, or null if in the default namespace.//<span style="color:#333333;">就是定义文件的命名空间,如果在默认命名空间,则为null</span> * @param localName the name of the attribute being set. // 属性名 * @param value the value of the attribute //属性值 * @throws JspException if the tag handler wishes to * signal that it does not accept the given attribute. The * container must not call doStartTag() or doTag() for this tag. */ public void setDynamicAttribute(String uri, String localName, Object value ) throws JspException; }
然后在定义文件中加入
<dynamic-attributes>true</dynamic-attributes>
这样标签才支持动态属性,否则使用动态属性,会抛出org.apache.jasper.JasperException异常.
然后servlet才会循环调用setDynamicAttribute方法处理动态属性,此方法是在属性注入过后执行的.
此致,标签的书写就结束了!
感谢阅读!
相关文章推荐
- 关于jsp2.0中简单的自定义标签
- 关于打包自定义标签,并导入项目使用时,出现java.lang.NoClassDefFoundError: JspException异常,解决方法和注意事项!
- 关于自定义标签 jsp
- 关于jsp页面自定义jstl标签简单项目配置
- 关于自定义标签 jsp
- 使用JSTL开发jsp自定义标签开发---迭代标签
- JSP页面中的自定义标签
- 创建你的第一个自定义jsp tag(jsp标签)
- JSP标签自定义(2)---getProperty
- 创建你的第一个自定义jsp tag(jsp标签)2
- 使用JSTL开发jsp自定义标签开发
- Web小结---Servlet,JSP,过滤器和监听器,四个作用域和九个内置对象,EL表达式语言,自定义标签,JSTL,国际化与汉字的编码
- 关于servlet2.5中自定义标签开发的一点见解
- 通过JSP自定义标签创建丰富多彩的超链接(Creating Richer Hyperlinks with JSP Custom Tags)
- Web小结---Servlet,JSP,过滤器和监听器,四个作用域和九个内置对象,EL表达式语言,自定义标签,JSTL,国际化与汉字的编码
- Web小结---Servlet,JSP,过滤器和监听器,四个作用域和九个内置对象,EL表达式语言,自定义标签,JSTL,国际化与汉字的编码
- 自定义JSP标签
- JSP标签自定义(3)---setProperty
- JSP标签自定义(1)---useBean
- JSP标签自定义(1)---useBean