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版本:

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”包:
這個jar包中有很多包和類,在最下面有一個“META-INF”目錄,這裡面儲存了很多标簽所需要的tld檔案,分别代表不同的庫,而我們所需要的jstl核心庫就是“c.tld”檔案:
對于jstl核心庫的所有标簽,都在這個“c.tld”檔案中進行了聲明描述。而這些所有的标簽都綁定到了一個uri上,通過在JSP中使用taglib指令導入這個uri,那麼我們就能使用這個标簽庫了,而這個uri就在“c.tld”檔案的<taglib>标簽下:
是以我們在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:
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擷取資料還是一樣的道理。在浏覽器中觀察:
例1-2:
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集合進行疊代:
那麼也就是說對于“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”)。
在浏覽器中觀察:
通過上面兩個例子,可以大體了解了<c:forEach>标簽的使用,當然<c:forEach>标簽還有一些需要了解的地方:
例1-3:
1 <c:forEach var="num" begin="1" end="9" step="1" >
2 ${num }
3 </c:forEach>
浏覽器觀察:
可以看到在<c:forEach>标簽中,如果沒有“items”屬性,那麼就從begin屬性指定的值開始疊代,直到end屬性指定的值為止,而“var”屬性依然是作為每次疊代出來元素的引用。
在<c:forEach>标簽中還有一個“varStatus”屬性,這個屬性用來封裝儲存疊代資訊的對象,比如這是第幾個疊代對象,是否是第一個疊代對象,是否是最後一次疊代對象等等,在“varStatus”屬性下,還有屬于varStatus的幾個從屬性,這些可以配合EL表達式使用:
index:目前這次疊代從 0 開始的疊代索引
count:目前這次疊代從 1 開始的疊代計數
first:用來表明目前這輪疊代是否為第一次疊代的标志
last:用來表明目前這輪疊代是否為最後一次疊代的标志
begin:屬性值
end:屬性值
step:屬性值
例1-4:
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>
浏覽器中觀察:
這裡使用到的是”varStatus”屬性的從屬性“count”,用來表示目前這次疊代從 1 開始的疊代計數。其他的從屬性都是類似的用法。
二.<c:if>标簽
<c:if test=“。。。”>标簽(test屬性是必須的)用于測試某個條件是否成立,經常配合EL表達式使用。
例2-1:
1 <c:if test="${user!=null}">
2 歡迎您:user.name
3 </c:if>
分析:“test”屬性隻接收布爾類型,當“test”屬性為“true”時才執行<c:if>标簽的标簽體中的内容,當“test”屬性為“false”時标簽體内容自動忽略。
例2-2:
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>标簽中的屬性介紹:
例3-1:
1 <c:url var="index" value="${pageContext.request.contextPath}/index" />
2
3 <a href="${index}" >首頁</a>
檢視網頁源碼:
可以看到在首次通路時确實在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" />
如果沒有使用到“var”屬性,那麼這個标簽會将内容直接顯示在網頁中,這一點要注意。同時該注意的還有這種沒有“var”屬性,會自動在URL前面添加web應用的名稱!是以在沒有使用“var”屬性的<c:url>标簽中的“value”屬性一定不要添加web應用的名稱。
例3-3:
<a href='<c:url value="/index" />'>首頁</a>
在浏覽器中觀察及網頁源碼:
通常<c:url>标簽還配合<c:param>标簽一起使用。使用<c:param>标簽可以在URL後面添加請求參數,更為重要的一點在于,使用<c:param>标簽能對參數中的中文進行URL重寫,這一點在《Servlet的學習之Request請求對象(2)》中說明了另一種解決方法。
例3-4:
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>
在浏覽器中觀察及其網頁源碼:
可以看到在網頁源碼中,URL位址後面已經跟随了請求參數,同時當請求參數中包含中文時也對中文進行了URL重寫。
四.<c:out>标簽
<c:out value="aaaa" />
輸出:aaaa。
<c:out value="<a href='www.baidu.com'>百度</a>" escapeXml="true" />
輸出:
五.<c:set>标簽
<c:set>标簽用于把一個對象或資料存在指定的域範圍内,或者設定web域中的java.util.Map類型的屬性對象,或者JavaBean類的屬性對象的屬性。
例4-1:
1 <c:set var="name" value="ding" scope="page" />
2
3 ${name }
輸出:ding。
例4-2:
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:
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>标簽用于進行網頁的重定向。