天天看點

JSTL标簽庫

  JSTL是Sun公司開發的一套用于JSP頁面中的标簽庫,使用JSTL可以在頁面中實作一些簡單的邏輯,進而替換頁面中的Java代碼。JSTL通常也會配合EL表達式一起使用,Sun公司的JSTL标簽庫封裝了大量的方法,當然如果JSTL中的标簽不能滿足我們的需求時,我們還可以通過使用自定義标簽達到我們的需求,關于自定義标簽會在之後的文章中講解。

  JSTL标簽庫是一個很大的庫,主要包含了以下幾種:

  ⑴ JSTL核心标簽庫——c.tld

  ⑵ 國際化标簽——fmt.tld

  ⑶ JSTL函數(EL函數)——fn.tld

  ⑷ 資料庫标簽  (不符合MVC模式,不用學)——sql.tld

  ⑸ XML标簽 (不符合MVC模式,不用學)——x.tld

  JSTL函數已經在《EL表達式(3)》中學習過,這裡就不再叙述;國際化标簽會在之後的文章中講解和學習。今天主要來學習JSTL核心标簽庫。

  在MyEclipse10中,建立JavaEE 5.0以上的版本都會預設帶上JSTL開發包,并且使用的是JSTL1.2版本:

  

JSTL标簽庫
  而如果建立的是J2EE 1.4及以下的版本,需要自己選擇是否添加JSTL支援,并且如果選擇添加,那麼導入的是JSTL1.1版本:
JSTL标簽庫

  JSTL1.2版本和JSTL1.1的版本在JAR包上的差別是JSTL1.2隻需要“jstl-1.2.jar”一個包就足夠了,而JSTL1.1需要“jstl.jar”包和“standard.jar”包的支援。如果我們在工程中缺少相對應的包,隻需要選擇合适的jar包導入即可。

  當然,這隻是外部版本的差別,其實不管是JSTL1.2版本還是JSTL1.1的版本,對于JSTL核心标簽庫都是使用“JSTL 1.1 core library”,我想差別可能是另外幾個庫吧。

在本篇中,我們均是以Java EE 5.0為WEB的Java版本,是以均采用JSTL1.2版本。

  除了要導入需要的jar包,要想使用JSTL标簽,還必須在JSP頁面中使用taglib指令導入需要的标簽庫。

文法:

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

  uri屬性:用來指定使用JSTL标簽庫中的哪個标簽庫。

  prefix屬性:用來指定在JSP頁面中使用該标簽的字首文字。

   那麼如何使用uri屬性來指定使用哪個标簽庫呢?我們可以點選工程中的“jstl-1.2.jar”包:

JSTL标簽庫

  這個jar包中有很多包和類,在最下面有一個“META-INF”目錄,這裡面儲存了很多标簽所需要的tld檔案,分别代表不同的庫,而我們所需要的jstl核心庫就是“c.tld”檔案:

JSTL标簽庫

  對于jstl核心庫的所有标簽,都在這個“c.tld”檔案中進行了聲明描述。而這些所有的标簽都綁定到了一個uri上,通過在JSP中使用taglib指令導入這個uri,那麼我們就能使用這個标簽庫了,而這個uri就在“c.tld”檔案的<taglib>标簽下:

JSTL标簽庫

是以我們在JSP頁面中使用taglib指令就可以這樣導入該标簽庫:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>      

  這裡taglib指令中的uri一定要和tld檔案中的uri一緻,而prefix字首通常采用tld檔案的檔案名,這樣容易明白這個标簽出自哪個JSTL庫。

  通過以上步驟,JSTL标簽庫的環境就已經配置好了,接下來我們就可以使用JSTL的核心庫标簽了。

  補充前言:标簽中如果含有“var”屬性,就是講該标簽的執行結果以“var”屬性的值存儲到某個域中,通常都會有“scope”屬性來指定存儲到哪個域中,如果沒有一般都是存儲到page域中。

  下面介紹幾個JSTL核心标簽庫中的幾個标簽的使用,較為常用的有前面三個:

一.<c:forEach>标簽

使用<c:forEach>标簽可以配合EL表達式對使用EL擷取的集合進行疊代,這一點光憑EL表達式是無法做到的。

例1-1:

JSTL标簽庫
JSTL标簽庫
1     <%
 2            ArrayList<Person> list = new ArrayList<Person>();
 3            list.add(new Person("Ding",25));
 4            list.add(new Person("LRR",24));
 5            pageContext.setAttribute("personList", list);
 6     %>
 7     
 8     <c:forEach var="person" items="${personList}">
 9         ${person.name }  <br>
10 </c:forEach>      

