一、简单标签
1, 简介:由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广, SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。
2, 实现SimpleTag接口的标签称为简单标签。简单标签共有五个方法
setJspContext方法:用于把JSP页面的pageContext对象传递给标签处理器对象
setParent方法:用于把父标签处理器对象传递给当前标签处理器对象
getParent方法:用于获得当前标签的父标签处理器对象
setJspBody方法:用于把代表标签体的JspFragment对象传递给标签处理器对象
doTag方法:
用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以抛出 javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。
3, web容器执行简单标签的步骤
a.WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
b.WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。
c.如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。
d.如果简单标签有标签体,WEB容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。
e.执行标签时WEB容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。
4,简单标签实例:sun公司针对SimpleTag接口提供了一个默认实现类SimpleTagSupport,继承这个类则可以完成简单标签开发
4.1编写标签处理器类
package com.chen.ying; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; public class SimpleTagDemo01 extends SimpleTagSupport { public void doTag()throws JspException,IOException{ //得到代表标签体的JspFragment用以操作标签体; JspFragment jfm=this.getJspBody(); jfm.invoke(null);//默认将标签体内容输出到浏览器 } }
4.2在标签库中配置标签
4.3在jsp中使用
5,控制标签体内容重复执行
5.1编写标签处理类
package com.chen.ying; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; public class SimpleTagDemo02 extends SimpleTagSupport { public void doTag()throws JspException,IOException{ //得到代表标签体的JspFragment用以操作标签体; JspFragment jfm=this.getJspBody(); for(int i=1;i<=3;i++){ jfm.invoke(null);//默认将标签体内容重复输出到浏览器 } } }
6,修改jsp内容并输出
6.1编写标签处理器类,将标签体内容转换成大写
public class SimpleTagDemo03 extends SimpleTagSupport { public void doTag()throws JspException,IOException{ //得到代表标签体的JspFragment用以操作标签体; JspFragment jfm=this.getJspBody(); StringWriter sw=new StringWriter();//String流 jfm.invoke(sw);//将标签体输出到String流中 String content=sw.getBuffer().toString();//得到流中内容 content=content.toUpperCase();//转换成大写 PageContext pageContext=(PageContext)this.getJspContext(); //将修改后的content输出到浏览器中 pageContext.getOut().write(content); } }
7,控制整个jsp页面是否执行
编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法抛出SkipPageException异常即可,jsp收到这个异常,将忽略标签余下jsp页面的执行。
public void doTag() throws JspException, IOException { //抛出一个SkipPageException异常就可以控制标签之后的Jsp不执行 throw new SkipPageException(); }
8,JspFragment类
javax.servlet.jsp.tagext.JspFragment类的实例对象代表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()方法返回的输出流对象中。(简而言之,可以理解为写给浏览器)
Invoke方法详解
JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:
在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。
9,带属性的简单标签开发
简单标签的属性设置与传统标签的属性设置类似。需要注意的是如果标签的属性值是8种基本数据类型,那么在JSP页面在传递字符串时,JSP引擎会自动转换成相应的类型,但如果标签的属性值是复合数据类型,那么JSP引擎是无法自动转换的
下面研究如何为复合数据类型的属性值赋值:
上面对一个日期类型的属性赋值,可以用表达式语言或表达式给属性赋值。
10,DynamicAttribute接口:使用此接口,可以接收动态属性
此接口只有一个接收动态属性的方法,当标签中含有未在标签库配置的动态属性时便会循环调用此方法
public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {
}
10.1编写一个标签处理类,可以接收动态填写的属性,并将属性相加值输出到浏览器
public class SimpleTagDemo04 extends SimpleTagSupport implements DynamicAttributes{ private Map<String,Float> map=new HashMap<String,Float>(); public void doTag()throws JspException,IOException{ Float sum=0.0f; for(Map.Entry<String, Float> m:map.entrySet()){ sum+=m.getValue();//将map中的属性值累加 } super.getJspContext().getOut().write(sum+"");//输出到浏览器 } public void setDynamicAttribute(String uri, String localName, Object value) throws JspException { //循环执行此函数,接收动态属性 map.put(localName,Float.parseFloat(value.toString())); } }
10.2在标签库中配置此标签
10.3在jsp使用此标签
结果
二、 标签开发细节
1,开发简单标签类时,不要直接去实现SimpleTag接口,而是应该继承SimpleTagSupport类,SimpleTagSupport类是 SimpleTag接口的一个默认实现类,通过继承SimpleTagSupport类,就可以直接使用SimpleTagSupport类已经实现的那 些方法,如果SimpleTagSupport类的方法实现不满足业务要求,那么就可以根据具体的业务情况将相应的方法进行重写。
2,tld文件中有四种标签体(body-content)类型 :empty、JSP、scriptless、tagdependent
在简单标签(SampleTag)中标签体body-content的值只允许是empty、scriptless、tagdependent,不允许设置成JSP,如果设置成JSP就会出现异常: jsp标签技术出现的目的就是为了移除在jsp页面上编写的java代码的,如果在jsp标签中允许出现java代码,那么就违背了jsp标签技术设计时的初衷了。所以在简单标签的标签体中是不允许出现java代码的。
如果标签体body-content的值设置成tagdepentend,那么就表示标签体里面的内容是给标签处理器类使用的,
例如:开发一个查询用户的sql标签,此时标签体中的SQL语句就是给SQL标签的标签处理器来使用的
<gacl:sql>SELECT * FROM USER</gacl:sql>
3,如果有两个标签库的uri相同,则不能简单地通过uri引用标签库,可通过uri=”标签库tld目录”区分
<%@taglib uri="/WEB-INF/gacl.tld" prefix="gacl"%>、
<%@taglib uri="/WEB-INF/simpletag.tld" prefix="gacl"%>
三、小结
1、编写一个类继承SimpleTagSupport类,然后根据业务需要重写SimpleTagSupport类中已经实现了的方法,一般情况下只需要重写doTag()方法即可。
2、在WEB-INF目录下创建一个tld文件,在tld文件中添加对该标签的描述。tld文件不一定放在WEB-INF目录下,也可以放在别的目录,习惯是放在WEB-INF目录下。