概述

本教程将概述如何创建 Jakarta-Taglibs 库中的一些基本标记。标记库允许您创建自定义操作并封装功能。自定义标记可以明确地将表示层与业务逻辑分开。它们是易于维护的可重用组件,可以访问 JSP 页面可用的所有对象。有关更多详细信息,请参阅JavaServer Pages 规范,版本 1.2

实现 JSP v1.1+ 的服务器支持标记库。您可以在JavaServer Pages 行业发展势头页面上找到各种服务器及其当前支持的描述。Sun 网站上还提供了非常好的Java Web 服务教程,其中包括自定义标记JSP 标准标记库 (JSTL)部分。

标记处理程序

标记处理程序负责 JSP 页面与其他服务器端对象之间的交互。在执行 JSP 页面时,当遇到自定义标记时会调用处理程序。doStartTag()doEndTag() 方法分别在遇到自定义标记的开始和结束标记时调用。 release() 方法释放标记处理程序分配的资源。

有两个描述标记处理程序的接口

标记 用于对不感兴趣于操作其主体内容的简单标记处理程序
主体标记 标记的扩展,允许处理程序访问其主体

标记处理程序有两个主要操作方法

doStartTag()

处理此操作的开始标记。

doEndTag() 处理此操作的结束标记。在从 doStartTag 返回后调用。
release() 释放资源

doStartTag() 返回以下内容

  • EVAL_BODY_INCLUDE
    • 处理操作的主体,但不要创建新的 BodyContent。原样传递主体,不进行操作。仅在实现 BodyTag 接口时有效。
  • EVAL_BODY_TAG
    • 处理操作的主体并创建新的 BodyContent。仅在实现 BodyTag 接口时有效。
  • SKIP_BODY
    • 不评估标记的主体

doEndTag() 返回以下内容

  • EVAL_PAGE
    • 将评估 JSP 页面的其余部分
  • SKIP_PAGE
    • 将不评估 JSP 页面的其余部分

返回值指示 JSP 容器如何评估 JSP 页面的其余部分。release() 方法释放标记处理程序分配的资源。

TagSupportBodyTagSupportTag 的子类,可以在创建新标记处理程序时用作基类。

TagSupport 类是一个实用程序类,它实现了 Tag 接口并添加了其他便利方法,包括

如果标记处理程序操作操作的主体,则它必须实现 BodyTag 接口。doStartTag() 必须返回 EVAL_BODY_TAG 才能评估标记的主体。如果返回 SKIP_BODY,则主体将被忽略。与主体内容交互的方法包括

doInitBody() 在标记主体评估之前调用,但在设置主体内容之后
doAfterBody() 在主体内容评估之后调用

BodyTagSupport 类实现了 BodyTag 接口并添加了其他便捷方法。其中一些方法包括

在 Web 应用程序中,处理程序必须位于以下标准位置之一,用于 Java 类

标记处理程序可以访问一些由 JSP 容器使用 setter 方法设置的属性。这包括 pageContextparent 对象。标记处理程序还可以访问服务器端对象和封闭操作。如果标记是嵌套的,则可以通过使用以下任一方法访问封闭标记的父处理程序

检索父对象后,可以获取父处理程序的静态和动态创建的对象。

标记库描述符

标记库描述符 (TLD) 由 JSP 容器用于解释包含引用该标记库的 taglib 指令的页面。它是一个 XML 文档,将操作标记映射到标记处理程序类。您可以通过两种方式找到 TLD

您可以在 Servlet 2.2 和 JSP 1.1 规范中找到有关 web.xml taglib 元素的更多信息。

由于最近更改为调用验证解析器,您需要明确引用外部 DOCTYPE

                                        
  <!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
    "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

TLD taglib 元素是文档根。它具有以下子元素

tlibversion 标记库实现的版本
jspversion 标记库所需的 JSP 规范版本
shortname 可用于从 JSP 页面引用标记库的名称
uri 唯一标识标记库的 uri - 描述标记库“用途”的信息字符串
info 描述标记库“用途”的字符串

标签元素定义标签库中的一个操作。它可能具有多个子元素,这些子元素定义操作

