使用SimpleTag支持自定义JSP标签

使用Java来开发JSP标记
    最近复习JSP中。我们知道JSP是Java WEB的一个规范。在这个规范之内我们可以自己去做很多事情。JSP API提供了接口允许我们自己去自定义JSP标签和EL表达式。自定义JSP标签的大致思想是这样的,实现一个包含标签参数和行为逻辑的类,这个类我们称它为标记处理器类,它实质上是一个Bean,我们设置标签的属性实际上是调用它的setter方法。接下来通过使用标记库描述文件(TLD)来描述标签的相关信息,以便在JSP页面中使用taglib指令时能顺利的找到它。下面我们来看看详细应该怎么去做。
    从JSP2.0开始引入了一个简单标记处理器接口——javax.servlet.jsp.tagext.SimpleTag接口,这个接口取代了原先JSP1.0提供的3个标记处理器接口,我们只需要使用SimpleTarget接口就可以实现所有类型的JSP标记。之所以称之为简单,是因为这样设计让开发者在编写程序上省了不少力气,但是它可以实现很复杂的功能,并不是说它的功能很简单。
    该接口包含了如下5个方法:
    void doTag();  //该方法包含了标签执行的业务逻辑
    JspTag getParent();  //获取该标签的父标签
    setJspBody(JspFragment body); //设置JSP标签体,关于JspFragment类我们稍后再讨论
    setJspContext(JspContext ctx);//设置JSP上下文
    setParent(JspTag parent);  //设置父标签
但是多数情况下我们不需要去亲自实现这个接口,因为作为开发者,我们关心的是业务逻辑,也就是doTag()方法的内容,这种情况我们只需要继承javax.servlet.jsp.tagext.SimpleTagSupport类即可,这个类为我们实现了SimpleTag接口,我们只需要去重写它的doTag()方法。下面我们来实现一个最简单的标签:给标签传递一个参数,让它在页面上显示出来.
首先我们要做的是写一个标记处理器类:
package test.jsp.tag.simple;

import java.io.IOException;

import javax.servlet.jsp.tagext.SimpleTagSupport;

public class HelloTag extends SimpleTagSupport{
   
    private String name;
   
    public void setName(String name){
        this.name = name;
    }

    @Override
    public void doTag()throws IOException{
        this.getJspContext().getOut().print("Hello! "+name);
    }
}

嗯,这是一个继承了SimpleTagSupport类的Bean,一样拥有属性、setter方法。唯一特别的是重写了父类的doTag()方法。在这个doTag()中,我们通过获得一个JSP上下文对象来向页面输出一句话:Hello!XXX。

下面是该介绍JspContext对象的时候了,这是一个抽象类,它唯一的子类是PageContext。这么说刚才所返回的实际对象是PageContext类型的。我们可以对其进行强制转换:PageContext pageCtx = (PageContext)this.getJspContext();

通过PageContext对象我们就可以访问到Request和Response对象了,如:

HttpServletRequest request = (HttpServletRequest)pageCtx.getRequest();
HttpServletResponse response = (HttpServletResponse)pageCtx.getResponse();

通过这种方式我们就可以在标签处理器中操作WEB应用各个作用域的数据了。

我们都知道在使用JSP标签时要在JSP页面开头使用taglib指令进行声明,如:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
taglib指令通过URL来对标签进行定位。但是它是如何做到的呢?这就要靠TLD了,TLD就是标记库描述文件(Tag Library Descriptor,TLD),我们看JSTL的JAR包中,META-INF文件夹下每个库都有一个对应的部署描述文件。TLD实际上是一个XML文件,里面描述了标记库和其中标记的信息。一个完整的TLD文件结构如下所示:


<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
   
  <tlib-version>1.1</tlib-version>
  <short-name>test</short-name>
  <uri>http://test</uri>
 
  <tag>
    <name>hello</name>
    <tag-class>test.jsp.tag.simple.HelloTag</tag-class>
    <body-content>empty</body-content>
    <attribute>
      <name>name</name>
      <required>true</required>
    </attribute>
  </tag>
 
  <tag>
    <name>if</name>
    <tag-class>test.jsp.tag.simple.IfTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
      <name>test</name>
      <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>
  <tag>
    <name>foreach</name>
    <tag-class>test.jsp.tag.simple.ForeachTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
      <name>items</name>
      <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
      <name>var</name>
    </attribute>
  </tag>

  <function>
   <description>
      Just for test
   </description>
   <name>add</name>
   <function-class>test.jsp.el.AddEl</function-class>
   <function-signature>int add(int,int)</function-signature>
  </function>
</taglib>

起始标签是taglib,<tlib-version>定义了taglib的版本号,<short-name>定义了标签库的简称,<uri>定义了URI标识,taglib就是通过此URI来找到相关的标记库的。
接下来的<tag>标签便是定义JSP标签的属性了:
以下是必须的属性
<name>标签名称
<tag-class>标记器类
<body-content>动作体类型,JSP2.0支持如下动作体:
empty 空标记
jsp:可以包含标签、EL和Scriptlet
scriptless:不允许Java脚本内容
tagdependent:对体不进行处理
<attribute>标签定义了标签参数。
其中:
<name>标签指定了参数的名称。
<required>指定了参数是否是必要的。true是必要,false是不必要
<rtexprvalue>指定了是否允许使用表达式(包括EL表达式和Java表达式),true为允许,false为不允许

<funtion>标签定义了EL表达式,我们稍后再做介绍。


如何执行动作体?
我们在编写JSP页面时经常会用到<c:if>和<c:forEach>之类的标签
<c:if test="true">
  <p>条件是真的,执行!</p>
</c:if>
只要满足条件,就会去执行动作体,那么我们怎么在自定义JSP标记中去执行动作体呢?
首先我们先要来研究一个叫做JspFragment的类。JspFragment代表了JSP标签的动作体,我们通过它的invoke方法就可以执行动作体,下面我们来实现一个类似于<c:if>的标签:
package test.jsp.tag.simple;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class IfTag extends SimpleTagSupport{

    private boolean test;
   
    public void setTest(boolean test){
        this.test = test;
    }
   
        @Override
    public void doTag()throws IOException,JspException{
        JspFragment body = getJspBody();
        //如果成立则执行相应逻辑
        if(test){
            body.invoke(null);
        }
    }
}
只要满足了条件,标签动作体就会执行。
invoke方法接受一个java.io.Writer对象,使用这个对象将内容输出到页面,如果不输出则可以给它传递一个null参数。

JSP中引入了EL表达式给我们的开发带来了很大的方便,同自定义标签一样,允许开发者去自定义EL表达式函数,定义EL表达式函数要比定义标签简单多了,我们甚至不需要去实现任何接口,假设我们要实现一个简单的EL表达式函数来计算两个数的和,就可以这样:

package test.jsp.tag.simple;

public class Calculator {

    public static int add(int a,int b){
        return a+b;
    }
   
    public static int minus(int a,int b){
        return a-b;
    }
   
    public static int multiply(int a,int b){
        return a*b;
    }
   
    public static int divide(int a,int b){
        return a/b;
    }
}

这个类中全部是static方法,这是一个工具类。
然后我们只需要在TLD声明即可:

<function>
   <description>
      Just for test
   </description>
   <name>add</name>
   <function-class>test.jsp.el.AddEl</function-class>
   <function-signature>int add(int,int)</function-signature>
</function>

function-signature类似于C语言中的函数声明,通过这个找到到底调用类中哪个工具方法。
使用的时候只需要这样就可以了:${test:add(1,2)}运行时输出结果为3


posted on 2010-08-01 15:10 迟宏泽 阅读(2981) 评论(1)  编辑  收藏

评论

# re: 使用SimpleTag支持自定义JSP标签 2015-03-25 17:46 iwwenbo

找了一下午才找到一篇写的这么详细清楚的,赞一个  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

<2010年8月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