javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段,这段JSP片段中不能包含JSP脚本元素。
WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中只定义了两个方法,如下所示:
getJspContext方法
用于返回代表调用页面的JspContext对象.
public abstract void invoke(java.io.Writer out)
用于执行JspFragment对象所代表的JSP代码片段,参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果 传递给参数out的值为null,则将执行结果写入到JspContext.getOut()方法返回的输出流对象中。(简而言之,可以理解为写给浏览器)
JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:
在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。
自定义标签可以定义一个或多个属性,这样,在JSP页面中应用自定义标签时就可以设置这些属性的值,通过这些属性为标签处理器传递参数信息,从而提高标签的灵活性和复用性。
要想让一个自定义标签具有属性,通常需要完成两个任务:
为自定义标签定义属性时,每个属性都必须按照JavaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收 JSP页面调用自定义标签时传递进来的属性值。 例如属性url,在标签处理器类中就要定义相应的setUrl(String url)方法。
在标签处理器中定义相应的set方法后,JSP引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用set属性方法,为标签设置属性。
范例1:通过标签的属性控制标签体的执行次数
示例代码如下:
SimpleTagDemo5.java
1 package me.gacl.web.simpletag; 2 3 import java.io.IOException; 4 import javax.servlet.jsp.JspException; 5 import javax.servlet.jsp.tagext.SimpleTagSupport; 6 7 /** 8 * @author gacl 9 * SimpleTagSupport类实现了SimpleTag接口, 10 * SampleTagDemo5类继承SimpleTagSupport 11 * 通过标签的属性控制标签体的执行次数 12 */ 13 public class SimpleTagDemo5 extends SimpleTagSupport { 14 15 /** 16 * 定义标签的属性 17 */ 18 private int count; 19 20 /**count属性对应的set方法 21 * @param count 22 */ 23 public void setCount(int count) { 24 this.count = count; 25 } 26 27 /* 简单标签使用这个方法就可以完成所有的业务逻辑 28 * @see javax.servlet.jsp.tagext.SimpleTagSupport#doTag() 29 * 重写doTag方法,通过标签的属性控制标签体的执行次数 30 */ 31 @Override 32 public void doTag() throws JspException, IOException { 33 for (int i = 0; i < count; i++) { 34 this.getJspBody().invoke(null); 35 } 36 } 37 38 }
在WEB-INF目录下的tld文件中添加对该标签的描述,如下所示:
1 <tag> 2 <!-- 标签名 --> 3 <name>demo5</name> 4 <!-- 标签处理器类--> 5 <tag-class>me.gacl.web.simpletag.SimpleTagDemo5</tag-class> 6 <!-- 标签体允许的内容--> 7 <body-content>scriptless</body-content> 8 9 <!-- 标签的属性描述 --> 10 <attribute> 11 <description>描述标签的count属性</description> 12 <!-- 标签的count属性 --> 13 <name>count</name> 14 <required>true</required> 15 <!-- rtexprvalue用来指示标签的属性值是否可以是一个表达式, 16 一般设置为true,true就表示允许标签的属性值可以是一个表达式--> 17 <rtexprvalue>true</rtexprvalue> 18 </attribute> 19 </tag>
在jsp页面引入标签库并使用自定义标签
1 <%@ page language="java" pageEncoding="UTF-8"%> 2 <%--在jsp页面中导入自定义标签库 --%> 3 <%--<%@taglib uri="/simpletag" prefix="gacl" %>--%> 4 <%--在jsp页面中也可以使用这种方式导入标签库,直接把uri设置成标签库的tld文件所在目录 --%> 5 <%@taglib uri="/WEB-INF/simpletag.tld" prefix="gacl"%> 6 <!DOCTYPE HTML> 7 <html> 8 <head> 9 <title>通过标签的属性控制标签体的执行次数</title> 10 </head> 11 12 <body> 13 <%--在jsp页面中使用自定义标签,标签有一个count属性 --%> 14 <gacl:demo5 count="2"> 15 <h1>孤傲苍狼</h1> 16 </gacl:demo5> 17 </body> 18 </html>
运行效果如下:
如果标签的属性值是8种基本数据类型,那么在JSP页面在传递字符串时,JSP引擎会自动转换成相应的类型,但如果标签的属性值是复合数据类型,那么JSP引擎是无法自动转换的
范例2:标签接收的属性值是一个复合数据类型,该如何给标签的属性赋值
示例代码如下:
SimpleTagDemo6.java
1 package me.gacl.web.simpletag; 2 3 import java.io.IOException; 4 import java.util.Date; 5 6 import javax.servlet.jsp.JspException; 7 import javax.servlet.jsp.tagext.SimpleTagSupport; 8 9 /** 10 * @author gacl 11 * SimpleTagSupport类实现了SimpleTag接口, 12 * SampleTagDemo6类继承SimpleTagSupport 13 * 标签的属性说明 14 */ 15 public class SimpleTagDemo6 extends SimpleTagSupport { 16 17 /** 18 * 定义标签的属性 19 */ 20 private Date date; 21 22 /**date属性对应的set方法 23 * @param date 24 */ 25 public void setDate(Date date) { 26 this.date = date; 27 } 28 29 /* 简单标签使用这个方法就可以完成所有的业务逻辑 30 * @see javax.servlet.jsp.tagext.SimpleTagSupport#doTag() 31 * 重写doTag方法,输出date属性值 32 */ 33 @Override 34 public void doTag() throws JspException, IOException { 35 this.getJspContext().getOut().write(date.toLocaleString()); 36 } 37 }
在WEB-INF目录下的tld文件中添加对该标签的描述,如下所示:
1 <tag> 2 <!-- 标签名 --> 3 <name>demo6</name> 4 <!-- 标签处理器类--> 5 <tag-class>me.gacl.web.simpletag.SimpleTagDemo6</tag-class> 6 <!-- 标签体允许的内容--> 7 <body-content>empty</body-content> 8 9 <!-- 标签的属性描述 --> 10 <attribute> 11 <description>描述标签的date属性</description> 12 <!-- 标签的date属性,复合数据类型 --> 13 <name>date</name> 14 <required>true</required> 15 <!-- rtexprvalue用来指示标签的属性值是否可以是一个表达式, 16 一般设置为true,true就表示允许标签的属性值可以是一个表达式--> 17 <rtexprvalue>true</rtexprvalue> 18 </attribute> 19 </tag>
在jsp页面引入标签库并使用自定义标签
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%--在jsp页面中导入自定义标签库 --%> 3 <%--<%@taglib uri="/simpletag" prefix="gacl" %>--%> 4 <%--在jsp页面中也可以使用这种方式导入标签库,直接把uri设置成标签库的tld文件所在目录 --%> 5 <%@taglib uri="/WEB-INF/simpletag.tld" prefix="gacl"%> 6 <!DOCTYPE HTML> 7 <html> 8 <head> 9 <title>如果标签接收的属性值是一个复合数据类型,该如何给标签的属性赋值</title> 10 </head> 11 12 <body> 13 <%-- 14 在jsp页面中使用自定义标签,标签有一个date属性 ,是一个复合数据类型 15 如果标签的属性值是8种基本数据类型,那么在JSP页面在传递字符串时,JSP引擎会自动转换成相应的类型 16 但如果标签的属性值是复合数据类型,那么JSP引擎是无法自动转换的, 17 这里将一个字符串赋值给demo6标签的date属性,在运行标签时就会出现如下错误: 18 Unable to convert string "1988-05-07" to class "java.util.Date" for attribute "date": 19 Property Editor not registered with the PropertyEditorManager 20 <gacl:demo6 date="1988-05-07"> 21 </gacl:demo6> 22 --%> 23 <%--如果一定要给标签的复合属性赋值,那么可以采用表达式的方式给复合属性赋值,如下所示: --%> 24 25 <% 26 Date d = new Date(); 27 request.setAttribute("date", d); 28 %> 29 30 <gacl:demo6 date="${date}"/> 31 <hr/> 32 <gacl:demo6 date="<%=new Date()%>"/> 33 </body> 34 </html>
运行效果如下:
<tag>元素的<attribute>子元素用于描述自定义标签的一个属性,自定义标签所具有的每个属性都要对应一个<attribute>元素
例如:
1 <tag> 2 <!-- 标签名 --> 3 <name>demo5</name> 4 <!-- 标签处理器类--> 5 <tag-class>me.gacl.web.simpletag.SimpleTagDemo5</tag-class> 6 <!-- 标签体允许的内容--> 7 <body-content>scriptless</body-content> 8 9 <!-- 标签的属性描述 --> 10 <attribute> 11 <description>描述标签的count属性</description> 12 <!-- 标签的count属性 --> 13 <name>count</name> 14 <required>true</required> 15 <!-- rtexprvalue用来指示标签的属性值是否可以是一个表达式, 16 一般设置为true,true就表示允许标签的属性值可以是一个表达式--> 17 <rtexprvalue>true</rtexprvalue> 18 </attribute> 19 </tag>
<attribute>元素的子元素说明:
到此,简单标签的开发技术就算是全部讲完了,在下一篇博文中会编写一些自定义标签的案例来加深自定标签技术的学习和理解。