Jsp自定義標籤

一、JSP自定義標籤簡介

  標籤是一種XML元素,通過標籤可以使JSP網頁變得簡潔並且易於維護,還可以方便地實現同一個JSP文件支持多種語言版本。由於標籤是XML元素,所以它的名稱和屬性都是大小寫敏感的

  標準JSP標籤是用來調用JavaBean組件的操作,處理定向請求以簡化JSP頁面開發與維護。JSP技術提供了一種封裝其它動態類型的機制——自定義標籤,它擴展了JSP語言。自定義標籤通常發佈在標籤庫中,該庫定義了一個自定義標籤集幷包含實現標籤的對象。

  自定義標籤是用戶定義的JSP語言元素。當JSP頁面包含一個自定義標籤時被轉化爲servlet,標籤轉化爲對稱爲tag handler的對象的操作。接着當servlet執行時Web container調用那些操作。

  二、兩種標籤

  可以定義兩種類型的標籤:

javax.servlet.jsp.tagext.Tag
javax.servlet.jsp.tagext.BodyTag

  有標籤體的標籤必須實現 BodyTag 接口。

<jsptag:map scope=“session” name=“tagMap”>
body
</jsptag:map>

  也可能沒有標籤體:

<jsptag:map/>

  無標籤體的簡單標籤可以實現 Tag 接口。

  三、標籤處理程序

  int doStartTag() throws JspException---處理開始標籤

  int doEndTag() throws JspException---處理結束標籤

  Tag getParent()/void setParent(Tag t)---獲得/設置標籤的父標籤

  void setPageContext(PageContext pc)--- pageContext 屬性的 setter 方法

  void release() 釋放獲得的所有資源

 doStartTag()和doEndTag()方法的返回值說明:

  SKIP_BODY      表示不用處理標籤體,直接調用doEndTag()方法。

  SKIP_PAGE      忽略標籤後面的jsp(SUN企業級應用的首選)內容。

  _PAGE      處理標籤後,繼續處理jsp(SUN企業級應用的首選)後面的內容。

  _BODY_BUFFERED 表示需要處理標籤體,且需要重新創建一個緩衝(調用setBodyContent方法)。

  _BODY_INCLUDE 表示在現有的輸出流對象中處理標籤體,但繞過setBodyContent()和doInitBody()方法

  _BODY_AGAIN    對標籤體循環處理。(存在於javax.servlet.jsp.tagext.IterationTag接口中)

  實現javax.servlet.jsp.tagext.Tag接口

  擴展javax.servlet.jsp.tagext.TagSupport類

  TagSupport 類定義了 get/setParent() 和 setPageContext(),這與所有標籤處理程序幾乎相同。

  get/setParent() 方法允許標籤嵌套。

  TagSupport 類還定義了一個可以被子類使用的 pageContext 實例變量 (protected PageContext pageContext),這個變量是由 setPageContext() 方法設置的。

  在創建自定義標籤之前,需要創建一個 標籤處理程序。標籤處理程序是一個執行自定義標籤操作的 Java 對象。在使用自定義標籤時,要導入一個 標籤庫 —— 即一組標籤/標籤處理程序對。通過在 Web 部署描述符中聲明庫導入它,然後用指令 taglib 將它導入 JSP 頁。

  如果 JSP 容器在轉換時遇到了自定義標籤,那麼它就檢查 標籤庫描述符(tag library descriptor)(TLD) 文件以查詢相應的標籤處理程序。TLD 文件對於自定義標籤處理程序,就像 Web 部署描述符對於 servlet 一樣。

  在運行時,JSP 頁生成的 servlet 得到對應於這一頁面所使用的標籤的標籤處理程序的一個實例。生成的 servlet 用傳遞給它的屬性初始化標籤處理程序。

  標籤處理程序實現了 生存週期 方法。生成的 servlet 用這些方法通知標籤處理程序應當啓動、停止或者重複自定義標籤操作。生成的 servlet 調用這些生存週期方法執行標籤的功能。

  四、TLD 文件

  TLD 文件的根元素是 taglib。taglib 描述了一個 標籤庫 —— 即一組標籤/標籤處理程序對。

  因爲我們使用的是 JSP 版本 1.2,所以在這個例子中需要 tlib-version 和 short-name 元素。

  tlib-version 元素對應於標籤庫版本。

  jsp-version 對應於標籤庫所依賴的 JSP 技術的版本。

  short-name 元素定義了 IDE 和其他開發工具可以使用的標籤庫的簡單名。

  taglib 元素包含許多 tag 元素,標籤庫中每一個標籤有一個 tag 元素。

  在JSP中導入TLD文件:

