天天看点

第六章_编写定制标签

认识到了用javabean分离表现逻辑和业务逻辑的不足之处之后,jsp1.1就定义了定制标签。定制标签具有javabeans所没有的优势。例如,定制标签可以访问jsp隐式对象,可以带有属性等。

在jsp2.0中,他们在javax.servlet.jsp.tagext包中添加了新的接口:simpletag。实现simpletag接口的标签处理器称作简单的标签处理器,实现tag、iteration或bodytag接口的标签处理器称作典型的标签处理器。

简单的标签处理器的声明周期更加简单,并且更容易。simpletag接口中只有一个方法:dotag,并且在标签调用时只执行一次。业务逻辑、迭代及主体操作代码都要在这里编写。简单的标签处理器中的主体是用一个jspfragment类实例表示的。

一个简单的标签处理器的生命周期如下:

1、jsp容器通过调用其无参构造器,创建一个简单标签处理器实例。因此,简单的标签处理器必须有一个无参构造器。

2、jsp容器调用setjspcontext方法,同时传递一个jspcontext对象。jspcontext最重要的方法是getout,它返回一个jspwriter,用于将响应发送到客户端。setjspcontext方法的签名如下:

public void setjspcontext(jspcontext jspcontext)

大多数时候,会需要将传进的jspcontext赋给一个类变量,以便供后续使用。

3、如果表示标签处理器的定制标签是嵌套在另一个标签中的,jsp容器就会调用setparent方法。该方法具有以下签名:

public void setparent(jsptag parent)

4、jsp容器为给该标签定义的每个属性都调用设置方法。(setter)

5、如果标签中有主体内容,jsp将调用simpletag接口的setjspbody方法,将主体内容作为jspfragment传递。如果没有主体内容,jsp容器则不会调用这个方法。

6、jsp容器调用dotag方法。所有变量在dotag方法返回时进行同步。

下面是我的测试代码的项目结构。

第六章_编写定制标签

下面是我的代码:

package customtag;  

import java.io.ioexception;  

import javax.servlet.jsp.jspcontext;  

import javax.servlet.jsp.jspexception;  

import javax.servlet.jsp.tagext.jspfragment;  

import javax.servlet.jsp.tagext.jsptag;  

import javax.servlet.jsp.tagext.simpletag;  

public class myfirsttag implements simpletag{  

    jspcontext jspcontext ;  

    public void dotag() throws jspexception, ioexception {  

        // todo auto-generated method stub  

        system.out.println("dotag");  

        jspcontext.getout().print("this is my first tag.") ;  

    }  

    public jsptag getparent() {  

        system.out.println("getparent");  

        return null;  

    public void setjspbody(jspfragment arg0) {  

        system.out.println("set jspbody");  

    public void setjspcontext(jspcontext arg0) {  

        system.out.println("setjspcontext");  

        this.jspcontext = arg0 ;  

    public void setparent(jsptag arg0) {  

        system.out.println("set parent");  

}  

<?xml version="1.0" encoding="utf-8"?>  

<taglib xmlnx="http://java.sun.com/xml/ns/j2ee"  

    xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"  

    xsi:schemalocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_1.xsd"  

    version="2.1">  

    <description>  

        simple tag examples  

    </description>  

    <tlib-version>1.0</tlib-version>  

    <short-name>my first taglib example</short-name>  

    <tag>  

        <name>firsttag</name>  

        <tag-class>customtag.myfirsttag</tag-class>  

        <body-content>empty</body-content>  

    </tag>  

</taglib>  

<%@ page language="java" import="java.util.*" pageencoding="utf-8"%>  

<%@ taglib prefix="easy" uri="/web-inf/mytags.tld" %>  

<html>  

  <head>  

    <title>testing my first tag</title>  

  </head>  

  <body>  

    hello!!!  

    <br />  

    <easy:firsttag/>  

  </body>  

</html>  

第六章_编写定制标签

实现simpletag接口或者继承simpletagsupport的标签处理器可以带有属性。

下面是项目结构图:

第六章_编写定制标签

下面是程序代码:

import java.util.stringtokenizer;  

import javax.servlet.jsp.jspwriter;  

import javax.servlet.jsp.tagext.simpletagsupport;  

public class dataformattertag extends simpletagsupport{  

    private string header ;  

    private string items ;  

    public void setheader(string header) {  

        this.header = header;  

    public void setitems(string items) {  

        this.items = items;  

    @override  

        jspcontext jspcontext = getjspcontext() ;  

        jspwriter out = jspcontext.getout() ;  

        out.print("<table style='border:1px solid green'>\n"  

                +"<tr><td><span style='font-wright:bold'>"  

                + header + "</span></td></tr>\n") ;  

        stringtokenizer tokenizer = new stringtokenizer(items, ",") ;  

        while(tokenizer.hasmoretokens()){  

            string token = tokenizer.nexttoken() ;  

            out.print("<tr><td>" + token + "</td></tr>\n") ;  

        }  

        out.print("</table>") ;  

<?xml version="1.0" encoding="utf-8"?>    

<taglib xmlnx="http://java.sun.com/xml/ns/j2ee"    

    xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"    

    xsi:schemalocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_1.xsd"    

    version="2.1">   

    <tlibversion>2.1</tlibversion>  

    <jspversion>2.1</jspversion>  

        <name>dataformatter</name>  

        <tag-class>customtag.dataformattertag</tag-class>  

        <attribute>  

            <name>header</name>  

            <required>true</required>  

        </attribute>  

            <name>items</name>  

</taglib>   

<%@ taglib uri="/web-inf/mytags.tld" prefix="easy"%>  

    <title>testing dataformattertag</title>  

    <easy:dataformatter items="alabama,alaska,georgia,florida" header="states"/>  

    <br/>  

    <easy:dataformatter header="countries">  

        <jsp:attribute name="items">  

            us,uk,canada,korea  

        </jsp:attribute>  

    </easy:dataformatter>  

运行结果图:

第六章_编写定制标签

有了simpletag,就可以通过jsp闯过来的jspfragment管理标签主体了。jspfragment类表示一段jsp代码,可以不调用,也可以调用多次。jsp片段的定义中不能包含scriplet或者scriptlet表达式,它只能包含模版文本和jsp动作指令元素。

jspfragment类有两个方法:getjspcontext和invoke,其方法签名如下:

public abstract jspcontext getjspcontext()

public abstract void invoke(java.io.writer writer)throws jspexception, java.io.ioexception

getjspcontext方法返回与这个jspfragment相关的jspcontext。我们可以调用invoke方法来执行片段(标签主体),并将所有输出内容导到指定的writer。如果传给invoke方法的值为null,那么输出的结果将会被导到与该片段相关的jspcontext的getout方法所返回的jspwriter。

下面是代码段:

public class selectelementtag extends simpletagsupport{  

    private string[] countries = {"australia", "brazil", "china"} ;  

        out.print("<select>\n") ;  

        for(int i=0;i<3; i++){  

            getjspcontext().setattribute("value", countries[i]) ;  

            getjspcontext().setattribute("text", countries[i]) ;  

            getjspbody().invoke(null) ;  

        out.print("</select>\n") ;  

        <name>select</name>  

        <tag-class>customtag.selectelementtag</tag-class>  

        <body-content>scriptless</body-content>  

<%@ taglib uri="/web-inf/mytags.tld" prefix="easy" %>  

    <title>my jsp 'selectelementtagtest.jsp' starting page</title>  

    <easy:select>  

        <option value="${value }">${text }</option>  

    </easy:select>  

输出结果显示:

第六章_编写定制标签

一般来说,编写一个el函数要遵循以下两个步骤:

1、创建一个包含讲台方法的public类。每个静态方法表示一个函数。这个类不需要实现接口或者继承类。你可以根据需要,像对待其他任何类一样部署这个类。这个类必须保存到web-inf/classes目录或其下面的某个目录中。

2、利用function元素在标签类库描述符中注册函数。

function元素必须直接放在taglib元素下,并且可以带有以下子元素:

description。这是一条特定于标签的可选信息。

display-name。xml工具显示的简称。

icon。xml工具可以使用的可选图标元素。

name。该函数独特的名称。

function-class。实现该函数的java类的全类名。

function-signature。表示该函数的静态java方法签名。

example。使用该函数的一个example的可选信息描述。

function-extension。通过xml工具使用,没有扩展名,或者有多个扩展名,提供关于该函数的其他信息。

使用函数时,需利用taglib指令及其uri属性,它指向标签类库描述符,以及要使用的前缀。然后在jsp页面中利用以下语法调用函数:

${prefix:functionname(parameterlist)}

下面是关于el函数的例子:

package function;  

public class stringfunctions {  

    public static string reversestring(string s){  

        return new stringbuffer(s).reverse().tostring() ;  

<%@ taglib uri="/web-inf/functions.tld" prefix="f" %>  

    <title>my jsp 'reversestringfunctiontest.jsp' starting page</title>  

    ${f:reversestring("hello world")}  

     <function>  

        <description>  

            reverse a string  

        </description>  

        <name>  

            reversestring  

        </name>  

        <function-class>  

            function.stringfunctions  

        </function-class>  

        <function-signature>  

            java.lang.string reversestring(java.lang.string)  

        </function-signature>  

    </function>  

在浏览器输入:http://localhost:8089/servlet/reversestringfunctiontest.jsp

第六章_编写定制标签

我们可以将定制标签处理器和标签类库描述符打包成一个jar文件,以便发给其他人使用,像jstl一样。在这种情况下,就需要包含所有的标签处理器,以及描述它们的tld文件。此外,还需要在描述符的uri元素中指定一个绝对的url。

例如,我就打包成一个cc.jar文件。jar文件内容如图所示。

第六章_编写定制标签

可以直接利用cmd的jar命令打包,如图:

第六章_编写定制标签
第六章_编写定制标签

这样我们就可以把jar包复制到项目的lib目录下,并且jsp中引用刚才的uri地址。

第六章_编写定制标签
第六章_编写定制标签

项目运行截图:

第六章_编写定制标签