name 唯一操作名称
tagclass 实现 javax.servlet.jsp.tagext.Tag 的标签处理程序类
teiclass javax.servlet.jsp.tagext.TagExtraInfo 的可选子类
bodycontent

三种正文内容类型之一

info

可选的标签特定信息

attribute

操作的所有属性

如果标签具有正文,则包含 bodycontent。它由页面组合工具使用,因此不会影响正文的组合。它可以是以下三种类型之一

  • JSP(默认)
    • JSP 容器应该计算标签的任何正文,但它也可以为空
  • tagdependent
    • 标签的任何正文都将由标签本身处理,但它也可以为空
  • empty
    • 正文必须为空

teiclass 定义脚本变量并包括以下信息

  • name
  • type
  • 是否需要创建变量
  • scope

attributes 可以具有以下字段

  • name(必需)
    • 属性名称
  • required
    • 如果属性是必需的还是可选的
  • rtexprvalue
    • 如果属性值可以在运行时由脚本动态计算。注意:默认值为“false”,表示属性具有静态值。如果属性值在请求时确定,请务必将其设置为“true”。

对于每个属性,您必须在标签处理程序中具有 JavaBeans 样式的 get 和 set 方法。如果您的属性名为 id,则 TagSupport 类为您定义 setId() 和 getId() 方法。

JavaServer Pages

JavaServer Pages 可以处理封装在标签库操作中的 XML 内容。

  <%@ taglib uri="identifier" prefix="prefix" %>

要使用标签库,您需要使用 taglib 指令告诉 JSP 容器它位于何处。该指令必须在任何操作之前

安装和部署

a) 创建通用标记库

要安装标记库,您需要执行以下步骤

  1. 将标记类捆绑到 jar 文件中。确保包含位于 /WEB-INF 目录中的标记库 {library}.tld 文件
  2. 将标记 {library}.jar 文件添加到 CLASSPATH
  3. {library}.jar 文件复制到 /WEB-INF/lib 目录
  4. /WEB-INF/web.xml 文件中定义标记库元素。例如
      <taglib>
        <taglib-uri>http://jakarta.apache.org/taglibs/{library}</taglib-uri>
        <taglib-location>/WEB-INF/{library}.tld</taglib-location>
      </taglib>
        
  5. 在 jsp 页面中定义标记扩展。<taglib-uri>uri 指令必须匹配。prefix 标识 jsp 页面中标记库中的标记。例如
  6.   <%@ taglib uri="http://jakarta.apache.org/taglibs/{library}" prefix="x" %>
        

b) 添加 Jakarta-Taglibs 库

要向 Jakarta-Taglibs 添加标记库子项目,您需要执行以下操作

  1. 为项目创建一个顶级目录。
  2. 从现有子项目之一复制以下顶级文件
    • build.sh
    • build.bat
    • build.xml
  3. taglib.name 属性更改为新的自定义标记库子项目名称
  4. 从现有子项目之一复制目录结构
  5. 修改顶级 Jakarta-Taglibs build.xml 文件以包含新库

c) 部署标记库

使用 jakarta-taglibs 项目中的构建脚本创建 war 文件。构建 war 文件后,您可以简单地将该文件放置在 $TOMCAT_HOME/webapps 目录中。Tomcat 将加载您的类并创建新上下文。

war 文件应具有以下结构

  META-INF/
  META-INF/MANIFEST.MF
  WEB-INF/
  WEB-INF/classes/
  WEB-INF/lib/
  WEB-INF/lib/{tagLibrary}.jar
  WEB-INF/web.xml
  WEB-INF/{tagLibrary}.tld

如果您不想使用 jar 文件,则可以将所有类文件放置在 /WEB-INF/classes 目录中。

有关 war 文件的更多信息,请参阅 Java Servlet 规范,v2.2

示例

一些示例包括

基本标记

此基本标记是“Hello World”示例。每当遇到该标记时,都会打印文本“Hello World”。

Hello World 标记处理程序

您可以在 /WEB-INF/classes/basic 目录中找到 Hello World 标记的标记处理程序,因为它属于 basic 包

  package basic;

导入 jsp 和标记类

  import javax.servlet.jsp.*;
  import javax.servlet.jsp.tagext.*;

