今天來整理一下simple tag這個自訂標籤處理器
tag file提供了嵌入工作的一種方式,全由JSP去完成
但在某些時候,需求無法完全依賴JSP去處理
還是需要使用java去做一些較複雜的處理時
JSP 2.0提供了一個叫做simple tag的自訂標籤處理器
如名稱一樣,透過簡單的宣告去呼叫java程式
在java去override我們要的邏輯
步驟如下:
package com.web.tag;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTagTest extends SimpleTagSupport{
}
@Override
public void doTag() throws JspException, IOException {
getJspContext().getOut().print("This is first simple tag");
}
<!--- taglib所使用的對應名稱 -->
<uri>myTag</uri>
<tag>
<!--- 可省略,只是說明一下此tag -->
<description>base simple tag</description>
<!--- 設定的tag名稱 -->
<name>simple</name>
<!--- 對應的java程式 -->
<tag-class>com.web.tag</tag-class>
<!--- 設定此標籤是否可以有主體-->
<body-context>empty</body-context>
4.佈署
產生的SimpleTagTest的classes會放在web-inf/classes目錄下
TLD則放在web-inf目錄
5.在JSP加入標籤
<%@ taglib prefi"mySimple" uri="myTag" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=BIG5">
<title>Insert title here</title>
</head>
<body>
<mySimple:simple/>
生命週期簡單整理順序為
Simple Tag api
透過繼承SimpleTagSupport去實作SimpleTag interface
SimpleTagSupport提供常用的幾種方法
除了doTag()外,其他都可以直接拿來用
和tag file一樣,會遇到需要新增屬性和body的狀況
新增屬性
若需要新增屬性,同樣也是在TLD宣告
差別只是在於java裡面也要新增set的屬性
JSP
<body>
<mySimple:simple songList="${songs}" >
<tr>
<td>${song.name}</td>
</tr>
</mySimple:simple>
</body>
SimpleTagTest.java
public class SimpleTagTest extends SimpleTagSupport{
private List songList;
public void setSongList(List songList) {
this.songList = songList;
}
@Override
public void doTag() throws JspException, IOException {
Iterator i = songList.iterator();
while(i.hasNext())
{
Song song = (Song) i.next();
getJspContext().setAttribute("song", song);
//因為標籤有含主體,這段表示處理body,並將它輸出到response
//null表示輸出送去response
getJspBody().invoke(null);
}
//getJspContext().getOut().print("This is first simple tag");
}
TLD
和一般新增屬性的方法相同
<!--- 若要設定此tag可接受屬性,則需要此內容-->
<attribute>
<!---若required設為true,則代表此tag必須要有屬性才能使用-->
<name>songList</name>
<required>true</required>
<!---設定此tag是否只能接受字串-->
<rtexpevalue>true</rtexpevalue>
</attribute>
Body
剛剛的例子其實就是有含body的範例了
simple tag也可有body,設定TLD和之前的相同
但差別在於java的部分,doTag()要調整
SimpleTagTest.java
//表示處理body,並將它輸出到response,null表示輸出送去response
getJspBody().invoke(null);
TLD也可以設定body-context(和前幾天整理的相同)
<body-content>scriptless</body-content>
此外body也可以是個collection
只要在doTag()裡將他取出來就可以了
拿剛剛的例子
因為在doTag裡面,把songList這個list使用Iterator取出並set在song這個屬性
之後JSP會將songList裡面的每一筆song的name顯示出來
SimpleTagTest.java
@Override
public void doTag() throws JspException, IOException {
//使用Iterator將值取出
Iterator i = songList.iterator();
while(i.hasNext())
{
Song song = (Song) i.next();
//設定屬性為song
getJspContext().setAttribute("song", song);
getJspBody().invoke(null);
}
JspFragment
剛剛使用到的getJspContext以及invoke
都是JspFragment裡提供的方法
JspFragment是代表JSP程式碼的物件
目的就是為了被呼叫
簡單說就是將body的內容封裝在JspFragment物件
再透過SimpleTagSupport的setJspBody()方法傳入給標籤處理器
所以JspFragment有以下特點需要注意:
專門處理tag自己本身的exception
若在doTag裡面發生exception,但又不想影響呼叫tag前頁面的結果
就可以使用SkipPageException去控制
SimpleTagTest.java
public void doTag() throws JspException, IOException {
boolean test = ture;
//因為寫在SkipPageException之前,傳段還是會被印出
getJspContext().getOut().print("This is first simple tag");
if(test)
{
throw new SkipPageException();
}
}
JSP
<%@ taglib prefi"mySimple" uri="myTag" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=BIG5">
<title>Insert title here</title>
</head>
<body>
<mySimple:simple/> <!-- 呼叫到此tag會先印出This is first simple tag,接下來才會丟exception -->
若tag是被include的狀況下,只會影響tag自己本身
但原先的頁面還是會繼續執行
假設有一個A.jsp,include了tag
現在tag裡面有exception,使用SkipPageException的結果
A.jsp裡面的內容還是會被顯示出來(只影響有exception的tag)
這一章其實有點複雜
個人覺得看程式碼其實比較好理解
若有時間看看能不能補充個練習上來