[toc]
简单标签和标签文件
传统自定义标签的方法较为复杂,需要考虑处理类中doStartTag()和doEndTag()的返回值。JSP2中引入了新的标签扩展机制,称为“简单标签扩展”。
可以通过定义实现javax.servlet.jsp.tagext.SimpleTag
接口的标签处理类,
或使用标签文件.tag或.tagx来定义标签。
1. 实现SimpleTag接口
javax.servlet.jsp.tagext.SimpleTag
接口,包中已有SimpleTagSupport类实现了接口,开发时只需继承该类,复写doTag()方法即可。
1.1 接口定义方法
void setJspContext(JspContext pc)
:容器调用,向SimpleTag对象传递当前JSPContext对象。JspContext类是PageContext类的父类。其中包含了对各种范围内属性的存取方法void setParent(JspTag parent)
:容器调用,向SimpleTag对象传递父标签的JSPTag对象JspTag getParent()
:返回父标签的JspTag对象void setJspBody(JspFragment jspBody)
:容器调用,向SimpleTag对象传递标签主体,参数表示主体,封装了一段JSP代码void doTag()
:负责具体标签处理过程,没有返回值
1.2 接口流程
SimpleTag对象由容器负责创建。当容器执行JSP文件时,遇到自定义的简单标签时,都会创建一个SimpleTag对象。标签处理完毕,就销毁该对象。而传统自定义标签,会缓存处理类实例以重用。
流程:
- 容器调用SimpleTag对象的setJspContext()和setParent()方法,把当前JSP页面的JspContext对象,以及父标签处理对象传给当前SimpleTag对象。如无父标签,则null
- 容器调用SimpleTag对象的一系列set方法,设置对象的属性。如标签无属性则无需
- 如有标签主体,容器调用setJSPBody()方法,设置主体
- 容器调用doTag()方法,完成处理标签的具体逻辑
1.3 普通的简单标签
<hello>标签,输出"This is my first tag!"。
简单标签处理类:
1 | public class HelloTag extends SimpleTagSupport { |
使用该标签的JSP例子:
1 | <%@ taglib prefix="mm" uri="/mytaglib" %> |
运行步骤:
-
编译HelloTag.java,编译时把<CATALINA_HOME>/lib/jsp-api.jar放下classpath中,把编译生成类文件放在web-app/WEB-INF/classes/mypack/HelloTag.class
-
在web-app/WEB-INF/mytag.tld中添加标签描述符
1
2
3
4
5
6<tag>
<description>prints hello</description>
<name>hello</name>
<tag-class>mypack.HelloTag</tag-class>
<body-content>empty</body-content>
</tag>注:简单标签的<body-content>元素,可选值empty、scriptless、tagdependent,由于不能包含Java片段,所以没有jsp选项
-
在web-app/WEB-INF/web.xml中加入mytaglib标签库
1
2
3
4<taglib>
<taglib-uri>/mytaglib</taglib-uri>
<taglib-location>/WEB-INF/mytaglib.tld</taglib-location>
</taglib>
1.4 带属性和标签主体的简单标签
<welcome>标签,将属性username和主体一同输出。
处理类
1 | public class WelcomeTag extends SimpleTagSupport { |
注:JspFragment对象,代表一段JSP代码,其invoke(Writer)方法负责执行所封装的JSP代码,并通过参数输出结果;若参数null,则输出到当前输出流
使用标签:
1 | <mm:welcome username="${param.username}"> |
web-app/WEB-INF/mytag.tld:
1 | <tag> |
1.5 带动态属性的简单标签
<max>标签,负责找出属性中最大值,存入page范围。
动态属性:数目不固定的属性。
处理类:
1 | public class MaxTag extends SimpleTagSupport implements DynamicAttributes{ |
注:实现了javax.servlet.jsp.tagext.DynamicAttributes接口,定义了setDynaminAttribute()方法;容器反复调用此方法向SImpleTag对象传递动态属性。
使用标签:
1 | <mm:max num1="100" num2="200" num3="300"/> |
web-app/WEB-INF/mytag.tld:
1 | <tag> |
2. 使用标签文件
- 标签文件使用JSP编写,可以不包含Java。拓展名通常为.tag,若使用XML语言则为.tagx
- 标签名字就是文件名字
- 标签文件和JSP的区别仅在于:
- JSP中page指令在标签文件中不能使用
- 标签文件中增加了tag指令、attribute指令和variable指令
- <jsp:invoke>和<jsp:doBody>两个标准动作元素只能在标签文件中使用
- 使用时标签文件可统一放在webapp/WEB-INF/tags目录下
- 标签文件的自定义标签方法,无需TLD,只需在使用的JSP页面中声明即可
<%@ taglib prefix="mm" tagdir="/WEB-INF/tags" %>
- 容器自动为tags和子目录配置隐含TLD,包含以下元素:
- <tlib-version>:1.1
- <short-name>:路径名设定,WEB-INF/tags,则为tags;WEB-INF/tags/a/b/c,则为a-b-c
- 为该目录中每个标签文件配置<tag-file>元素,子元素<name>设置文件名,<path>设置标签文件路径,路径以/WEB-INF开始
- 标签文件打包JAR时,放在META-INF/tags下,并提供TLD,<path>以/META-INF开始
- 容器遇到标签时,解析并编译.tag标签文件,在<CATA_LINA>/work/Catalina/localhost/webapp/org/apache/jsp/tag/web下生成处理类name_tag类,即实际上标签文件仍是简单标签处理类,只是由容器翻译
2.1 标签文件隐含对象
request(HttpServletRequest):存于request范围
response(HTTPServletResponse):存于page
jspContext(JspContext):page
application(ServletContext):application
out(JspWriter):page
config(ServletConfig):page
session(HttpSession):session
与JSP相比,标签文件不存在page和exception隐含对象,存在jspContext对象,是JSP中的pageContext的父类。
2.2 标签文件的指令
包含taglib。include、tag。attribute、variable五种指令,后三种是特有。
- tag指令:与JSP中的page指令类似,设置整个标签文件的一些属性
- display-name:为标签指定一个简短名字,默认不含扩展名的文件名
- body-content:指定标签主体格式,可选empty、scriptless、tagdependent,默认scriptless
- dynamic-attributes:指定动态属性名,容器翻译为简单标签处理类时,类中创建Map对象,存放动态属性的名字和值,属性名key,属性值value
- small-icon:为标签指定小图标文件gif jpeg的路径,16*16
- large-icon:为标签指定大图标文件gif jpeg的路径,32*32
- description
- example:提供使用本标签的例子的信息描述
- language:设定编程语言,默认Java
- import:引入Java类
- pageEncoding:文件的字符编码
- isELIgnored;是否忽略EL表达式,默认false,会解析EL表达式
- attribute指令:类似TLD中<attribute>元素,声明自定义标签的属性,指令包含以下属性
- name:对于本指令是必需,指定指令所代表的属性名字
- required:本属性是否必需,默认false
- fragment:本属性是否是JspFragment对象,默认false;若true,则无需设置rtexpvalue和type属性,此时二者默认为true和JspFragment
- rtexpvalue:本属性是否可以是一个运行时表达式,默认true
- type:本属性类型,默认String,需要是类,不能是基本型
- description
- variable指令:类似于TLD中的<variable>元素,设置标签为JSP页面提供变量
- name-given:指定变量名字
- name-from-attribute:用标签的某个属性的值作为变量名称
- alias:定义一个本地范围的属性保存这个变量的值,当name-from-attribute时必须alias
- variable-class:变量的Java类型,默认String
- declare:是否引用新对象,默认true
- scope:变量的范围,可选AT_BEGIN(从标签起始标记到JSP页面结束)、NESTED(标签主体范围)、AT_END(从标签结束标签到JSP页面结束),默认NESTED
- description
2.3 <jsp:invoke>和<jsp:doBody>动作元素
- <jsp:invoke>用于执行标签的JspFragment类型的属性所包含的JSP代码,并把执行结果输出到当前JspWriter对象中,或保存到指定的命名变量中
- fragment:必需属性,指定类型为JspFragment的属性名称
- var:指定一个命名变量名字,保存JspFragment对象执行结果
- varReader:制定一个Reader类型的命名变量,保存了JspFragment执行结果
- 如以上两保存属性都无,则输出到当前JspWriter对象中
- scope:为var或varReader指定存放范围
- <jsp:doBody>用于执行标签主体,并把结果输出到当前JspWriter对象中,或保存到指定命名变量中,有var、varReader、socpe属性
2.4 带属性和标签主体的标签文件
本例简单的display.tag,定义了一个表格模板,包含color、bgcolor、title属性,都是String类型,在标签文件中可以通过${color}的形式访问属性。
标签文件 display.tag:
1 | <%@ attribute name="color" %> |
使用标签:
1 | <tags:display color="#ff000" bgcolor="#ffc0c0" title="Travel"> |
2.5 使用JspFragment的标签文件
本例welcome.tag,根据属性username,输出不同文字。
标签文件:
1 | <%@ tag pageEncoding="GB2312" %> |
通过<jsp:invoke>执行JspFragment类型的username属性,并把结果存放在命名变量user中。然后根据user,输出不同文字。
使用标签:
1 | <mm:welcome> |
因为属性username是Fragment类型,就需要<jsp:attribute>设定;同时,标签若嵌入了<jsp:attribute>,就要用<jsp:body>设置标签主体。
2.6 带变量的标签文件
JSP页面和标签之间交互数据方法:
1. 共享数据放在特点范围内
2. 在JSP页面中设置标签的属性,实现JSP向标签的数据传递
3. 在标签中定义变量,实现标签向JSP页面的数据传递
简单标签文件的variable指令用于定义标签变量。
本例precode.tag,具有一个code变量
1 | <%"preserve" fragment="true" %> name= |
把标签主体的结果存放在code中,<jsp:invoke>执行preserve包含的JSP代码,把结果输出到当前JspWriter中。
使用标签:
1 | <mm:precode> |
标签doBody,将TOMCAT存入code变量;然后invoke执行preserve属性包含的JSP代码,输出code的值,最终页面输出TOMCAT。