自定义标签(一)——tld文件解析

自定义标签实现方式

之前我们使用的标签库都是JSTL为我们提供的,大部分的数据操作和控制都可以使用它来完成,但是如果我们项目中有特殊需求或者为了统一开发规范,那么我们也可以自己定义一套标签库供自己的团队使用。

自定义tag有两种方式:

  1. 使用TLD文件,将自定义的tag映射到java code或者tag文件。
  2. 使用Tag文件,自定义的tag由jsp tag实现。

使用TLD文件方式自定义标签的实现步骤:

  • 创建标签处理程序 (Tag Handler Class)
  • 创建标签库描述文件(Tag Library Descrptor File)
  • 在web.xml文件中配置元素(可选,如果标签库描述文件不放在WEB-INF或其子目录下则需要配置)

    <jsp-config>
        <taglib>
            <!-- tld描述文件中的uri -->
            <taglib-uri></taglib-uri>
            <!-- 存放路径 -->
            <taglib-location></taglib-location>
        </taglib>
      </jsp-config>
    
  • 在JSP文件中使用taglib指令引入标签库

  • 使用标准格式调用自定义标签

使用Tag文件的自定义标签位置和引用

自定义的tag文件是位于/WEB-INF/tags目录或其子目录中的.tag或者.tagx文件。我们自己web app的tag文件可以被TLD文件通过<tag-file>文件使用,或者通过directive在jsp中使用:

<%@ taglib prefix="myTag" tagdir="/WEB-INF/tags" %>   
<%@ taglib prefix="t" tagdir="/WEB-INF/tags/fmt" %>  
<%@ taglib prefix="f" tagdir="/WEB-INF/tags/fn" %>  

三者的区别是是其相应的tag名字分别是<myTag>、<fmt:t>、<fn:f>
如果我们要封装为jar包,作为第三方的tag文件提供,则tag文件需要在jar文件的/META-INF/tags目录下,且通过JAR文件的/META-INF目录下的TLD文件所使用。除了与tld文件路径有区别外,不能以tag文件的方式被直接使用。

JSTL中TLD

这是JSTL采用的方式。TLD(Tag Library Descriptor)描述tag和function,以及具体执行的java代码tag handler(查看jstl jar包META-INF下tld文件)。Tag Handler是javax.servlet.jsp.tagext.Tag或javax.servlet.jsp.tagext.SimpleTag的实现。web容器使用TLD将jsp中的tag映射到执行的java代码。前面的博客已介绍了jstl标签的使用,我们来看看这些TLD是怎么写的。

Taglib描述信息

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

<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

  <description>JSTL 1.1 core library</description>
  <display-name>JSTL core</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>c</short-name>
  <uri>http://java.sun.com/jsp/jstl/core</uri>

  ......

</taglib>

这里是XML的标准声明,通过Schema在web-jsptaglibrary_2_1.xsd中定义,TLD文件标签的先后顺序都是通过schema约束。描述TLD的整体信息:

  • <description>与<display-name>:可选,用于在IDE中的XML工具显示,和真正的TLD内容没什么关系,可有多个,用于不同语言的显示。
  • <icon>:可选,没有实际用途。
  • <tlib-version>:必选,taglib的版本。
  • <short-name>:必选,给出推荐和缺省的tag前缀。
  • <uri>:可选,建议给出,若不提供则需要在web.xml中配置<jsp-config>描述tag
    library,uri可以随意配置,不需要真实存在。

validator和listener

 <validator>
    <description>
        Provides core validation features for JSTL tags.
    </description>
    <validator-class>
        org.apache.taglibs.standard.tlv.JstlCoreTLV
    </validator-class>
  </validator>

 在编译的时候使用javax.servlet.jsp.tagext.TagLibraryValidator类来验证,确保正确使用tag lib,如&;<c:url>的格式正确。validator复杂且很少在自定义tag中使用,略过。
 listener,如ServletContextListener,HttpSessionListener,但是它的使用极为罕见,反正我是没见过,略过。

定义标签Tag

<tag>
    <description>
        Catches any Throwable that occurs in its body and optionally
        exposes it.
    </description>
    <name>catch</name>
    <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <description>
