[Day 26] 自订标签 – Simple tag

前言

今天来整理一下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的操作一样
     
    myTag
    
      
     
    base simple tag
     
    simple
     
    com.web.tag
     
    empty
  • 4.布署
    产生的SimpleTagTest的classes会放在web-inf/classes目录下
    TLD则放在web-inf目录

  • 5.在JSP加入标签

<%@ taglib prefi"mySimple" uri="myTag" %>



Insert title here



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



 
  ${song.name}
 
 

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
和一般新增属性的方法相同

  
    
         
    	songList
    	true
         
    	true
    

Body
刚刚的例子其实就是有含body的范例了
simple tag也可有body,设定TLD和之前的相同
但差别在于java的部分,doTag()要调整

SimpleTagTest.java

//表示处理body,并将它输出到response,null表示输出送去response
getJspBody().invoke(null); 

TLD也可以设定body-context(和前几天整理的相同)

scriptless

此外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" %>



Insert title here


 

若tag是被include的状况下,只会影响tag自己本身
但原先的页面还是会继续执行

假设有一个A.jsp,include了tag
现在tag里面有exception,使用SkipPageException的结果
A.jsp里面的内容还是会被显示出来(只影响有exception的tag)


小结

这一章其实有点复杂
个人觉得看代码其实比较好理解
若有时间看看能不能补充个练习上来