Hello World 标记处理程序实现了 doStartTag() 方法,该方法在遇到开始标记时调用。

    public int doStartTag() throws JspException {
        try {
            pageContext.getOut().print("Hello World");
        } catch (Exception ex) {
            throw new JspException("IO problems");
        }
        return SKIP_BODY;
    }

JSP 容器设置 pageContext,并且标签处理程序可以使用它。 SKIP_BODY 值确保不评估标签主体。

Hello World 标签库描述符

  <?xml version="1.0" encoding="ISO-8859-1" ?>

描述部署描述符 DOCTYPE 的 XML 头。部署描述符包括 Web 应用程序的元素和配置信息。

  <!DOCTYPE taglib
            PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" 
            "http://java.sun.com/j2ee/dtds/web-jsptaglib_1_1.dtd">

初始标签库描述

  <taglib>
    <!-- The version number of this tag library -->
    <tlibversion>1.0</tlibversion>

    <!-- The JSP specification version required to function -->
    <jspversion>1.1</jspversion>

    <!-- The short name of this tag library -->
    <shortname>utility</shortname>

    <!-- Public URI that uniquely identifies this version of the tag library -->
    <uri>http://jakarta.apache.org/taglibs/utilitytags</uri>

    <!-- General information about this tag library -->
    <info>
          A simple tag library for the examples
    </info>

Hello World 标签描述。

  • tagclass 元素将 Hello World 标签处理程序与 Hello World 标签关联
  • bodycontent 标签告诉我们该标签不会包含任何主体
  <!-- Hello tag -->
    <tag>
      <name>Hello</name>
      <tagclass>basic.Hello</tagclass>
      <bodycontent>empty</bodycontent>
      <info>
        Print Hello World
      </info>
    </tag>

web.xml 文件

web.xml 文件描述标签库 uri 与标签库描述符位置之间的映射。

此处,唯一的 taglib-uri "http://jakarta.apache.org/taglibs/utilitytags" 与 /WEB-INF/tld/utilitytags.tld 中的标签库描述符关联。

  <web-app>
    <taglib>
       <taglib-uri>
         http://jakarta.apache.org/taglibs/utilitytags
       </taglib-uri>
       <taglib-location>
         /WEB-INF/tld/utilitytags.tld
       </taglib-location>
    </taglib>
  </web-app>

Hello World jsp

以下指令告诉 JSP 容器使用 web.xml 中定义的 "http://jakarta.apache.org/taglibs/utilitytags" uri。"jLib" 被定义为该标签的前缀值。

  <%@ taglib uri="http://jakarta.apache.org/taglibs/utilitytags" prefix="jLib" %>

调用 Hello World 标签。标签名称 "Hello" 在标签库描述符中定义。

  <jLib:Hello/>

简单嵌套操作

此嵌套标签是 "If" 条件标签的一个示例。根据属性值,将评估或跳过包含的脚本片段。

If 标签处理程序

