iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 26
0

前言

今天來整理一下simple tag這個自訂標籤處理器


什麼是simple tag

tag file提供了嵌入工作的一種方式,全由JSP去完成
但在某些時候,需求無法完全依賴JSP去處理
還是需要使用java去做一些較複雜的處理時
JSP 2.0提供了一個叫做simple tag的自訂標籤處理器
如名稱一樣,透過簡單的宣告去呼叫java程式
在java去override我們要的邏輯

製作simple tag 處理器

步驟如下:

  • 1.撰寫SimpleTagSupport
    SimpleTagTest.java
package com.web.tag;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTagTest extends SimpleTagSupport{
}
  • 2.override doTag()
    這裡面包含要實作這個標籤的部分
    都會在這裡處理
	 @Override
	    public void doTag() throws JspException, IOException {
	        getJspContext().getOut().print("This is first simple tag");
	    }
  • 3.建立TLD
    這邊和之前TLD的操作一樣
    <!--- 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 生命週期

生命週期簡單整理順序為

  • 1.載入simpleTag類別,建立instance(tag 的clasee 為無參數的Constructor)
  • 2.呼叫setJspContext(JspContext)去設定PageContext(為JspContext的 subclass)
  • 3.如果此標籤為巢狀(即被包在另一個標籤內),則呼叫setParent(JspTag)
  • 4.若設定標籤有屬性,則呼叫設定屬性的方法(使用javaBean命名方式)
  • 5.假如標籤有主體,呼叫setJspBody(JspFragment)
  • 6.呼叫doTag(),把標籤處理的邏輯寫入

Simple Tag api
透過繼承SimpleTagSupport去實作SimpleTag interface
SimpleTagSupport提供常用的幾種方法
除了doTag()外,其他都可以直接拿來用

SimpleTagSupport API

simple tag的屬性及body

和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有以下特點需要注意:

  • 1.不可以包含scripting(Scriptlet,宣告,以及scripting運算式)
  • 2.可以透過getJspContext()取得物件的屬性,也可以將其屬性交給其他物件
  • 3.若要將body內容回傳給response,則使用 getJspBody().invoke(null)
    傳入null,若要存取實際的內容,可以使用writer的方法,處理body的內容

SkipPageException

專門處理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)


小結

這一章其實有點複雜
個人覺得看程式碼其實比較好理解
若有時間看看能不能補充個練習上來


上一篇
[Day 25] 自訂標籤 - Tag File
下一篇
[Day 27] 自訂標籤 - classic Tag
系列文
30 days JSP & Servlet學習紀錄 30

尚未有邦友留言

立即登入留言