自定义标签在功能上逻辑上与javaBean 类似,都封装Java 代码。自定义标签是可重用的组件代码,并且允许开发人员为复杂的操作提供逻辑名称;其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。

为什么要使用自定义标签?

JSTL标签库只提供了简单的输出等功能,没有实现任何的HTML代码封装,并且某些复杂类型转换,或者逻辑处理的时候,JSTL标签库完成不了,需要自定义标签!

一般情况,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库等操作。

自定义标签语法中两类标签:自定义标签与自定义函数。

自定义标签与普通标签库中的标签用法相同,自定义函数它可以让我们在jsp用直接调用某个方法,根据自定义的方法返回指定的值,兼容jstl标签,省去了在jsp中直接使用<%!%>来定义方法体再调用的繁琐。

编写自定义标签的步骤:

1.编写一个实现Tag接口的Java类【标签处理器类】;

2.在WEB-INF目录下创建tld(Tag Library Descriptor)文件,在tld文件中对标签处理类(实现Tag接口的Java类)进行描述;

自定义标签TLD文件配置属性说明:

taglib子元素说明:

tlib-version:标签库的版本
jsp-version:这个标签库要求的JSP规范版本
short-name:JSP页面编写工具可以用来创建助记名的可选名字
uri:唯一标识该标签库的的URI
display-name:将由工具显示的可选名
description:可选的标签特定信息
listener:一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。

tag子元素说明:

name:独一无二的元素名
tag-class:Tag标签对应的tag处理类
tei-class:javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
body-content:Tag标签body的类型
display-name:被可视化工具(诸如Jbuilder)用来显示的名称(可选)
small-icon:被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
large-icon:被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
description:此tag标签的描述
variable:提供脚本变量的信息(同tei-class)(可选)
attribute:Tag标签的属性名

attribute子元素说明:

name:属性名
required:该属性名可不可省略
rtextprvalue: 表示的是属性是否接受scriptlet表达式的计算结果,默认情况下为false,即只能接受静态值
type:标签处理类中相关属性的类型

自定义标签实例:

编写一个实现Tag接口的Java类:

通常我们自定义类继承TagSupport、BodyTagSupport,重写doStartTag(),doAfterBody()和doEndTag()方法,在对应方法中实现我们自己的逻辑:

public class SelectButton extends BodyTagSupport {

  private static final long serialVersionUID = 1L;
  private String flag;
  private JspWriter out;

    public void init() {
        out = pageContext.getOut();
    }

    @Override
    public int doStartTag() throws JspException {
        init();
        return super.EVAL_BODY_INCLUDE;
    }
    //处理方法
    @Override
    public int doEndTag() throws JspException {
        try {
            StringBuffer sb=new StringBuffer();
            sb.append("<select>");
            if(flag=="0") {
              sb.append("<option value =\"shanxi\">山西</option>");
                sb.append("<option value =\"beijing\">北京</option>"); 
                sb.append("<option value=\"shanghai\">上海</option>");
                sb.append("</select>");  
            }else {
              sb.append("<option value =\"shanxi\">山西1</option>");
              sb.append("<option value =\"beijing\">北京1</option>"); 
              sb.append("<option value=\"shanghai\">上海1</option>");
              sb.append("</select>");
        }
            out.print(sb.toString());
        }catch (Exception e) {
      // TODO: handle exception
    }
        return super.EVAL_PAGE;
    }

  public String getFlag() {
    return flag;
  }

  public void setFlag(String flag) {
    this.flag = flag;
  }
}

为了简化标签开发的复杂度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。一般地,我们做开发都是继承SimpleTagSupport类(该类实现了SimpleTag)来编写自定义标签。

实现了SimpeTag接口的标签称之为简单标签:

public class SimpSelectButton extends SimpleTagSupport {

  private String flag;

  @Override
  public void doTag() throws JspException, IOException {
    StringBuffer sb = new StringBuffer();

    sb.append("<select>");
    if (flag == "0") {
      sb.append("<option value =\"shanxi\"><--简单的标签实现方式--></option>");
      sb.append("<option value =\"shanxi\">山西</option>");
      sb.append("<option value =\"beijing\">北京</option>");
      sb.append("<option value=\"shanghai\">上海</option>");
      sb.append("</select>");
    } else {
      sb.append("<option value =\"shanxi\">山西1</option>");
      sb.append("<option value =\"beijing\">北京1</option>");
      sb.append("<option value=\"shanghai\">上海1</option>");
      sb.append("</select>");
    }

    this.getJspContext().getOut().write(sb.toString());
  }

