認識到了用javabean分離表現邏輯和業務邏輯的不足之處之後,jsp1.1就定義了定制标簽。定制标簽具有javabeans所沒有的優勢。例如,定制标簽可以通路jsp隐式對象,可以帶有屬性等。
在jsp2.0中,他們在javax.servlet.jsp.tagext包中添加了新的接口:simpletag。實作simpletag接口的标簽處理器稱作簡單的标簽處理器,實作tag、iteration或bodytag接口的标簽處理器稱作典型的标簽處理器。
簡單的标簽處理器的聲明周期更加簡單,并且更容易。simpletag接口中隻有一個方法:dotag,并且在标簽調用時隻執行一次。業務邏輯、疊代及主體操作代碼都要在這裡編寫。簡單的标簽處理器中的主體是用一個jspfragment類執行個體表示的。
一個簡單的标簽處理器的生命周期如下:
1、jsp容器通過調用其無參構造器,建立一個簡單标簽處理器執行個體。是以,簡單的标簽處理器必須有一個無參構造器。
2、jsp容器調用setjspcontext方法,同時傳遞一個jspcontext對象。jspcontext最重要的方法是getout,它傳回一個jspwriter,用于将響應發送到用戶端。setjspcontext方法的簽名如下:
public void setjspcontext(jspcontext jspcontext)
大多數時候,會需要将傳進的jspcontext賦給一個類變量,以便供後續使用。
3、如果表示标簽處理器的定制标簽是嵌套在另一個标簽中的,jsp容器就會調用setparent方法。該方法具有以下簽名:
public void setparent(jsptag parent)
4、jsp容器為給該标簽定義的每個屬性都調用設定方法。(setter)
5、如果标簽中有主體内容,jsp将調用simpletag接口的setjspbody方法,将主體内容作為jspfragment傳遞。如果沒有主體内容,jsp容器則不會調用這個方法。
6、jsp容器調用dotag方法。所有變量在dotag方法傳回時進行同步。
下面是我的測試代碼的項目結構。
下面是我的代碼:
package customtag;
import java.io.ioexception;
import javax.servlet.jsp.jspcontext;
import javax.servlet.jsp.jspexception;
import javax.servlet.jsp.tagext.jspfragment;
import javax.servlet.jsp.tagext.jsptag;
import javax.servlet.jsp.tagext.simpletag;
public class myfirsttag implements simpletag{
jspcontext jspcontext ;
public void dotag() throws jspexception, ioexception {
// todo auto-generated method stub
system.out.println("dotag");
jspcontext.getout().print("this is my first tag.") ;
}
public jsptag getparent() {
system.out.println("getparent");
return null;
public void setjspbody(jspfragment arg0) {
system.out.println("set jspbody");
public void setjspcontext(jspcontext arg0) {
system.out.println("setjspcontext");
this.jspcontext = arg0 ;
public void setparent(jsptag arg0) {
system.out.println("set parent");
}
<?xml version="1.0" encoding="utf-8"?>
<taglib xmlnx="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xsi:schemalocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_1.xsd"
version="2.1">
<description>
simple tag examples
</description>
<tlib-version>1.0</tlib-version>
<short-name>my first taglib example</short-name>
<tag>
<name>firsttag</name>
<tag-class>customtag.myfirsttag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
<%@ page language="java" import="java.util.*" pageencoding="utf-8"%>
<%@ taglib prefix="easy" uri="/web-inf/mytags.tld" %>
<html>
<head>
<title>testing my first tag</title>
</head>
<body>
hello!!!
<br />
<easy:firsttag/>
</body>
</html>
實作simpletag接口或者繼承simpletagsupport的标簽處理器可以帶有屬性。
下面是項目結構圖:
下面是程式代碼:
import java.util.stringtokenizer;
import javax.servlet.jsp.jspwriter;
import javax.servlet.jsp.tagext.simpletagsupport;
public class dataformattertag extends simpletagsupport{
private string header ;
private string items ;
public void setheader(string header) {
this.header = header;
public void setitems(string items) {
this.items = items;
@override
jspcontext jspcontext = getjspcontext() ;
jspwriter out = jspcontext.getout() ;
out.print("<table style='border:1px solid green'>\n"
+"<tr><td><span style='font-wright:bold'>"
+ header + "</span></td></tr>\n") ;
stringtokenizer tokenizer = new stringtokenizer(items, ",") ;
while(tokenizer.hasmoretokens()){
string token = tokenizer.nexttoken() ;
out.print("<tr><td>" + token + "</td></tr>\n") ;
}
out.print("</table>") ;
<?xml version="1.0" encoding="utf-8"?>
<taglib xmlnx="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xsi:schemalocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_1.xsd"
version="2.1">
<tlibversion>2.1</tlibversion>
<jspversion>2.1</jspversion>
<name>dataformatter</name>
<tag-class>customtag.dataformattertag</tag-class>
<attribute>
<name>header</name>
<required>true</required>
</attribute>
<name>items</name>
</taglib>
<%@ taglib uri="/web-inf/mytags.tld" prefix="easy"%>
<title>testing dataformattertag</title>
<easy:dataformatter items="alabama,alaska,georgia,florida" header="states"/>
<br/>
<easy:dataformatter header="countries">
<jsp:attribute name="items">
us,uk,canada,korea
</jsp:attribute>
</easy:dataformatter>
運作結果圖:
有了simpletag,就可以通過jsp闖過來的jspfragment管理标簽主體了。jspfragment類表示一段jsp代碼,可以不調用,也可以調用多次。jsp片段的定義中不能包含scriplet或者scriptlet表達式,它隻能包含模版文本和jsp動作指令元素。
jspfragment類有兩個方法:getjspcontext和invoke,其方法簽名如下:
public abstract jspcontext getjspcontext()
public abstract void invoke(java.io.writer writer)throws jspexception, java.io.ioexception
getjspcontext方法傳回與這個jspfragment相關的jspcontext。我們可以調用invoke方法來執行片段(标簽主體),并将所有輸出内容導到指定的writer。如果傳給invoke方法的值為null,那麼輸出的結果将會被導到與該片段相關的jspcontext的getout方法所傳回的jspwriter。
下面是代碼段:
public class selectelementtag extends simpletagsupport{
private string[] countries = {"australia", "brazil", "china"} ;
out.print("<select>\n") ;
for(int i=0;i<3; i++){
getjspcontext().setattribute("value", countries[i]) ;
getjspcontext().setattribute("text", countries[i]) ;
getjspbody().invoke(null) ;
out.print("</select>\n") ;
<name>select</name>
<tag-class>customtag.selectelementtag</tag-class>
<body-content>scriptless</body-content>
<%@ taglib uri="/web-inf/mytags.tld" prefix="easy" %>
<title>my jsp 'selectelementtagtest.jsp' starting page</title>
<easy:select>
<option value="${value }">${text }</option>
</easy:select>
輸出結果顯示:
一般來說,編寫一個el函數要遵循以下兩個步驟:
1、建立一個包含講台方法的public類。每個靜态方法表示一個函數。這個類不需要實作接口或者繼承類。你可以根據需要,像對待其他任何類一樣部署這個類。這個類必須儲存到web-inf/classes目錄或其下面的某個目錄中。
2、利用function元素在标簽類庫描述符中注冊函數。
function元素必須直接放在taglib元素下,并且可以帶有以下子元素:
description。這是一條特定于标簽的可選資訊。
display-name。xml工具顯示的簡稱。
icon。xml工具可以使用的可選圖示元素。
name。該函數獨特的名稱。
function-class。實作該函數的java類的全類名。
function-signature。表示該函數的靜态java方法簽名。
example。使用該函數的一個example的可選資訊描述。
function-extension。通過xml工具使用,沒有擴充名,或者有多個擴充名,提供關于該函數的其他資訊。
使用函數時,需利用taglib指令及其uri屬性,它指向标簽類庫描述符,以及要使用的字首。然後在jsp頁面中利用以下文法調用函數:
${prefix:functionname(parameterlist)}
下面是關于el函數的例子:
package function;
public class stringfunctions {
public static string reversestring(string s){
return new stringbuffer(s).reverse().tostring() ;
<%@ taglib uri="/web-inf/functions.tld" prefix="f" %>
<title>my jsp 'reversestringfunctiontest.jsp' starting page</title>
${f:reversestring("hello world")}
<function>
<description>
reverse a string
</description>
<name>
reversestring
</name>
<function-class>
function.stringfunctions
</function-class>
<function-signature>
java.lang.string reversestring(java.lang.string)
</function-signature>
</function>
在浏覽器輸入:http://localhost:8089/servlet/reversestringfunctiontest.jsp
我們可以将定制标簽處理器和标簽類庫描述符打包成一個jar檔案,以便發給其他人使用,像jstl一樣。在這種情況下,就需要包含所有的标簽處理器,以及描述它們的tld檔案。此外,還需要在描述符的uri元素中指定一個絕對的url。
例如,我就打包成一個cc.jar檔案。jar檔案内容如圖所示。
可以直接利用cmd的jar指令打包,如圖:
這樣我們就可以把jar包複制到項目的lib目錄下,并且jsp中引用剛才的uri位址。
項目運作截圖: