自定义标签

1. HelloWorld

  ①. 创建一个标签处理器类: 实现 SimpleTag 接口.

  ②. 在 WEB-INF 文件夹下新建一个 .tld(标签库描述文件) 为扩展名的 xml 文件. 并拷入固定的部分: 并对 description, display-name, tlib-version, short-name, uri 做出修改

<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>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>

   ③. 在 tld 文件中描述自定义的标签:

<!-- 描述自定义的 HelloSimpleTag 标签 -->
  <tag>
      <!-- 标签的名字: 在 JSP 页面上使用标签时的名字 -->
      <name>hello</name>     
      <!-- 标签所在的全类名 -->
      <tag-class>com.atguigu.javaweb.tag.HelloSimpleTag</tag-class>
      <!-- 标签体的类型 -->
      <body-content>empty</body-content>
  </tag>

   ④. 在 JSP 页面上使用自定义标签:

    > 使用 taglib 指令导入标签库描述文件: <%@taglib uri="http://www.atguigu.com/mytag/core" prefix="atguigu" %>

    > 使用自定义的标签: <atguigu:hello/>

2. setJspContext: 一定会被 JSP 引擎所调用, 先于 doTag, 把代表 JSP 引擎的 pageContext 传给标签处理器类.

3. 带属性的自定义标签:

  ①. 先在标签处理器类中定义 setter 方法. 建议把所有的属性类型都设置为 String 类型.

private String value;
private String count;

public void setValue(String value) {
    this.value = value;
}

public void setCount(String count) {
    this.count = count;
}

  ②. 在 tld 描述文件中来描述属性:

<!-- 描述当前标签的属性 -->
<attribute>
    <!-- 属性名, 需和标签处理器类的 setter 方法定义的属性相同 -->
    <name>value</name>
    <!-- 该属性是否被必须 -->
    <required>true</required>
    <!-- rtexprvalue: runtime expression value
        当前属性是否可以接受运行时表达式的动态值 -->
    <rtexprvalue>true</rtexprvalue>
</attribute>

  ③. 在页面中使用属性, 属性名同 tld 文件中定义的名字.

<atguigu:hello value="${param.name }" count="10"/>

 4. 通常情况下开发简单标签直接继承 SimpleTagSupport 就可以了. 可以直接调用其对应的 getter 方法得到对应的 API

public class SimpleTagSupport implements SimpleTag{
    
    public void doTag()
        throws JspException, IOException{}
    
    private JspTag parentTag;
    
    public void setParent( JspTag parent ) {
        this.parentTag = parent;
    }
    
    public JspTag getParent() {
        return this.parentTag;
    }
    
    private JspContext jspContext;
    
    public void setJspContext( JspContext pc ) {
        this.jspContext = pc;
    }
    
    protected JspContext getJspContext() {
        return this.jspContext;
    }
    
    private JspFragment jspBody;
                
    public void setJspBody( JspFragment jspBody ) {
        this.jspBody = jspBody;
    }
    
    protected JspFragment getJspBody() {
        return this.jspBody;
    }   
}

 带标签体的自定义标签:

1). 若一个标签有标签体:

<atguigu:testJspFragment>abcdefg</atguigu:testJspFragment>

在自定义标签的标签处理器中使用 JspFragment 对象封装标签体信息.

2). 若配置了标签含有标签体, 则 JSP 引擎会调用 setJspBody() 方法把 JspFragment 传递给标签处理器类在 SimpleTagSupport 中还定义了一个 getJspBody() 方法, 用于返回 JspFragment 对象.

3). JspFragment 的 invoke(Writer) 方法: 把标签体内容从 Writer 中输出, 若为 null, 则等同于 invoke(getJspContext().getOut()), 即直接把标签体内容输出到页面上

  有时, 可以 借助于 StringWriter, 可以在标签处理器类中先得到标签体的内容:

//1. 利用 StringWriter 得到标签体的内容.
StringWriter sw = new StringWriter();
bodyContent.invoke(sw);

//2. 把标签体的内容都变为大写
String content = sw.toString().toUpperCase();

4). 在 tld 文件中, 使用 body-content 节点来描述标签体的类型:

<body-content>: 指定标签体的类型, 大部分情况下, 取值为 scriptless。可能取值有 3 种:

  empty: 没有标签体   

  scriptless: 标签体可以包含 el 表达式和 JSP 动作元素,但不能包含 JSP 的脚本元素

  tagdependent: 表示标签体交由标签本身去解析处理。若指定 tagdependent,在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器

5).  实现 forEach 标签:

  > 两个属性: items(集合类型, Collection), var(String 类型)

  > doTag:
      * 遍历 items 对应的集合
         * 把正在遍历的对象放入到 pageContext 中, 键: var, 值: 正在遍历的对象.
         * 把标签体的内容直接输出到页面上.

开发有父标签的标签:

1). 父标签无法获取子标签的引用, 父标签仅把子标签作为标签体来使用.

2). 子标签可以通过 getParent() 方法来获取父标签的引用(需继承 SimpleTagSupport 或自实现 SimpleTag 接口的该方法):若子标签的确有父标签, JSP 引擎会把代表父标签的引用通过  setParent(JspTag parent)  赋给标签处理器

3). 注意: 父标签的类型是 JspTag 类型. 该接口是一个空接口, 但是来统一 SimpleTag 和 Tag 的. 实际使用需要进行类型的强制转换.

4). 在 tld 配置文件中, 无需为父标签有额外的配置. 但, 子标签是是以标签体的形式存在的, 所以父标签的 <body-content></body-content>需设置为 scriptless

5). 实现

<c:choose>
    <c:when test="${param.age > 24}">大学毕业</c:when>
    <c:when test="${param.age > 20}">高中毕业</c:when>
    <c:otherwise>高中以下...</c:otherwise>
</c:choose>

    > 开发 3 个标签: choose, when, otherwise
    > 其中 when 标签有一个 boolean 类型的属性: test
    > choose 是 when 和 otherwise 的父标签
    > when 在 otherwise 之前使用
    
    > 在父标签 choose 中定义一个 "全局" 的 boolean 类型的 flag: 用于判断子标签在满足条件的情况下是否执行.  
        * 若 when 的 test 为 true, 且 when 的父标签的 flag 也为 true, 则执行 when 的标签体(正常输出标签体的内容), 同时把 flag 设置为 false
        * 若 when 的 test 为 true, 且 when 的父标签的 flag 为 false, 则不执行标签体.
        * 若 flag 为 true, otherwise 执行标签体.

posted @ 2016-07-06 10:57  岳灵珊  阅读(192)  评论(0编辑  收藏  举报