BodyTagSupport 类实现 BodyTag 接口,并具有 bodyContent 属性的 getter 方法。

  public class IfTag extends BodyTagSupport {

doStartTag() 方法在遇到开始标签时调用,并调用本地 getPredicate() 方法。如果返回值为 true,则评估标签主体的其余部分,否则跳过它。

  public int doStartTag() {
    if (getPredicate()) return EVAL_BODY_TAG;
    else return SKIP_BODY;
  }

doAfterBody() 在评估某些主体后调用。它不会在空标签或在 doStartTag() 中返回 SKIP_BODY 的标签中调用。

  public int doAfterBody() throws JspException {
    try {
      bodyContent.writeOut(bodyContent.getEnclosingWriter());
      return SKIP_BODY;
    } catch (IOException ex) {
      throw new JspTagException(ex.toString());
    }
  }

如果标签库描述符

  <!-- IF tag -->
    <tag>
      <name>If</name>
      <tagclass>lang.IfTag</tagclass>

If 标签有一个必需的属性。由于 rtexprvalue 设置为 true,因此属性可以将脚本表达式作为值。该值可以在请求时动态计算。

      <attribute>
        <name>predicate</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
      </attribute>
      <info>
        Conditional Tag.
      </info>
    </tag>  

web.xml 文件

web.xml 文件描述标签库 uri 与标签库描述符位置之间的映射。

此处,唯一的 taglib-uri "http://jakarta.apache.org/taglibs/utilitytags" 与 /WEB-INF/tld/utilitytags.tld 中的标签库描述符关联。

如果 JSP

If 标签需要一个属性。谓词属性包含一个将在运行时评估的脚本。基于谓词属性值,jLib:Hello 标签将被评估或跳过。

  <jlib:if predicate="<%= x==5 %>">
    <jLib:Hello/>   
  </jlib:if>

UtilityTags 标签库的文档

1. 简介

utilitytags 自定义标签库包含一些基本标签的示例。它展示了多种简单的自定义标签库代码技术。

2. 必备软件

此自定义标签库不需要除支持 JavaServer Pages 规范 1.1 版 的 servlet 容器之外的任何软件。

3. 配置信息

按照以下步骤使用此标签库配置 Web 应用程序

  • 将标签库描述符文件 (utilitytags/utilitytags.tld) 复制到 Web 应用程序的 /WEB-INF 子目录。
  • 将标签库 JAR 文件 (utilitytags/utilitytags.jar) 复制到 Web 应用程序的 /WEB-INF/lib 子目录。
  • /WEB-INF/web.xml 中的 Web 应用程序部署描述符添加一个 <taglib> 元素,如下所示
        <taglib>
            <taglib-uri>http://jakarta.apache.org/taglibs/utilitytags</taglib-uri>
            <taglib-location>/WEB-INF/utilitytags.tld</taglib-location>
        </taglib>
        

要在 JSP 页面中使用此库中的标签,请在每个页面的顶部添加以下指令

    <%@ taglib uri="http://jakarta.apache.org/taglibs/utilitytags" prefix="x" %>
其中“x”是您希望用于此库中的标签的标签名称前缀。您可以将此值更改为任何喜欢的前缀。

4. 标签文档

utilitytags 标签库包含以下标签

Hello 标签

Hello 标签打印文本“Hello World”。它没有任何属性。

属性
说明
必需
-
-
-
  • Copy 标签

    MacroCopy 标签将属性文本复制到 Writer。

    属性
    说明
    必需
    name
    与要复制的文本关联的名称。任何字符串值。
  • Paste 标签

    MacroPaste 标签粘贴由 Writer 指定的文本。

    属性
    说明
    必需
    name
    与要粘贴的文本关联的名称。任何字符串值。
  • ShowSource 标签

    ShowSource 标签采用 jspFile 并将内容复制到 Writer。

    属性
    说明
    必需
    jspFile
    jsp 文件的文件名和相对路径。任何字符串值。
  • Include 标签

    Include 标签内联包含指定 URL 的输出。

    属性
    说明
    必需
    url
    任何有效的 URL。
  • If 标签

    If 标签是一个基本的条件标签。

    属性
    说明
    必需
    predicate
    任何字符串值。
  • For 标签

    For 标签是一个基本的循环标签。

    属性
    说明
    必需
    iterations
    要完成的循环迭代次数。任何字符串整数值。
    varName
    与 For 循环关联的变量名称。任何字符串值。
    no
    begin
    循环起始值。任何字符串整数值。
    no
  • useBean 标签

    useBean 标签将 Java 对象的实例与给定的 ID 关联。

    属性
    说明
    必需
    id
    在 JSP 容器和页面中唯一标识 bean。任何字符串值。
    scope
    page|request|session|application
    no
    classname
    定义对象实现的类的名称。
    no
    type
    定义的脚本变量的类型
    no
    beanName
    java.beans.Beans 类的 instantiate() 方法所期望的 bean 名称
    processRequest
    true|false。JSP 0.92 兼容性。
    no
  • Validate 标签

    Validate 标签生成 Javascript 以验证 HTML 表单。

    属性
    说明
    必需
    name
    表单的名称。任何字符串值。
    method
    要生成的 Javascript 函数的名称。任何字符串值。
    reqdFields
    以逗号分隔的必填字段列表。任何字符串值。