Name of the exported scoped variable for the
exception thrown from a nested action. The type of the
scoped variable is the type of the exception thrown.
        </description>
        <name>var</name>
        <required>false</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>
  • <description><display-name>:作用与taglib的一样,可以有多个。
  • <name>:必选,标签名称。
  • <tag-class>:标签处理类。
  • <tei-class>:可选,javax.servlet.jsp.tagext.TagExtraInfo的继承类,用于校验tag的属性,确保使用的正确,<c:import><c:forEach>就有定义。
  • <body-content>:必选,有四个选项empty、scriptless、JSP、tagdependent,之后篇章介绍。
  • <variable>:可选,可定义多个,JSTL TLD中都没有使用,它是用来提供tag的结果的各种变量信息。什么是variable?我们通过pageContext.setAttribute/getAttribute设置或获取某个值,这就是变量。不通过variable,我们也可以通过EL来获取。如果提供了variable,我们除了EL外,还可以在java代码中使用这些变量。但现在都是采用MVC模式,JSP页面中java代码基本上也不会被使用。子参数依次包括:

    • <description>
    • <name-given> 变量的名字 。
    • <name-from-attribute> 决定变量名字,这和<name-given>相互冲突,只能二选一。String,不能是EL等在运行时计算 。
    • <variable-class> 变量的类型 。
    • <declare> true表示变量是新,需要声明;false表示已存在,只是修改值。
    • <scope> 缺省是NESTED,即在tag内有效;AT_BEGIN表示变量tag内及之后有效;AT_END表示变量只在tag后有效。
  • <attribute>:可选,可定义多个,定义Tag的属性。

    • <description>:可选。 <name>:属性名称。
    • <required:可选,属性是否必须true/false,缺省为false。
    • <rtexprvalue:可选,rtexprvalue是runtime expression value:true表示允许EL这类运行时计算值,false则不允许,缺省为false。
    • <type>:可选,属性类型,缺省为Object。
    • <fragment>可选,设置true时表示用jsp fragment,容器不进行计算,而是由handler进行计算。缺省值为false。如果使用fragment,可以通过<jsp:attribute>来设置,而非xml的属性。如:
    <myTag:doSomething>
            <jsp:attribute name="someAttribute"> 
                Any <b>content</b> <fmt:message key="including.jsp.tags" />  
            </jsp:attribute>
        </myTag:doSomething>
  • <dynamic-attribute>:可选,缺省为false,如果设置为true,表示允许使用没有定义的属性。这通常在jsg tag的最终输出为html tag的情况,这时handler需要实现javax.servlet.jsp.tagext.DynamicAttributes。Spring的form tag lib就使用动态属性 。
  • <example>:可选,用于给出tag使用的示范案例。
  • <tag-extension>:可选,可定义多个,提供给IDE的,对tag本身没有任何影响。

引用Tag文件

在tld中是可以使用0~n个tag文件,定义在tag标签后面,如下:

<tag-file>  
    <!-- <description>、<display-name>和<icon>,其中description是必选 -->  
    <description>This tag outputs bar.</description>  
    <!-- name就是prefix之后的名字,和tag中一样 -->  
    <name>foo</name>  
    <!-- tag文件路径,web应用中的/WEB-INF/tags或者jar中的/META-INF/tags -->  
    <path>/WEB-INF/tags/foo.tag</path>  
    <!-- 最后是<example>和<tag-extension> -->  
</tag-file>  

若tag文件加入到jar中,就必须在TLD中定义;如果多个tag文件有相同的namespace,也需在TLD中定义。

定义function

<function>  
    <!-- <description>, <display-name>, <icon>, <name>与前面一样。 -->  
    <description>  
      Tests if an input string contains the specified substring.  
    </description>
    <name>contains</name>  
    <!-- 该function对应的公共类全名 -->  
    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>  
    <!-- 该function在公共类中对应的公共静态方法 -->  
    <function-signature>boolean contains(java.lang.String, java.lang.String)</function-signature>  
    <!-- 接下来的<example>、<function-extension>和tag的<example>和<tag-extension>同义 -->  
    <example>  
      <!-- 这里是个不好的示例,我们应该写成<![CDATA[...]]> -->  
      <c:if test="${fn:contains(name, searchString)}">  
    </example>  
</function>  

定义Tag library Extensions

  <taglib-extension>和tag已经function中的extension一样,对tag或者container无实际作用,仅是支持IDE工具,我们不会使用到的。

猜你喜欢

转载自blog.csdn.net/yutao_struggle/article/details/78857368