  public String getFlag() {
    return flag;
  }

  public void setFlag(String flag) {
    this.flag = flag;
  }
}

在WEB-INF目录下创建tld(Tag Library Descriptor)文件,在tld文件中对标签处理类(实现Tag接口的Java类)进行描述

<?xml version="1.0" encoding="UTF-8" ?>
<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">

  <description>自定义标签库</description>
  <display-name>author functions</display-name>
  <tlib-version>1.0</tlib-version>
  <short-name>author</short-name>
  <uri>/author</uri>
  <tag>
    <description><![CDATA[Render a select element]]></description>
    <name>select</name>
    <tag-class>com.qiyun.SelectButton</tag-class> <!-- 注意这里是自己定义的标签类(处理你自己的标签内容)-->
    <body-content>JSP</body-content>
    <attribute>
      <description><![CDATA[The css class to use for element]]></description>
      <name>flag</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
    </tag>
    
    <tag>
    <description><![CDATA[Render a select element]]></description>
    <name>simpselect</name>
    <tag-class>com.qiyun.SimpSelectButton</tag-class> <!-- 注意这里是自己定义的标签类(处理你自己的标签内容)-->
    <body-content>empty</body-content>
    
    <attribute>
      <description><![CDATA[The css class to use for element]]></description>
      <name>flag</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
      
    </attribute>
    </tag>
</taglib>

自定义标签的使用:

如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)

<%@taglib prefix="author" uri="/author" %>

uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。

prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。

TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。

引用自定义标签的简单使用:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="author" uri="/author" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>练习自定义标签TLD的用法</title>
</head>
<body>
<div><author:select flag="0"></author:select>     </div>
<div><author:simpselect flag="0"></author:simpselect>     </div>

</body>
</html>

自定义函数:

自定义函数也是自定义标签的一种,只是更加简单。

编写自定义函数的步骤:

1.编写一个实现function接口的Java类【标签处理器类】;

2.在WEB-INF目录下创建tld(Tag Library Descriptor)文件,在tld文件中对标签处理类(实现function接口的Java类)进行描述;

自定义函数TLD文件配置属性说明:

taglib子元素说明:

tlib-version:标签库的版本
jsp-version:这个标签库要求的JSP规范版本
short-name:JSP页面编写工具可以用来创建助记名的可选名字
uri:唯一标识该标签库的的URI
display-name:将由工具显示的可选名
description:可选的标签特定信息
listener:一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。

function子元素说明:

description:可选的标签特定信息
name:独一无二的元素名
function-class:定义函数处理类
function-signature:定义函数的对应方法
实例:执行标签具体的方法的类

实例:编写执行标签具体的方法的类:

public class Tools {
  
  /**
   * 获取当前用户权限
   */
  public static String getUserAuthor(String menuId) {
    
    return menuId;
  }    
}

在WEB-INF目录下创建tld(Tag Library Descriptor)文件,在tld文件中对自定义函数处理类进行描述:

<?xml version="1.0" encoding="UTF-8" ?>
<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">

  <description>自定义标签库</description>
  <display-name>author functions</display-name>
  <tlib-version>1.0</tlib-version>
  <short-name>author</short-name>
  <uri>/author</uri>
  <function>
    <description>取得用户权限</description>
    <name>author</name>
    <function-class>com.qiyun.Tools</function-class>
    <function-signature>java.lang.String getUserAuthor(java.lang.String)</function-signature>
  </function>

</taglib>

自定义函数的使用:

如果要使用自定义函数,与自定义标签一样,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)

<%@taglib prefix="author" uri="/author" %>

uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。

prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。

TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。

引用自定义标签的简单使用:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="author" uri="/author" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>练习自定义标签TLD的用法</title>
</head>
<body>
<button class="${author:author('button1')}">${author:author('button')}</button>
<h1 class="hidden">这是一个隐藏标题</h1>
<h1>这是一个标题</h1>
</body>
</html>
<style>
button.button{
  display: none;
}
h1.hidden {display:none;}
</style>