View Code

  分析:這個例子中在<c:forEach>标簽内,“items”屬性用于指定擷取疊代的對象。記住,這裡一定要用EL表達式才能擷取存儲在域中的對象。而“var”屬性則是對每次疊代的元素以var的值為關鍵字存在域中,就好像使用了Map集合一樣,對集合中的每個元素作為value值,而“var”名稱作為key一樣。

  在上面的示例中,items通過EL表達式擷取域對象中的“list”集合,而對“list”集合的每次疊代都是一個Person對象,這個Person對象使用了var屬性指定的值作為引用。是以在标簽體中,再次使用了EL表達式,而這個EL表達式中的“person”既是var屬性所指的名稱,也是每次疊代的Person對象的引用,而Person對象中含有name屬性,是以可以使用EL表達式取出,這點與之前學過的EL擷取資料還是一樣的道理。在浏覽器中觀察:

JSTL标簽庫

例1-2:

JSTL标簽庫
JSTL标簽庫
1     <%
 2            Map<String,Person> map = new HashMap<String,Person>();
 3            map.put("p1",new Person("Ding",25));
 4            map.put("p2",new Person("LRR",24));
 5            pageContext.setAttribute("personMap", map);
 6     %>
 7     
 8     <c:forEach var="entry" items="${personMap}">
 9         ${entry.value.name }  <br>
10     </c:forEach>      

  分析:在這個例子中,“items”屬性依然還是擷取要疊代的對象(使用EL表達式才能擷取域對象中儲存的要疊代的集合對象)。而這裡我們使用<c:forEach>标簽并不是真正對Map集合進行疊代,而是将Map集合先調用了entrySet方法,擷取到的是Set<Map.Entry<K,V>>集合,然後再對這個Set集合進行疊代:

JSTL标簽庫

  那麼也就是說對于“var”屬性,指定的都是對Set集合進行疊代出來元素的引用,而Set集合疊代出來的每個元素都是Map.Entry集合,即以“var”名稱所引用。是以上述示例中的var屬性的值“entry”代表了每次疊代出來的Map.Entry集合,而這個Map.Entry集合中含有key屬性和value屬性(通過API可以看到含有getKey方法和getValue方法),是以在标簽體中,${entry.value}代表了存在Map集合中的Person對象,另外${entry.key}代表了Map集合中Person對象所被引用的key值(如”p1”)。

在浏覽器中觀察:

JSTL标簽庫

  通過上面兩個例子,可以大體了解了<c:forEach>标簽的使用,當然<c:forEach>标簽還有一些需要了解的地方:

JSTL标簽庫

例1-3:

JSTL标簽庫
JSTL标簽庫
1     <c:forEach var="num" begin="1" end="9" step="1" >
2         ${num }
3     </c:forEach>      

浏覽器觀察:

JSTL标簽庫

可以看到在<c:forEach>标簽中,如果沒有“items”屬性,那麼就從begin屬性指定的值開始疊代,直到end屬性指定的值為止,而“var”屬性依然是作為每次疊代出來元素的引用。

  在<c:forEach>标簽中還有一個“varStatus”屬性,這個屬性用來封裝儲存疊代資訊的對象,比如這是第幾個疊代對象,是否是第一個疊代對象,是否是最後一次疊代對象等等,在“varStatus”屬性下,還有屬于varStatus的幾個從屬性,這些可以配合EL表達式使用:

  index:目前這次疊代從 0 開始的疊代索引

  count:目前這次疊代從 1 開始的疊代計數

  first:用來表明目前這輪疊代是否為第一次疊代的标志

  last:用來表明目前這輪疊代是否為最後一次疊代的标志

  begin:屬性值

  end:屬性值

  step:屬性值

例1-4:

JSTL标簽庫
JSTL标簽庫
1     <%
 2            ArrayList<Person> list = new ArrayList<Person>();
 3            list.add(new Person("Ding",25));
 4            list.add(new Person("LRR",24));
 5            
 6            pageContext.setAttribute("personList", list);
 7        %>
 8        
 9     <c:forEach var="person" items="${personList }" varStatus="listInfo" >
10         ${person.name } ---- ${listInfo.count }   <br>
11     </c:forEach>      

浏覽器中觀察:

JSTL标簽庫

  這裡使用到的是”varStatus”屬性的從屬性“count”,用來表示目前這次疊代從 1 開始的疊代計數。其他的從屬性都是類似的用法。

二.<c:if>标簽

  <c:if  test=“。。。”>标簽(test屬性是必須的)用于測試某個條件是否成立,經常配合EL表達式使用。

JSTL标簽庫

例2-1:

JSTL标簽庫
JSTL标簽庫
1     <c:if test="${user!=null}">
2         歡迎您:user.name
3     </c:if>      

  分析:“test”屬性隻接收布爾類型,當“test”屬性為“true”時才執行<c:if>标簽的标簽體中的内容,當“test”屬性為“false”時标簽體内容自動忽略。

例2-2:

JSTL标簽庫
JSTL标簽庫
1     <c:if var="booleanTest" test="${user!=null}" scope="page">
2         歡迎您:user.name
3     </c:if>  
4     
5     ${booleanTest }      

