下面是項目結構圖:
下面是代碼清單:
這是firsttag.tag檔案
<%@ tag import="java.util.date" import="java.text.dateformat" %>
<%
dateformat dateformat = dateformat.getdateinstance(dateformat.full) ;
date now = new date(system.currenttimemillis()) ;
out.println(dateformat.format(now)) ;
%>
firsttagtest.jsp
<%@ page language="java" import="java.util.*" pageencoding="utf-8"%>
<%@ taglib prefix="easy" tagdir="/web-inf/tags" %>
<html>
<head>
<title>my jsp 'firsttagtest.jsp' starting page</title>
</head>
<body>
today is <easy:firsttag></easy:firsttag>
</body>
</html>
項目運作截圖:
像jsp頁面一樣,标簽檔案可以利用指令來控制jsp容器如何編譯和轉換标簽檔案。标簽檔案指令的文法與jsp指令的文法一樣:
<%@ directive (attribure=”value”)* %>
星号(*)表示括号中的内容可以不重複,也可以重複多次。這個文法可以用一種比較随意的方式進行改寫:
<%@ directive attribute1=”value1” attribute2=”value2” ... %>
其中的屬性必須用單引号或者雙引号括起來,起始符号<%@後面的空格和結束符号%>前面的空格是可選的,不過使用空格可以提升可讀性。
除了page之外,所有jsp指令在标簽檔案中都可以使用。這裡不用page,而是用tag指令。而且,在标簽檔案中,還有另外兩個指令可以使用:attribute和variable。下面是可以在标簽檔案中使用的所有指令。
1、tag。該指令與jsp頁面的page指令相似
2、include。用這個指令包含來自标簽檔案的其他資源
3、taglib。用這個指令從标簽檔案内部使用定制标簽類庫
4、attribute。用這個指令在标簽檔案中聲明一個屬性
5、variable用這個指令定義一個可以暴露給在調用jsp頁面的變量
tag指令的文法:
<%@ tag (attribute=”value”)* %>
以上文法用非正式的可以表示為:
<%@ tag attribute1=”value1” attribute2=”value2” ... %>
tag指令的屬性為:
display-name:通過xml工具顯示的簡稱,預設值為标簽檔案名,沒有tag擴充名。
body-content:關于這個标簽主體内容的資訊,它的值可以為empty、tagdependent或scriptless(預設)。
dynamic-attributes:表名對動态屬性的支援。它的值表示一個放置map的有界屬性,其中包含了這個調用期間傳遞的動态屬性名和值
small-icon:xml工具要用到的小圖檔檔案相對于context的路徑,或者相對于标簽資源檔案的路徑。我們通常不使用這個屬性。
large-icon:包含xml工具要用到的大圖示圖檔檔案相對于context的路徑,或者相對于标簽資源檔案的路徑。我們通常也不使用這個屬性。
description:描述該标簽的一個字元串。
example:該動作指令用法範例的一個非正式描述。
import:用于導入java類型,與page指令中的import屬性相同。
pageencoding:描述該标簽檔案的字元編碼,這個值的形式為“charset”,必須是字元編碼的iana名稱。該屬性與page指令的pageencoding屬性相同。
iselignored:表名忽略還是運算el表達式,該屬性的預設值為“false”,意為運算el表達式,該屬性與page指令的iselignored屬性相同。
除了import屬性之外,所有其他屬性在同一個标簽檔案的一個tag指令或者多個tag指令中都隻能出現一次。例如,以下tag檔案就是無效的,因為body-content屬性不止一次地出現在多個tag指令中:
<%@ tag display-name=”first tag file” body-content=”scriptless”%>
<%@ tag body-content=”empty” %>
下面是項目代碼片段:
includedemotag.tag
this tag file shows the use of whe include directive.
the first include directive demontrates how you can include
a static resource called included.html
<br />
here is the content of included.html
<%@ include file="included.html" %>
the second include directive includes another dynamic resource:
included.tagf.
<%@ include file="included.tagf" %>
included.html
<table>
<tr>
<td><b>menu</b></td>
</tr>
<td>cds</td>
<td>dvds</td>
<td>others</td>
</table>
included.tagf
out.print("hello from included.tagf") ;
includedemotagtest.jsp
<easy:includedemotag></easy:includedemotag>
打開浏覽器輸入位址:
http://localhost:8089/testtag/includedemotagtest.jsp
利用taglib指令可以使用标簽檔案中的定制标簽。taglib指令的文法如下:
<%@ taglib uri=”taglibraryuri prefix=”tagprefix””%>
uri屬性指定一個絕對或相對的uri,用來唯一辨別與這個字首相關的标簽類庫描述符,prefix屬性定義一個字元串,它将成為用于區分某個定制動作指令的字首。
有了taglib指令,就可以通過以下格式使用不帶内容主體的定制标簽:
<prefix:tagname/>
或者通過以下格式使用帶有内容主體的定制标簽:
<prefix:tagname>body</prefix:tagname>
attribute指令支援在标簽檔案中使用屬性,它相當于标簽類庫描述符中的attribute元素。文法如下:
<%@ attribute (attribute=”value”) %>
上述文法也可以用一種非正式的形式進行表達,如:
<%@ attribute attribute1 = “value1” attribute2=”value2” ... %>
attribute中的name屬性是必須的。屬性清單如下:
name:該标簽檔案能夠接受的屬性名稱,name屬性值必須在整個目前标簽檔案中都是唯一的。
required:表明該屬性是否是必須的,它的值可以是true或false。
fragment:表明該屬性是一個要通過标簽處理器進行運算的部分,或在傳給标簽處理器之前通過容器進行運算的一個普通屬性。它的值為true或者false。如果該屬性要通過标簽處理器進行運算,則值為true。
rtexprvalue:指定該屬性值是否可以在運作時通過一個scriplet表達式進行動态計算。這個值為true(預設值)或者false。
type:屬性值的類型,預設為java.lang.string
description:這個屬性的描述
下面是這個指令的測試:
encode.tag:
<%@ attribute name="input" required="true" %>
<%!
private string encodehtmltag(string tag){
if(tag == null){
return null ;
}
int length = tag.length() ;
stringbuilder encodedtag = new stringbuilder(2 * length) ;
for(int i=0; i<length; i++){
char c = tag.charat(i) ;
if(c == '<'){
encodedtag.append("<") ;
}else if(c == '>'){
encodedtag.append(">") ;
}else if(c == '&'){
encodedtag.append("&") ;
}else if(c == '"'){
encodedtag.append(""") ;
}else if(c == ' '){
encodedtag.append(" ") ;
}else{
encodedtag.append(c) ;
}
return encodedtag.tostring() ;
}
<%=encodehtmltag(input)%>
encodetagtest.jsp
<%@ taglib prefix="easy" tagdir="/web-inf/tags" %>
<title>my jsp 'encodetagtest.jsp' starting page</title>
<easy:encode input="<br />hello csdn" />
variable指令的文法如下:
<%@ variable (attribute=”value”)* %>
非正式形式的表達文法如下:
<%@ variable attribute1=”value” attribute2=”value2” %>
variable指令的屬性如下:
name-given:将要在調用jsp頁面的腳本語言或者el表達式中使用的變量名稱。如果使用name-form-attribute,就不能再用name-given屬性,反之亦然。name-given的值不能與該标簽檔案中的任何屬性值相同。
name-from-attribute:該屬性與name-given類似,但是它的值應該是一個屬性的名稱,并且它在開始進行标簽調用之時提供變量名稱,如果同時指定name-given和name-form-attribute屬性,或者這兩者都沒有指定,那麼将會産生編譯錯誤。
alias:這是一個局部範圍的屬性,用于存放該變量的值。
variable-class:該變量的類型,預設為java.lang.string
declare:表明是在調用頁面中聲明該變量,還是在調用之後在标簽檔案中聲明。預設值為true。
scope:所定義腳本變量的範圍,其可能值為at_begin、at_end和nested(預設)
description:該變量的描述
你可能會問,如果可以将處理結果直接輸出到在調用jsp頁面的jspwriter,那麼為什麼還需要variable指令呢?這是因為,隻将string發送到jspwriter,會導緻在調用的jsp頁面喪失如何使用該結果的靈活性。例如将伺服器的目前如期以long格式輸出。如果你還想以short格式提供伺服器的目前日期,那麼就必須另外編寫一個标簽檔案。有兩個标簽檔案來完成類似功能時,會增加不必要的維護問題。替代做法是,在标簽檔案中暴露兩個變量:longdate和shortdate。
下面是測試代碼:
vardemo.tag
<%@ variable name-given="longdate" %>
<%@ variable name-given="shortdate" %>
dateformat longformat = dateformat.getdateinstance(dateformat.long) ;
dateformat shortformat = dateformat.getdateinstance(dateformat.short) ;
jspcontext.setattribute("longdate", longformat.format(now)) ;
jspcontext.setattribute("shortdate", shortformat.format(now)) ;
<jsp:dobody></jsp:dobody>
vardemotest.jsp
<%@ taglib tagdir="/web-inf/tags" prefix="easy" %>
<title>my jsp 'vardemotest.jsp' starting page</title>
today's date:
<easy:vardemo>
in long format: ${longdate}
<br />
in short format: ${shortdate}
</easy:vardemo>
标簽動作指令dobody隻能通過标簽檔案内部進行使用。我們可以用它調用标簽的主體。
dobody動作指令可以帶有屬性。如果需要将标簽調用的結果導入到某個變量中,就可以使用這些屬性。如果使用dobody時不帶屬性,那麼标準動作指令dobody就會将輸出結果寫入在所調用jsp頁面的jspwriter中。
标準指令dobody的屬性如下:
var:這是一個限域屬性名稱,用來儲存标簽主體調用的輸出。它的值儲存為java.lang.string。var和varreader二者不能同時存在。
varreader:這是一個限域屬性名稱,用來儲存标簽主體調用的輸出。它的值儲存為java.io.reader。var和varreader二者不能同時存在。
scope:結果變量的範圍。
下面是對于dobody的例子:
dobodydemo.tag
<jsp:dobody var="referer" scope="session"></jsp:dobody>
main.jsp
<%@ taglib prefix="tags" tagdir="/web-inf/tags" %>
your referer header:${header.referer}
<br/>
<tags:dobodydemo>
${header.referer}
</tags:dobodydemo>
<a href="viewreferer.jsp">view</a> the referer as a session attribute.
viewreferer.jsp
the referer header of the previous page is ${sessionscope.referer}
searchenginer.html
please click <a href="main.jsp">here</a>
invoke标準動作指令與dobody相似,可以在标簽檔案中用來調用一個fragment屬性。前面說過,屬性可以帶有一個fragment屬性,它的值為true或false。如果fragment屬性值為true,那麼該屬性就是一個fragment屬性,你可以根據需要通過标簽檔案對它進行多次調用。invoke也可以帶有屬性。invoke的屬性如下,注意:隻有fragment屬性是必須的。
fragment:在這個标簽調用期間用于辨別該fragment的名稱。
var:這是一個限域屬性名稱,用來儲存标簽主體調用的輸出。它的值儲存為java.lang.string。var或varreader屬性二者不能同時存在。
下面是對于invoke的例子:
invokedemo.tag
<%@ attribute name="productdetails" fragment="true" %>
<%@ variable name-given="productname" %>
<%@ variable name-given="description" %>
<%@ variable name-given="price" %>
jspcontext.setattribute("productname", "pelesonic dvd player") ;
jspcontext.setattribute("description", "dolby digital output through coaxial digital-audio jack,"+
" 500 lines horizontal resoulution-image digest viewing") ;
jspcontext.setattribute("price", "65") ;
<jsp:invoke fragment="productdetails"></jsp:invoke>
invoketest.jsp
<title>my jsp 'invoketest.jsp' starting page</title>
<easy:invokedemo>
<jsp:attribute name="productdetails">
<table width="220" border="1">
<tr>
<td><b>productname</b></td>
<td><b>${productname}</b></td>
</tr>
<td><b>description</b></td>
<td><b>${description}</b></td>
<td><b>price</b></td>
<td><b>${price}</b></td>
</table>
</jsp:attribute>
</easy:invokedemo>
下面是結果截圖: