今天要實現的功能是useBean標簽。下表是它的一些屬性和用途。(我只選了個比較重要的屬性,并沒有實現所有屬性)
屬性 | 用途 |
id |
給將要應用bean的變量一個名字,如果發現有相同id和scope的bean對象,則應用此對象而不會產生一個新的例示。 |
class |
指明了bean的整個包名。 |
scope |
表
明了此bean的作用范圍,共有四個值:page, request, session, 和
application,缺省的是page屬性,表明此bean只能應用于當前頁(保存在當前頁的PageContext
中);request屬性表明此bean只能應用于當前的用戶請求中(保存在ServletRequest對象中);session屬性表明此bean能
應用于當前HttpSession生命周期內的所有頁面;application屬性值則表明此bean能應用于共享ServletContext的所有
頁面。需要注意的是,當沒有具有相同的id和scope對象時,一個jsp:useBean
實體只能作用于一個新的例示中,反之,則作用于以前的對象,這時,在jsp:useBean標簽之間的任何jsp:setParameter和其它實體都
將被忽略。 |
type |
說明將要索引對象的變量類型,它必須與類名及父類名相匹配。記住,這個變量的名字是由id屬性值代替的。 |
beanName |
給定此bean的名字,可以將其提供給bean的例示方法,只提供beanName和type而忽略class屬性的情況是允許的。 |
下面是標簽處理方法類:UseBean.java:
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.lang.reflect.*;
//
public class UseBean extends TagSupport{ //繼承自TagSupport類
private String scope;
private String type;
public UseBean(){super();}
/**
*設置屬性存取方法,這個方法由容器自動調用。setId()和getId()由系統自動實現
*/
public void setScope(String s) {
this.scope = s;
}
public String getScope(){return this.scope;}
public void setType(String type){
this.type=type;
}
public String getType(){return this.type;}
/**
*覆蓋doStartTag方法
*/
public int doStartTag() throws JspTagException
{
Object o = null;
// find the bean in the specified scope
if (scope.equals("page")) {
o = pageContext.getAttribute(getId(),PageContext.PAGE_SCOPE);
} else if (scope.equals("request")) {
o = pageContext.getAttribute(getId(), PageContext.REQUEST_SCOPE);
} else if (scope.equals("session")) {
o = pageContext.getAttribute(getId(), PageContext.SESSION_SCOPE);
} else if (scope.equals("application")) {
o = pageContext.getAttribute(getId(), PageContext.APPLICATION_SCOPE);
}
if(o==null)
{
System.out.println("o is null!");
try{
Class u=Class.forName(type);
o=u.newInstance();//無參構造方法
System.out.println("create success!");
}
catch(Exception e){
throw new JspTagException("error to created a "+getId()+" object!");
}
}
pageContext.setAttribute(getId(), o); //保存實例對象到上下文對象中
return EVAL_BODY_INCLUDE; //返回類型
}
}
現
在我們已經把對象實例放到pageContext里了,是不是這樣就可以在JSP頁面中直接引用了?當然不是了,直接將JAVA對象放進
pageContext中與在腳本中直接引用是不同的。差別在于JSP容器要負責取得這個對象,以腳本變量的形式提供給頁面。即JSP容器負責來維護腳本
變量與pageContext中相應對象的狀態。有兩種方法可以為自定義標簽來聲明腳本變量。
一種是聲明variable,一種是通過TagExtraInfo類聲明變量。前者是JDK1.2后的方法,優點是比較方便。后者因為要再寫一個類文件,所以顯得麻煩些,但更靈活,出于兼容性與功能上的考慮,建議還是采用后者。(關于此類的詳細說明,請參考PPT文檔)
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class UseBeanTag extends TagExtraInfo {
public VariableInfo[] getVariableInfo(TagData data) {
return new VariableInfo[] {
new VariableInfo(
data.getId(),
data.getAttributeString("type"),
true,
VariableInfo.AT_BEGIN)
};
}
}
現在,定義一個useBean標簽的工作已進行大半,下面該定義標簽庫描述(TLD)文件了,該文件是一個XML文檔,主要定義標簽的屬性、處理類和擴展信息類的聲明。主要聲明部分如下:(tag.tld)
……………………(省去標頭部分)
<!-- useBEAN 標簽-->
<tag>
<name>useBEAN</name>
<!—聲明標簽處理類-->
<tag-class>cn.dever.tag.UseBean</tag-class>
<!—聲明標簽擴展信息類-->
<tei-class>cn.dever.taginfo.UseBeanTag</tei-class>
<!—主體內容類型-->
<body-content>jsp</body-content>
<!—屬性設置-->
<attribute>
<name>scope</name>
<!—是否必選-->
<required>true</required>
<!—是否可以使用JSP表達式-->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>id</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>type</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
其實這個標簽庫描述文件應該是最先建立的,因為我們主要是為了說明實現的方法,所以標簽描述放在后邊了。接下就是將剛才做的這些東西部署到我們的應用中去。在目標JSP頁面中引用一下就OK了。
<%@ taglib uri="/WEB-INF/tag.tld" prefix="dever" %>
<dever:useBEAN id="test" type="cn.dever.common.User" scope="page" />
OK,到此為止