iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 27
0
自我挑戰組

30 days JSP & Servlet學習紀錄 系列 第 27

[Day 27] 自訂標籤 - classic Tag

前言

今天來看到classic tag
這部分較複雜一點點


Classic Tag簡介

最早JSP所提供的自訂標標籤處理器
在JSP 2.0之後雖然simple tag結合JSTL和tag file已經可以處理大部分的事了
但這塊還是可以稍微了解一下
且若要考認證考試還是會出個幾題

Classic Tag架構

有別於simple tag的doTag
classic主要分成兩個部分
doStartTag()和doEndTag()
在JSP和TLD和simplet tag是相同的(也就是說TLD也可以切換到呼叫simple tag)
主要差在java程式,上述的兩個方法已以及回傳的參數意義
還有IOException要另外處理的部分

ClassiclTag.java

package com.web.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;
public class ClassiclTag extends TagSupport{
	JspWriter output;
	// Classic並沒有宣告IOException,所以要在程式裡面自己try catch
	public int doStartTag() throws JspException{
		//從TagSupport繼承到pageContext(類似simple tag的getJspContext())
		output = pageContext.getOut();
		try{
			output.print("doStartTag...");
		}catch(IOException ex)
		{
			throw new JspException("IOException is "+ex.toString());
		}
		//這個參數表示就算有body,也直接跳到doEndTag方法
        //若要執行body(具有主體時),則回傳EVAL_BODY_INCLUDE
		return SKIP_BODY;
		
	}
	public int doEndTag()throws JspException{
		try{
			output.print("doEndTag...");
		}catch(IOException ex)
		{
			throw new JspException("IOException is "+ex.toString());
		}
		//繼續執行剩下的部分
		//和它相反的為SKIP_PAGE,類似simple的SkipPageException
		return EVAL_PAGE;
	}
}

Classic Tag生命週期

因為Classic有doStartTag和doEndTag
不像simple tag有dotag()一次做完
所以classic提供了doAfterBody()來處理body的部分

順序如下:

  • 1.載入Classic類別,建立instance(tag 的clasee 為無參數的Constructor)
  • 2.呼叫setPageContext(PageContext)去設定PageContext
  • 3.如果此標籤為巢狀(即被包在另一個標籤內),則呼叫setParent(Tag)
  • 4.若設定標籤有屬性,則呼叫設定屬性的方法(使用javaBean命名方式)
  • 5.呼叫doStartTag(),只會被呼叫一次
    若tag設定body不為空,且body也有內容,則回傳EVAL_BODY_INCLUDE
    若為空則回傳SKIP_BODY
  • 6.若執行完body則呼叫doAfterBody(),在執行body之後呼叫,可不只被呼叫一次
  • 7.呼叫doEndTag(),只會被呼叫一次

整個流程及回傳的return值直接用下圖表示
其中所有的回傳值只有EVAL_BODY_AGAIN是由IterationTag所提供
http://ithelp.ithome.com.tw/upload/images/20161227/20103425x83xsbeFVm.jpg

使用IterationTag處理body

剛剛有提到的doAfterBody()就是由IterationTag提供
IterationTag API

若在doAfterBody()裡面set屬性
因為doAfterBody()是在主體被執行一次才會執行
所以在doStartTag()時也需要set一次相同的屬性,否則在doStartTag()時會找不到此屬性
畫面上會多一個空值

另外Classic Tag是可以重複被Container使用
這點和Simple tag不相同,因此在參數的設定上也需要注意是否要重新設定其值

存取Body

Simple tag可以利用writer的方法,處理body的內容
但classic tag
則需要BodyTag來幫忙
BodyTag繼承了BodyTagSupport
可以使用setBodyContext()和doInitBody()
來呼叫處理器的實際主內容去做控制

因此整個流程就變成,多了兩個方法和一個回傳值
http://ithelp.ithome.com.tw/upload/images/20161227/201034251rA6OTk548.jpg

巢狀標籤

這裡分成兩個部分討論(此部分simple 和classic都相同)

  • 1.父tag要取得子tag的資訊 => 新增屬性
  • 2.子tag要取得父tag的資訊 => getParent()

1.父tag要取得子tag的資訊
因為沒有提供往下找的方法
所以需要在子tag裡面去新增屬性,將子tag的屬性傳給父tag

ParentTag.java

package com.web.tag;
import java.util.ArrayList;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class ParentTag extends TagSupport{
	
	private ArrayList arrayName;
	
	//新增一個方法供子tag呼叫
	public void addItem(String s)
	{
		arrayName.add(s);
	}
	
	public int doStartTag() throws JspException{
		return EVAL_BODY_INCLUDE;
	}
	public int doEndTag()throws JspException{
		return EVAL_PAGE;
	}
}

SubTag.java

package com.web.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class SubTag extends TagSupport{
	private String str;
	
	public void setStr(String str) {
		this.str = str;
	}
	public int doStartTag() throws JspException{
		return EVAL_BODY_INCLUDE;
	}
	public int doEndTag()throws JspException{
		//呼叫父tag,使用addItem將子tag的值傳入
		ParentTag parTag = (ParentTag) getParent();
		parTag.addItem(str);
		return EVAL_PAGE;
	}
}

2.子tag要取得父tag的資訊
不管是simple和tag都具有getParent()的方法
只是回傳的型別不相同
因此可以在子tag裡面使用getParent()得到父tag的物件
但要記得做轉型

此外由於simple回傳是JspTag
包含了tag的interface
所以getParent()

classic tag只能存取classic tag的父標籤
但simple tag除了存取自己類型的父tag之外,也可存取classic tag


小結

其實今天還有漏掉一個主題
DynamicAttributes
不是因為偷懶,是因為還需要花一些時間研究一下
不是很了解書中講解的範例
明天會先繼續後面的進度
再找時間練習這個部分,之後再補充上來


上一篇
[Day 26] 自訂標籤 - Simple tag
下一篇
[Day 28 ] web部署
系列文
30 days JSP & Servlet學習紀錄 30

尚未有邦友留言

立即登入留言