輸出:false

  分析:“test”屬性傳回Boolean性結果(true或false),“var”屬性均是作為存儲資料用的,這裡是将“test”屬性的結果以“var”屬性的值(這裡是booleanTest)存儲到某個域中,存到什麼域呢,由“scope”屬性指定。這樣最後能由EL表達式從域中根據“var”屬性的值取出相對應的資料。

  總結:隻要某個标簽含有“var”屬性,就是講該标簽的執行結果以“var”屬性的值存儲到某個域中,通常都會有“scope”屬性來指定存儲到哪個域中,如果沒有一般都是存儲到page域中。

三.<c:url>标簽與<c:param>标簽

  <c:url>标簽用于在JSP頁面中建立一個URL位址,最關鍵的目的在于<c:url>标簽能對其“value”屬性提供的URL位址進行重寫,加入JSESSIONID,以便于在通路禁用cookie的主機能為其建立session等功能。這一點在《Servlet的學習之Session(3)》 中已經介紹過。

  下圖為<c:url>标簽中的屬性介紹:

JSTL标簽庫

例3-1:

JSTL标簽庫
JSTL标簽庫
1     <c:url var="index" value="${pageContext.request.contextPath}/index" />
2     
3     <a href="${index}" >首頁</a>      
JSTL标簽庫

檢視網頁源碼:

JSTL标簽庫

  可以看到在首次通路時确實在URL後面跟了JSESSIONID,這是<c:url>标簽用于防止客戶浏覽器禁止了Cookie,同樣的,如果伺服器發現了客戶機浏覽器并沒有禁用cookie的話,那麼再次通路的話,<c:url>标簽會将這個JSESSIONID會自動删去,這一點同使用Response.encodeURL()方法或Response.encodeRedirectURL()方法是一樣的。

  另外:<c:url>标簽中使用了“var”屬性,就是将“value”中的URL進行重寫後儲存在域中(預設為page域,可用“scope”選擇域)。那麼在其他HTML标簽中如果有需要URL的超連結時,隻需要使用EL表達式從域中取出即可,取出的即使經過URL重寫的超連結URL,正如上面的例子。

例3-2:

<c:url value="/index" />      
JSTL标簽庫

  如果沒有使用到“var”屬性,那麼這個标簽會将内容直接顯示在網頁中,這一點要注意。同時該注意的還有這種沒有“var”屬性,會自動在URL前面添加web應用的名稱!是以在沒有使用“var”屬性的<c:url>标簽中的“value”屬性一定不要添加web應用的名稱。

例3-3:

<a href='<c:url value="/index" />'>首頁</a>      

在浏覽器中觀察及網頁源碼:

JSTL标簽庫

  通常<c:url>标簽還配合<c:param>标簽一起使用。使用<c:param>标簽可以在URL後面添加請求參數,更為重要的一點在于,使用<c:param>标簽能對參數中的中文進行URL重寫,這一點在《Servlet的學習之Request請求對象(2)》中說明了另一種解決方法。

例3-4:

JSTL标簽庫
JSTL标簽庫
1 <c:url var="index" value="${pageContext.request.contextPath}/index.jsp" >
2     <c:param name="username" value="銀魂"></c:param>
3 </c:url>
4     
5 <a href="${index}">首頁</a>      

在浏覽器中觀察及其網頁源碼:

JSTL标簽庫

  可以看到在網頁源碼中,URL位址後面已經跟随了請求參數,同時當請求參數中包含中文時也對中文進行了URL重寫。

四.<c:out>标簽

JSTL标簽庫
<c:out value="aaaa" />      

輸出:aaaa。

<c:out value="<a href='www.baidu.com'>百度</a>" escapeXml="true" />      

輸出:

JSTL标簽庫

五.<c:set>标簽

  <c:set>标簽用于把一個對象或資料存在指定的域範圍内,或者設定web域中的java.util.Map類型的屬性對象,或者JavaBean類的屬性對象的屬性。

JSTL标簽庫

例4-1:

JSTL标簽庫
JSTL标簽庫
1     <c:set var="name" value="ding" scope="page" />
2     
3     ${name }      

輸出:ding。

例4-2:

JSTL标簽庫
JSTL标簽庫
1     <%
2            HashMap map = new HashMap();
3            pageContext.setAttribute("map", map);
4     %>
5    
6     <c:set property="name" value="ding" target="${map}" ></c:set>
7     
8        ${map.name }      

例4-3:

JSTL标簽庫
JSTL标簽庫
1     <%
2        Person p = new Person();
3            pageContext.setAttribute("person", p);
4     %>
5    
6     <c:set property="age" value="25" target="${person}" ></c:set>
7     
8        ${person.age }      

輸出:25

六.<c:remove>标簽

  <c:remove>标簽用于移除web域中的各種儲存的資料。

文法格式:

<c:remove    var=”儲存的資料引用名”
                [scope=“{ page(預設) | request | session | application }”] />      

七.<c:redirect >标簽

  <c:redirect>标簽用于進行網頁的重定向。

JSTL标簽庫

繼續閱讀