<%@ taglib uri="firstTag" prefix="my"%>

  五、編寫自定義迭代標籤和el表達式調用類的靜態方法實例

  循環標籤體類:ForEach.java

 1import java.util.Collection;
 2import java.util.Iterator;
 3
 4import javax.servlet.jsp.JspException;
 5import javax.servlet.jsp.tagext.BodyContent;
 6import javax.servlet.jsp.tagext.BodyTagSupport;
 7
 8public class ForEach  extends BodyTagSupport
 9{
10  private String id;
11  private String collection;
12  private Iterator iter;
13 
14  public void setCollection(String collection)
15  {
16    this.collection = collection;
17  }
18  public void setId(String id)
19  {
20    this.id = id;
21  }
22 
23  //遇到開始標籤執行
24  public int doStartTag() throws JspException
25  {
26    Collection coll = (Collection) pageContext.findAttribute(collection);
27    // 表示如果未找到指定集合,則不用處理標籤體,直接調用doEndTag()方法。
28    if(coll==null||coll.isEmpty()) return SKIP_BODY;
29   
30    iter = coll.iterator();
31    pageContext.setAttribute(id, iter.next());
32    // 表示在現有的輸出流對象中處理標籤體,但繞過setBodyContent()和doInitBody()方法
33    // 這裏一定要返回_BODY_INCLUDE,否則標籤體的內容不會在網頁上輸出顯示
34    return _BODY_INCLUDE;
35  }
36 
37  //在doInitBody方法之前執行,在這裏被繞過不執行
38  @Override
39  public void setBodyContent(BodyContent arg0)
40  {
41    System.out.println("setBodyContent");
42    super.setBodyContent(arg0);
43  }
44  //此方法被繞過不會被執行
45  @Override
46  public void doInitBody() throws JspException
47  {
48    System.out.println("doInitBody");
49    super.doInitBody();
50  }
51 
52  //遇到標籤體執行
53  public int doAfterBody() throws JspException
54  {
55    if(iter.hasNext())
56    {
57      pageContext.setAttribute(id, iter.next());
58      return _BODY_AGAIN;// 如果集合中還有對像,則循環執行標籤體
59    }
60    return SKIP_BODY;//迭代完集合後,跳過標籤體,調用doEndTag()方法。
61  }
62 
63  //遇到結束標籤執行
64  public int doEndTag() throws JspException
65  {
66    System.out.println("doEndTag");
67    return _PAGE;
68  }
69
70}

 獲取VO屬性類:GetProperty.java

 1import java.lang.reflect.Method;
 2
 3import javax.servlet.jsp.JspException;
 4import javax.servlet.jsp.tagext.BodyTagSupport;
 5
 6public class GetProperty extends BodyTagSupport
 7{
 8
 9  private String name;
10  private String property;
11
12  public void setName(String name)
13  {
14    this.name = name;
15  }
16
17  public void setProperty(String property)
18  {
19    this.property = property;
20  }
21
22  @SuppressWarnings("unchecked")
23  public int doStartTag() throws JspException
24  {
25    try
26    {
27      Object obj = pageContext.findAttribute(name);
28     
29      if (obj == null) return SKIP_BODY;
30     
31      Class c = obj.getClass();
32      //構造GET方法名字 get+屬性名(屬性名第一個字母大寫)
33      String getMethodName = "get" + property.substring(0, 1).toUpperCase()
34                              + property.substring(1, property.length());
35      Method getMethod = c.getMethod(getMethodName, new Class[]{});
36     
37      pageContext.getOut().print(getMethod.invoke(obj));
38      System.out.print(property + ":" + getMethod.invoke(obj) + "t");
39    } catch (Exception e)
40    {
41      e.printStackTrace();
42    }
43    return SKIP_BODY;
44  }
45
46  public int doEndTag() throws JspException
47  {
48    return _PAGE;
49  }
50}
51
52表達式直接訪問此類中靜態的方法:ELFunction.java
53public class ELFunction
54{
55 public static int add( int i,int j )
56 {
57  return i+j;
58 }
59}

  寫一個測試用的VO類:UserVo.java

 1public class UserVo
 2{
 3  private String name;
 4  private String password;
 5 
 6  public String getName()
 7  {
 8    return name;
 9  }
10  public void setName(String name)
11  {
12    this.name = name;
13  }
14  public String getPassword()
15  {
16    return password;
17  }
18  public void setPassword(String password)
19  {
20    this.password = password;
21  }
22}

  建好TLD文件tag.tld,放在WEB-INF目錄下

 1<?xml version="1.0" encoding="utf-8"?>
 2<taglib version="2.0"
 3 xmlns="http://java.sun.com/xml/ns/j2ee"
 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5 xmlns:shcemalocation="http://java.sun.com/xml/ns/j2ee
 6 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 7
 8 <description>自定義標籤</description>
 9 <display-name>JSTL core</display-name>
10 <tlib-version>1.1</tlib-version>
11 <short-name>firstLabel</short-name>
12 <uri>http://java.sun.com/jsp/jstl/core</uri>
13
14 <!-- 創建自定義 迭代標籤 -->
15 <tag>
16  <name>forEach</name>
17  <tag-class>exercise.taglib.ForEach</tag-class>
18  <!-- 如果沒有標籤體,設置empty , 如果有標籤休必須設置JSP-->
19  <body-content>JSP</body-content>
20  <attribute>
21   <name>id</name>
22   <required>true</required><!-- 標識屬性是否是必須的 -->
23   <rtexprvalue>true</rtexprvalue><!-- 標識屬性值是否可以用表達式語言 -->
24  </attribute>
25  <attribute>
26   <name>collection</name>
27   <required>true</required>
28   <rtexprvalue>true</rtexprvalue>
29  </attribute>
30 </tag>
31
32 <!-- 創建自定義獲得屬性標籤 -->
33 <tag>
34  <name>getProperty</name>
35  <tag-class>exercise.taglib.GetProperty</tag-class>
36  <body-content>empty</body-content>
37  <attribute>
38   <name>name</name>
39   <required>true</required>
40   <rtexprvalue>true</rtexprvalue>
41  </attribute>
42  <attribute>
43   <name>property</name>
44   <required>true</required>
45   <rtexprvalue>true</rtexprvalue>
46  </attribute>
47 </tag>
48
49 <!-- 配置一個表達式調用 的函數 -->
50    <function>
51     <name>add</name><!-- 配置一個標籤,在JSP頁面通過引用前綴調用 -->
52     <function-class>exercise.taglib.ELFunction</function-class><!-- 實現類 -->
53     <function-signature>int add(int,int)</function-signature><!-- 靜態的方法:包括返回類型,方法名,入參的類型 -->
54    </function>
55</taglib>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章