<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    konhon

    忘掉過去,展望未來。找回自我,超越自我。
    逃避不一定躲的過, 面對不一定最難過, 孤單不一定不快樂, 得到不一定能長久, 失去不一定不再擁有, 可能因為某個理由而傷心難過, 但我卻能找個理由讓自己快樂.

    Google

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      203 Posts :: 0 Stories :: 61 Comments :: 0 Trackbacks

    #

    標準的JSP 標記可以調用JavaBeans組件或者執行客戶的請求,這大大降低了JSP開發的復雜度和維護量。JSP技術也允許你自定義taglib,其實換句話說,taglib可以看成是對JSP標記的一種擴展,正如xml是對html的一種擴展一樣。taglib通常定義在tag標簽庫中,這種標簽庫存放著你自己定義的tag標簽。簡而言之,如果使用taglib,那么你可以設計自己的JSP標記!

    一般來說,自定義tag標簽主要用于操作隱藏對象、處理html提交表單、訪問數據庫或其它企業級的服務,諸如郵件和目錄操作等等。自定義tag標簽的使用者一般都是那些對java編程語言非常精通,而且對數據訪問和企業級服務訪問都非常熟悉的程序員,對于HTML設計者來說,使得他可以不去關注那些較復雜的商業邏輯,而將精力放在網頁設計上。同時,它也將庫開發者和庫使用者進行合理分工,自定義tag標簽將那些重復工作進行封裝,從而大大提高了生產力,而且可以使得tag庫可用于不同的項目中,完美地體現了軟件復用的思想。

    在這篇文章中,我們主要討論:

    · 什么是自定義tag標簽?

    · 怎么使用tag標簽?

    o 聲明要使用的tag庫

    o 找到與之對應的tag處理類

    o tag標簽的類型

    · 自定義tag標簽

    o tag處理類

    o tag庫描述

    o tag標簽示例

    o 帶屬性的tag

    o 帶body的tag

    o 定義了腳本變量的tag

    o 具有協作關系的tag

    · 自定義tag標簽

    o 一個迭代tag的例子

    o 一個模板tag庫

    o tag處理類到底是怎樣被調用的?


    什么是自定義的tag?

    一個自定義的tag標簽是用戶定義的一種JSP標記。當一個含有自定義的tag標簽的JSP頁面被jsp引擎編譯成servlet時,tag標簽被轉化成了對一個稱為tag處理類的對象進行的操作。于是當JSP頁面被jsp引擎轉化為servlet后,實際上tag標簽被轉化成為了對tag處理類的操作。

    自定義tag標簽有很多特色,諸如:

    · 可以在JSP頁面中自定義tag標簽的屬性

    · 訪問JSP頁面中的所有對象

    · 可以動態地修改頁面輸出

    · 彼此這間可以相互通信。你可以先創建一個JavaBeans組件,然后在一個tag中調用此JavaBeans組件,同時可以在另一個tag中調用它。

    · tag允許相互嵌套,可以在一個JSP頁面中完成一些復雜的交互。


    使用tag標簽


    本節主要描述怎樣在JSP頁面中使用tag標簽,以及tag標簽的不同類型。

    要使用tag標簽,JSP程序員必須做2件事:

    · 聲明此tag標簽的tag庫

    · 實現此tag標簽

    聲明tag標簽所在的tag庫

    如果要使用tag標簽,則應用JSP的taglib指示符來指定其tag庫(注意:taglib要在在使用此tag標簽之前聲明)

    <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>

    uri屬性定義了唯一的標簽庫描述(以下簡稱TLD),它可以是直接是tld文件名或一個獨一無二的名字。prefix是用來區別其它TLD中和本TLD中有重名的tag的一種手段。

    TLD必須以.tld作為擴展名,并且存放在當前應用的WEB-INF目錄或其子目錄下。你可以通過它的文件名直接引用它,也可以通過別的方式間接地引用它。

    以下taglib指示符直接引用一個TLD:

    <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>

    以下的taglib指示符通過一個邏輯名稱間接地引用一個TLD:

    <%@ taglib uri=”/tutorial-template” prefix=”tt” %>

    如果是間接引用TLD的話,那你必須還要在web.xml中定義此邏輯名稱與tld文件之間的映射,具體做法是在web.xml中加入一個名為taglib的元素:

    <taglib>

    <taglib-uri>/tutorial-template</taglib-uri>

    <taglib-location>

    /WEB-INF/tutorial-template.tld

    </taglib-location>

    </taglib>


    實現此tag標簽


    為了實現tag標簽,你有2種方法來存放tag處理類。一、讓tag處理類以.class的方式存放于當前應用的WEB-INF/class子目錄下,二、如果tag處理類是以JAR包的形式存在的話,那可以放在當前應用的WEB-INF/lib目錄下,如果tag處理類要在多個應用中共享,那么它就應放在jsp服務器上的common/lib目錄下,對于tomcat來說,就是tomcat/common/lib目錄下。


    tag標簽類型


    自定義的tag標簽遵循XML語法。它有一個開始標記和一個結束標記,有的還有body(即文本節點):

    <tt:tag>

    body

    </tt:tag>


    一個不帶body的tag標簽如下:

    <tt:tag />


    簡單的tag標簽

    一個沒有body和屬性的tag標簽如下:

    <tt:simple />


    帶屬性的tag標簽


    自定義標簽可以有自己的屬性。屬性一般在開始標記中定義,語法為 attr=”value”。屬性的作用相當于自定義標簽的一個參數,它影響著tag處理類的行為。你可以在TLD中詳細定義它。

    你可以用一個String常量給一個屬性賦值,也可以通過表達式給它賦值,如<%= ...%>。以struts為例,它的logic:present標簽就是用的String常量來給屬性賦值:

    <loglic:present parameter = “Clear”>

    而另一個標簽logic:iterate是用表達式來給屬性賦值:

    <logci:iterate collection=”<%= bookDB.getBooks() %>”

    id=”book” type=”database.BookDetails”>


    帶body的tag標簽

    一個自定義標簽可以包含其它自定義標簽、腳本變量、HTML標記或其它內容。

    在下述例子中,此JSP頁面使用了struts的logic:present標簽,如果些標簽定義了parameter=”Clear”的屬性,則將清除購物車的內容,然后打印出一條信息:

    <logic:present parameter=”Clear”>

    <% cart.clear(); %>

    <font color=”#ff0000” size=”+2”><strong>

    你選擇了清除購物車!

    </strong></font>

    </logic:present>


    到底是用屬性還是用body來傳遞信息?

    如上所述,我們既可以通過屬性,也可以通過body來傳遞信息。但一般來說,比較簡單的類型,如字符串或簡單表達式最好采用屬性來傳遞信息。


    定義腳本變量的tag標簽

    所謂腳本變量,是指JSP中可以調用的變量或對象。它可由tag標簽產生。以下示例闡述了一個tag標簽定義了一個名為tx的由JNDI所定義的事務處理對象。腳本變量可以是ejb對象、事務、數據庫連接等等:

    <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />

    <% tx.begin(); %>

    ...


    具有協作關系的tag標簽

    自定義tag標簽之間可以通過共享對象來實現協作。在下述例子中,標簽tag1創建了一個名為obj1的對象,在標簽tag2仍可以重復使用obj。

    <tt:tag1 attr1=”obj1” value1=”value” />

    <tt:tag2 attr1=”obj1” />

    在以下這個例子當中,如果外層的tag標簽創建了一個對象,那么其內層的所有tag標簽都可以使用這個對象。由于這樣產生的對象沒有一個指定的名字,那么就可以將少重名的沖突。這個例子闡述了一系列協作的嵌套對象。

    <tt:outerTag>

    <tt:innerTag />

    </tt:outerTag>


    Tag處理類


    Tag處理類必須實現Tag接口或BodyTag接口,不過現在一般都流行從TagSupport或BodyTagSupport類中繼承,這些類或接口都可以在javax.servlet.jsp.tagext包中找到。

    當JSP引擎看到自己的JSP頁面中包含有tag標簽時,它會調用doStartTag方法來處理tag標簽的開頭,調用doEndTag方法來處理tag標簽的結束。

    下表說明不同類型的tag所需要不同的處理過程:

    Tag處理類的方法

    Tag標簽類型
    所調用的方法

    基本標簽
    doStartTag, doEndTag, release

    帶屬性的標簽
    doStartTag, doEndTag, set/getAttribute1...N, release

    帶內容的標簽
    doStartTag, doEndTag, release

    帶內容的標簽,且內容重復循環
    doStartTag, doAfterBody, doEndTag, release

    帶內容的標簽,且內容與JSP交互
    doStartTag, doEndTag, release, doInitBody, doAfterBody, release

    一個tag處理類可以通過javax.servlet.jsp.PageContext來與JSP交互,通過javax.servlet.jsp.PageContext類,tag處理類可以訪問JSP中的request、session和application對像。

    如果tag標簽是互相嵌套的,那內層的tag處理類可以通過它的parent屬性來訪問上層的tag處理類。

    一般情況都將所有的tag處理類打成了JAR的包,以便于發布。


    Tag庫描述(簡稱TLD)


    Tag庫是用xml語言描述的,TLD包括了tag庫中所有tag標簽的描述,它一般用來被jsp服務器用來校驗tag的語法正確性,或者被jsp開發者用來開發新的標簽。

    TLD的文件擴展名必須為.tld,而且必須放在當前WEB應用的WEB-INF目錄或其子目錄中。

    一個TLD的內容的開頭必須遵守標準的XML開頭,用于描述DTD和xml的版本,例如:

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "TLD必須以<taglib>來作為它的根元素,<taglib>的子元素如下表:


    <taglib>的子元素

    Element
    Description

    tlib-version
    Tag庫的版本

    jsp-version
    Tag庫所需要的jsp的版本

    short-name
    助記符,tag的一個別名(可選)

    uri
    用于確定一個唯一的tag庫

    display-name
    被可視化工具(諸如Jbuilder)用來顯示的名稱(可選)

    small-icon
    被可視化工具(諸如Jbuilder)用來顯示的小圖標(可選)

    large-icon
    被可視化工具(諸如Jbuilder)用來顯示的大圖標(可選)

    description
    對tag庫的描述(可選)

    listener
    參見下面listener元素

    tag
    參見下面tag 元素

    Listener元素

    一個tag庫可能定義一些類做為它的事件偵聽類,這些類在TLD中被稱為listener 元素,jsp服務器將會實例化這些偵聽類,并且注冊它們。Listener元素中有一個叫listener-class的子元素,這個元素的值必須是該偵聽類的完整類名。

    Tag元素

    每個tag元素在tag庫中都要指出它的名字、類名、腳本變量、tag的屬性。其中腳本變量的值可以直接在TLD中定義或通過tag附加信息的類來取得。每個屬性描述了這個屬性是否可以省略,它的值是否可以通過<%= …%>這樣的JSP語法來獲得,以及屬性的類型。

    每一個tag在TLD中對應一個tag元素,下表是tag元素的子元素:

    Tag元素的子元素

    元素名稱
    描述

    name
    獨一無二的元素名

    tag-class
    Tag標簽對應的tag處理類

    tei-class
    javax.servlet.jsp.tagext.TagExtraInfo的子類,用于表達腳本變量(可選)

    body-content
    Tag標簽body的類型

    display-name
    被可視化工具(諸如Jbuilder)用來顯示的名稱(可選)

    small-icon
    被可視化工具(諸如Jbuilder)用來顯示的小圖標(可選)

    large-icon
    被可視化工具(諸如Jbuilder)用來顯示的大圖標(可選)

    description
    此tag標簽的描述

    variable
    提供腳本變量的信息(同tei-class)(可選)

    attribute
    Tag標簽的屬性名

    以下章節介紹對于不同類型的tag,如何具體地實現它們。


    簡單的tag


    tag處理類

    簡單的tag處理類必須實現Tag接口的doStartTag和doEndTag方法。當jsp引擎碰到tag標簽的開頭時,doStartTag被調用,因為簡單的tag沒有body,所以此方法將返回 SKIP_BODY。當jsp引擎碰到tag標簽的結尾時,doEndTag被調用,如果余下的頁面還要被計算,那它將返回EVAL_PAGE,否則將會返回SKIP_PAGE。

    以下是例子:對于標簽 <tt:simple /> ,它的tag處理類實現如下:


    public SimpleTag extends TagSupport

    {

    public int doStartTag() throws JspException

    {

    try{

    pageContext.getOut().print(“Hello.”);

    }catch(Exception e){

    throw new JspTagException(“SimpleTag: “ + e.getMessage());

    }

    return SKIP_BODY;

    }

    public int doEndTag()

    {

    return EVAL_PAGE;

    }

    }


    注意:如果tag標簽沒有內容的話,那必須定義body-content元素為空,例如

    <body-content>empty</body-content>


    帶屬性的tag標簽


    tag處理類

    對于tag標簽的每個屬性,你必須依照JavaBeans規范來定義其屬性,以及get和set方法。以struts的logic:present 標簽為例,

    <logic:present parameter=”Clear”>

    與此相應,此tag處理類應有如下方法和定義:


    protected String parameter = null;

    public String getParameter()

    {

    return this.parameter;

    }

    public void setParameter(String parameter)

    {

    this.parameter = parameter;

    }


    注意:如果你的屬性名為id,而且你的tag處理類是從TagSupport類繼承的,那你就不需要定義它的屬性和set和get方法,因為他們早已在TagSupport被定義過了。

    Attribute元素

    對于tag標簽的每個屬性,你必須定義它是否必須的,它的值是否可以用諸如<%= …%>的表達式來獲得,以及它的類型(可選),如果不指定它的類型,那就默認為是java.lang.String類型。如果rtexprvalue元素被定義為true或yes,那么在type元素中就定義了attribute的返回類型。

    <attribute>

    <name>attr1</name>

    <required>true|false|yes|no</required>

    <rtexprvalue>true|false|yes|no</rtexprvalue>

    <type>attribute的返回類型(只用當rtexprvalue為真是才有效)</type>

    </attribute>

    如果tag的某個屬性不是必須的,那tag處理類會自動提供一個缺省值。

    例如,在logic:present這個tag標簽中定義了一個屬性叫parameter,但它不是必須的,而且它可以被諸如<%= …%>的表達式來賦值。

    <tag>

    <name>present</name>

    <tag-class>org.apache.struts.taglib.logic.PresentTag</tag-class>

    <body-content>JSP</body-content>

    <attribute>

    <name>parameter</name>

    <required>false</required>

    <rtexprvalue>true</rtexprvalue>

    </attribute>

    </tag>


    屬性元素的校驗


    有關于tag標簽的有效值可以從tag庫的說明文檔中獲得,當JSP頁面被編譯時,jsp引擎會強制性地參照TLD中定義的規則進行檢查。

    還有一個方法也可以進行屬性元素的校驗,就是先繼承類TagExtraInfo,然后調用它的isValid方法。這個類同時也起到提供tag中定義的腳本變量信息的作用。

    IsValid方法通過TagData對象來傳遞屬性信息,它包括著tag的所有的屬性名-值的信息。由于校驗發生在運行時刻,因此這個屬性的值將被賦值為TagData.REQUEST_TIME_VALUE。

    例如tag標簽<tt:twa attr1=”value1” />在TLD中定義如下:

    <attribute>

    <name>attr1</name>

    <required>true</required>

    <rtexprvalue>true</rtexprvalue>

    </attribute>


    這個定義說明了attr1能在運行期間被賦值。

    以下的isValid方法檢查attr1屬性的值是否屬于Boolean類型。注意由于attr1能在運行刻被賦值,那么isValid方法必須檢查tag用戶是否對此tag進行了運行時刻賦值。


    Public class TwaTEI extends TagExtraInfo

    {

    public boolean isValid(Tagdata data)

    {

    Object o = data.getAttribute(“attr1”);

    If(o != null && o != TagData.REQUEST_TIME_VALUE)

    {

    if( ( (String)o).toLowerCase().equals(“true”) || 

    ((String)o).toLowerCase().equals(“false”) )

    return true;

    else

    return false;

    }

    else

    return true;

    }

    }


    帶body的tag


    tag處理類


    如果tag標簽含有內容,那處理方式會略微有些不同,而且還要視tag處理類是否要與body交互的情況而定。如果要與body交互,那我們認為tag處理類要可能要對body進行操作。

    Tag處理類不與body交互

    如果tag處理類不與body交互,tag處理類應該實現Tag接口或從TagSupport中派生,如果body要被計算,那么doStartTag方法應返回 EVAL_BODY_INCLUDE,否則應返回SKIP_BODY。

    如果tag處理類要對body反復運算,則它應該實現IterationTag或從TagSupport中派生。如果tag處理類認為body還未計算完的話,那它的doStartTag方法和doAfterBody方法必須返回EVAL_BODY_AGAIN。

    Tag處理類與body交互

    如果tag處理類與body交互,那tag處理類應實現BodyTag接口或從BodyTagSupport中派生。這種tag處理類一般要實現doInitBody和doAfterBody方法。

    Body允許一些方法來讀寫它的內容。Tag處理類可以調用body內容的getString或getReader方法來從body中提取信息,也可用 writeOut(out) 方法來將body的內容寫入到out對象中。其中out對象通過tag處理類的getPreviousOut方法來獲得。

    如果body的內容需要被計算,那么doStartTag方法必須返回EVAL_BODY_BUFFERED,否則,它將返回 SKIP_BODY。

    doInitBody 方法

    此方法在body內容已經設好,但未被計算之前被調用。你可以根據不同的body內容來制定初始化策略。

    doAfterBody方法

    此方法在body內容已被計算后進行調用。

    和doStartTag方法一樣,doAfterBody方法返回一個指示符指示是否要繼續計算body,如果要繼續計算,則doAfterBody應返回EVAL_BODY_BUFFERED,否則,它應返回SKIP_BODY。

    release 方法

    tag處理類調用此方法將它的狀態重置為初始狀態,并釋放所有的私有資源。


    以下的例子讀取body的內容(其中含有一條sql語句),然后將它傳遞給一個對象,讓它進行查詢。由于此處body不須重新計算,所以doAfterBody會返回SKIP_BODY。


    Public class QueryTag extends BodyTagSupport

    {

    public int doAfterBody() throws JspTagException

    {

    BodyContent bc = getBodyContent();

    //將body的內容以字符串的格式提取出來

    String query = bc.getString();

    //清除body

    bc.clearBody();

    try{

    Statement stmt = connection.createStatement();

    Result result = stmt.executeQuery(query);

    }catch(SQLException e){

    throw new JspTagException(“queryTag: “ + e.getMessage() );

    return SKIP_BODY;

    }

    }


    body-content元素


    由于tag可能會有body,你必須用body-content元素來指定body內容的類型:

    <body-content>JSP|tagdependent</body-content>


    如果body的內容是定制的或內部的tag、腳本元素、或HTML廣本,則歸類為JSP類型。其他的類型,比如上面代碼所述的?D?D將sql statement類傳給 query tag的這種類型應該標為tagdependent。

    注意:實際上body-content的值并不影響tag處理類對body內容的處理,它僅僅是被tag編輯工具用來描述此body的內容。


    用tags定義腳本變量


    tag處理類


    tag處理類負責創建或設置頁面中定義的腳本變量,用pageContext.setAttribute(name,value,scope)或pageContext.setAttribute(name,value)方法來實現。一般來說,tag處理類通過腳本變量的名稱來獲取它,腳本變量的名稱一般可用get方法來獲得。

    如果腳本變量的值依賴于tag處理類中的上下文中某一對象,那它可用pageContext.getAttribute(name,scope)方法來找到那個對象。一般的處理過程是tag處理類先找到腳本變量,再對其進行處理,然后用pageContext.setAttribute(name,object)的方法來設置它的新值。

    對象的生存周期(scope)如下表:

    對象的生存周期表

    名字
    可訪問范圍
    生存周期

    page
    當前頁面
    一直有效,除非頁面向客戶提交響應或重定向到一個新頁面

    request
    當前頁面或當前頁面重定向到的頁面
    一直有效,除非頁面向客戶提交響應

    session
    當前頁面或在同一瀏覽器窗口中的頁面
    一直有效,除非關閉當前瀏覽器、超時、網絡故障

    application
    整個web應用程序的所有請求
    一直有效,除非發生網絡故障、服務器故障

    提供關于腳本變量的信息

    以下示例定義了一個名為“book”的腳本變量,用來訪問程序中關于書的信息:

    <bean:define id=”book” name=”bookDB” property=”bookDetails” type=”database.BookDetails” />

    <font color=”red” size=”+2” >

    <%= messages.getString(“CartRemoved”) %>

    <strong><jsp:getProperty name=”book” property=”title” /></strong>

    </font>

    當包含此tag的JSP頁面被編譯時,jsp引擎會自動生成關于此book的同步的代碼(同步可以避免幾個客戶同時訪問此book時造成的沖突),要生成同步代碼,jsp引擎需要知道此腳本變量的如下信息:

    · 腳本變量名稱

    · 腳本變量所屬的類

    · 此腳本變量是否引用了一個新的或已存在的對象

    · 此腳本變量的有效性

    有兩種辦法可以向jsp引擎提供關于腳本變量的信息:在TLD中定義variable子元素,或用tei-class子元素定義一個額外tag信息類。用variable最簡單,但可能降低了一些靈活性。

    Variable元素

    Variable元素有如下子元素:

    · name-given ?D?D 給出的名字,是一個常量

    · name-from-attribute?D?D 屬性名,在編譯時給出的屬性名

    name-given或name-from-attribute兩者必須選一,但以下子元素是可選的:

    · variable-class?D?D變量的類型,缺省為java.lang.String。

    · declare?D?D此腳本變量是否引用了一個新對象,缺省為True。

    · scope?D?D腳本變量的范圍,缺省為NESTED。下表描述了scope的幾種類型:

    腳本變量的有效范圍


    有效性
    方法

    NESTED
    在tag標簽的開始和結束之間
    如果tag處理類實現BodyTag接口,則在doInitBody和doAfterBody中調用,否則在doStartTag中調用

    AT_BEGIN
    從tag標簽的開始一直到頁面結束
    如果tag處理類實現BodyTag接口,則在doInitBody、doAfterBody和doEndTag中調用,否則在doStartTag和doEndTag中調用

    AT_END
    從tag標簽的結束一直到頁面結束
    在doEndTag中調用

    以struts為例,它的bean:define標簽的實現遵循JSP1.1規范,此規范要求使用額外tag信息類來定義腳本變量。Variable元素是JSP1.2規范中加入的。以bean:define標簽為例,你可以定義如下variable元素:

    <tag>

    <variable>

    <name-from-attribute>id</name-from-attribute>

    <variable-class>database.BookDetails</variable-class>

    <declare>true</declare>

    <scope>AT_BEGIN</scope>

    </variable>

    </tag>

    額外tag信息類

    如果要定義一個額外tag信息類,你要繼承javax.servlet.jsp.TagExtraInfo類。一個TagExtraInfo類必須實現getVariableInfo方法,此方法返回一個叫VariableInfo的數組類,它包括如下信息:

    · 變量名

    · 變量所屬類名

    · 此變量是否引用了一個新對象

    · 此變量的有效范圍

    jsp引擎將一個名為data的參數傳給getVariableInfo方法,data中包括tag標簽中的所有“屬性名?D?D屬性值”對。它可以用來向VariableInfo對象提供腳本變量的名字和類名。

    以struts為例,它在bean:define標簽中定義了一個名為DefineTei的額外tag信息類,用來向腳本變量提供信息。由于腳本變量的名稱(book)和類名(database.BookDetails)是通過tag標簽的屬性來傳遞的,它們一般定義在VariableInfo的構建代碼中,并且可用data.getAttributeString方法來得到這些信息。如果要允許book腳本變量能在從tag開始直到整個JSP頁面結束的范圍內都可用的話,那它的范圍應設為AT_BEGIN。如下所示:


    public class DefineTei extends TagExtraInfo

    {

    public VariableInfo[] getVariableInfo(TagData data)

    {

    String type = data.getAttributeString(“type”);

    If( type == null)

    type = “java.lang.Object”;

    return new VariableInfo[] {

    new VariableInfo(data.getAttributeString(“id”), 

    type,

    true,

    VariableInfo.AT_BEGIN)

    };

    }

    }


    注意:關于額外tag信息類的類名必須要在TLD中的tag標簽下的tei-class子元素中定義。因此,DefineTei的tei-class中的定義看起來如下:
    <tei-class>
    org.apache.struts.taglib.bean.DefineTagTei
    </tei-class>


    具有協作關系的tag


    tag通過共享對象來進行協作,JSP技術支持2種方式的對象共享。

    第一種方法是使用pageContext對象進行對象的共享(可支持JSP頁面和tag處理類之間的共享),如果在一個tag處理類中要調用由另一個tag處理類創建的對象,可調用pageContext.getAttribute(name, scope)方法。

    第二各方式的共享是對于tag之間有嵌套關系而言的,外層的tag所創建的對象對于內層的tag來說是可以共用的。這種形式的共享的好處是減少了可能存在的重名沖突。

    要訪問一個嵌套tag創建的對象,tag處理類必須先找到此嵌套tag對象,可用TagSupport的靜態方法 TagSupport.findAncestorWithClass(from, class)或TagSupport.getParent方法。前者在當不確定此tag是否為嵌套tag對象時使用。一旦它的父類被找到,它就能訪問其所有動態或靜態創建的對象。靜態創建的對象是父類的成員,而動態創建的對象可能是父類的私有對象。諸如此類的對象可以用tag處理類的setValue方法來保存,用getValue方法來獲得。

    下例闡述了以上兩種共享對象的方法。在這個例子當中,一個查詢tag檢查一個名為connection的屬性名是否在doStartTag中被設置。如果connection屬性被設置,tag處理類從pageContext中得到這個connection對象。否則,此tag處理類先找到它的父tag處理類,然后從它的父tag處理類中找到connection對象。


    public class QueryTag extends BodyTagSupport

    {

    private String connectionId;

    public int doStartTag() throws JspException

    {

    String cid = getConnection();

    if(cid != null)

    {

    //存在一個connection id,使用它。

    connection = (Connection) pageContext.getAttribute(cid);

    }

    else

    {

    ConnectionTag ancestorTag = (ConnectionTag)findAncestorWithClass(this, 

    ConnectionTag.class);

    if(ancestorTag == null)

    {

    throw new JspTagException(“一個沒有connection屬性的查詢標簽必須被一個connection標記嵌套。”);

    }

    connection = ancestorTag.getConnection();

    }

    }

     

    此查詢標簽在JSP頁面中的調用形式可以從以下2種定義中任選一種:


    <tt:connection id=”con01” ...> ... </tt:connection>

    <tt:query id=”balances” connection=”con01” >

    SELECT account, balance FROM acct_table

    where customer_num = <%= request.getCustno() %>

    </tt:query>


    <tt:connection ...>

    <x:query id=”balances”>

    SELECT account, balance FROM acct_table

    where customer_num = <%= request.getCustno() %>

    </x:query>

    </tt:connection>


    與此同時,在TLD中必須指定connection屬性為可選的,定義如下:

    <tag>

    ...

    <attribute>

    <name>connection</name>

    <required>false</required>

    </attribute>

    </tag>

     

    posted @ 2005-08-22 19:48 konhon 優華 閱讀(244) | 評論 (0)編輯 收藏

         摘要:   import java.text.*;import java.util.*;public class StringFormat {    private static SimpleDateFormat dateFormat = new&nb...  閱讀全文
    posted @ 2005-08-16 21:01 konhon 優華 閱讀(378) | 評論 (0)編輯 收藏

         摘要:     1.方法聲明時使用,放在范圍操作符(public等)之后,返回類型聲明(void等)之前.這時,線程獲得的是成員鎖,即一次只能有一個線程進入該方法,其他線程要想在此時調用該方法,只能排隊等候,當前線程(就是在synchronized方法內部的線程)執行完該方法后,別的線程才能進入.       例如:...  閱讀全文
    posted @ 2005-08-16 20:23 konhon 優華 閱讀(105124) | 評論 (32)編輯 收藏

    下午測試用jdbc連SQL Server時, 竟然出現如下錯誤:
    Invalid object name 'Materiel'. ...
    但Materiel表實際上是存在的, 在"查詢分析器"執行查詢都沒有錯.
    最後沒辦法只好將查詢語句改為: "select * from Stock_Demo.DBO.Materiel"
    才可以執行查詢, 百思不得其解, 到Google搜索了一下, 原來好多人碰到此問題.這不知道是是濁Microsoft SQLServer JDBC Drvier的Bug.

    posted @ 2005-08-15 03:02 konhon 優華 閱讀(282) | 評論 (0)編輯 收藏



      1、如何學習Spring?

      你可以通過下列途徑學習spring:

      (1) spring下載包中doc目錄下的MVC-step-by-step和sample目錄下的例子都是比較好的spring開發的例子。

      (2) AppFuse集成了目前最流行的幾個開源輕量級框架或者工具 Ant,XDoclet,Spring,Hibernate(iBATIS),JUnit,Cactus,StrutsTestCase,Canoo&#39;s WebTest,Struts Menu,Display Tag Library,OSCache,JSTL,Struts 。

      你可以通過AppFuse源代碼來學習spring。

    AppFuse網站:http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse

      (3)Spring 開發指南(夏昕)(http://www.xiaxin.net/Spring_Dev_Guide.rar)

      一本spring的入門書籍,里面介紹了反轉控制和依賴注射的概念,以及spring的bean管理,spring的MVC,spring和hibernte,iBatis的結合。

      (4) spring學習的中文論壇

      SpringFramework中文論壇(http://spring.jactiongroup.net)

      Java視線論壇(http://forum.javaeye.com)的spring欄目

      2、利用Spring框架編程,console打印出log4j:WARN Please initialize the log4j system properly?

      說明你的log4j.properties沒有配置。請把log4j.properties放到工程的classpath中,eclipse的classpath為bin目錄,由于編譯后src目錄下的文件會拷貝到bin目錄下,所以你可以把log4j.properties放到src目錄下。

      這里給出一個log4j.properties的例子:

    log4j.rootLogger=DEBUG,stdout
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d %5p (%F:%L) - %m%n

      3、出現 java.lang.NoClassDefFoundError?

      一般情況下是由于你沒有把必要的jar包放到lib中。

      比如你要采用spring和hibernate(帶事務支持的話),你除了spring.jar外還需要hibernat.jar、aopalliance.jar、cglig.jar、jakarta-commons下的幾個jar包。

    http://www.springframework.org/download.html下載spring開發包,提供兩種zip包
    spring-framework-1.1.3-with-dependencies.zip和spring-framework-1.1.3.zip,我建議你下載spring-framework-1.1.3-with-dependencies.zip。這個zip解壓縮后比后者多一個lib目錄,其中有hibernate、j2ee、dom4j、aopalliance、jakarta-commons等常用包。

      4、java.io.FileNotFoundException: Could not open class path resource [....hbm.xml],提示找不到xml文件?

      原因一般有兩個:

      (1)該xml文件沒有在classpath中。

      (2)applicationContext-hibernate.xml中的xml名字沒有帶包名。比如:

    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
    <property name="dataSource"><ref bean="dataSource"/></property>
    <property name="mappingResources">
     <list>
      <value>User.hbm.xml</value>
      錯,改為:
      <value>com/yz/spring/domain/User.hbm.xml</value>
     </list>
    </property>
    <property name="hibernateProperties">
    <props>
     <prop key="hibernate.dialect"> net.sf.hibernate.dialect.MySQLDialect </prop>
     <prop key="hibernate.show_sql">true</prop>
    </props>
    </property>
    </bean>

      5、org.springframework.beans.NotWritablePropertyException: Invalid property &#39;postDao&#39; of bean class?

      出現異常的原因是在application-xxx.xml中property name的錯誤。

      <property name="...."> 中name的名字是與bean的set方法相關的,而且要注意大小寫。

      比如

    public class PostManageImpl extends BaseManage implements PostManage {
     private PostDAO dao = null;
     public void setPostDAO(PostDAO postDAO){
      this.dao = postDAO;
     }
    }

      那么xml的定義應該是:

    <bean id="postManage" parent="txProxyTemplate">
    <property name="target">
     <bean class="com.yz.spring.service.implement.PostManageImpl">
      <property name="postDAO"><ref bean="postDAO"/></property> 對
      <property name="dao"><ref bean="postDAO"/></property> 錯
     </bean>
    </property>
    </bean>

      6、Spring中如何實現事務管理?

      首先,如果使用mysql,確定mysql為InnoDB類型。

      事務管理的控制應該放到商業邏輯層。你可以寫個處理商業邏輯的JavaBean,在該JavaBean中調用DAO,然后把該Bean的方法納入spring的事務管理。

      比如:xml文件定義如下:

    <bean id="txProxyTemplate" abstract="true"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager"><ref bean="transactionManager"/></property>
    <property name="transactionAttributes">
    <props>
    <prop key="save*">PROPAGATION_REQUIRED</prop>
    <prop key="remove*">PROPAGATION_REQUIRED</prop>
    <prop key="*">PROPAGATION_REQUIRED</prop>
    </props>
    </property>
    </bean>

    <bean id="userManage" parent="txProxyTemplate">
     <property name="target">
      <bean class="com.yz.spring.service.implement.UserManageImpl">
       <property name="userDAO"><ref bean="userDAO"/></property>
      </bean>
     </property>
    </bean>

      com.yz.spring.service.implement.UserManageImpl就是我們的實現商業邏輯的JavaBean。我們通過parent元素聲明其事務支持。

      7、如何管理Spring框架下更多的JavaBean?

      JavaBean越多,spring配置文件就越大,這樣不易維護。為了使配置清晰,我們可以將JavaBean分類管理,放在不同的配置文件中。 應用啟動時將所有的xml同時加載。

      比如:

      DAO層的JavaBean放到applicationContext-hibernate.xml中,商業邏輯層的JavaBean放到applicationContext-service.xml中。然后啟動類中調用以下代碼載入所有的ApplicationContext。

    String[] paths = {"com/yz/spring/dao/hibernate/applicationContext-hibernate.xml",
    "com/yz/spring/service/applicationContext-service.xml"};
    ctx = new ClassPathXmlApplicationContext(paths);

      8、web應用中如何加載ApplicationContext?

      可以通過定義web.xml,由web容器自動加載。

    <servlet>
    <servlet-name>context</servlet-name>
    <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext-hibernate.xml</param-value>
    <param-value>/WEB-INF/applicationContext-service.xml</param-value>
    </context-param>

      9、在spring中如何配置的log4j?

      在web.xml中加入以下代碼即可。

    <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/log4j.properties</param-value>
    </context-param>

      10、Spring框架入門的編程問題解決了,我該如何更深地領會Spring框架呢?

      這兩本書你該去看看。這兩本書是由Spring的作者Rod Johnson編寫的。

    Expert One on one J2EE Design and Development
    Expert One on one J2EE Development Without EJB

      你也該看看martinfowler的Inversion of Control Containers and the Dependency Injection pattern。

    http://www.martinfowler.com/articles/injection.html
     
      再好好研讀一下spring的文檔。

    http://www.jactiongroup.net/reference/html/index.html(中文版,未全部翻譯)

      還有就是多實踐吧。
    posted @ 2005-08-12 19:24 konhon 優華 閱讀(466) | 評論 (0)編輯 收藏

     

    Query上有list()與iterator()方法,兩者的差別在於list()方法在讀取資料時,並不會利用到快取,而是直接再向資料庫查詢,而iterator()則將讀取到的資料寫到快取,並於讀取時再次利用。

    來看看下面的程式:
    Session session = sessionFactory.openSession();
           
    Query query = session.createQuery("from User");
    List users = query.list();
    users = query.list();

    session.close();

    這個程式片段會使用兩次SQL來查詢資料庫:
    Hibernate: select user0_.id as id, user0_.name as name0_, user0_.age as age0_ from user user0_
    Hibernate: select user0_.id as id, user0_.name as name0_, user0_.age as age0_ from user user0_

    如果在Session關閉之前,要再將所有資料在取出,可以使用iterator()方法,例如:
    Session session = sessionFactory.openSession();

    Query query = session.createQuery("from User");
    Iterator users = query.iterate();
    users = query.iterate();

    session.close();

    這個程式片段會使用一次SQL向資料庫查詢,第二次則直接從快取中取得資料:
    Hibernate: select user0_.id as col_0_0_ from user user0_

    由於使用iterator()方法時會使用到Session level快取,所以在查詢大量資料時,會耗用大量的記憶體,必要時可以使用Session的evict()或clear()方法來清除快取。
    posted @ 2005-08-11 22:25 konhon 優華 閱讀(5493) | 評論 (2)編輯 收藏

    如果將要檔案寫入資料庫,您可以在欄位上使用BLOB或CLOB資料型態BLOB全名Binary Large Object,用於儲存大量的二進位資料,CLOB全名Character Large Object,用於儲存大量的文字資料。

    在JDBC中也提供了Blob與Clob兩個類別分別代表BLOB與CLOB資料,JDBC並沒有提供直接存入BLOB或CLOB的對應介面(像是setBlob()、setClob()等),但您可以使用PreparedStatement的setBinaryStream()、 setObject()、setAsciiStream()、setUnicodeStream()等方法來代替,例如我們可以如下取得一個檔案,並將之存入資料庫中:
    // 取得檔案
    File file = new File("./logo_phpbb.jpg");
    int length = (int) file.length();
    InputStream fin = new FileInputStream(file);
     
    // 填入資料庫
    PreparedStatement pstmt = conn.prepareStatement(
                           "INSERT INTO files VALUES(?, ?)");

    pstmt.setString(1, "米小國Logo");
    pstmt.setBinaryStream (2, fin, length);

    pstmt.executeUpdate();
    pstmt.clearParameters();
    pstmt.close();
    fin.close();
     

    如果要從資料庫中取得BLOB或CLOB資料,您可以如下進行:
    Blob blob = result.getBlob(2);  // 取得BLOB
    Clob clob = result.getClob(2)  // 取得CLOB 
     

    Blob擁有getBinaryStream()、getBytes()等方法,可以取得二進位串流或byte等資料,同樣的,Clob擁有getCharacterStream()、getSubString()等方法,可以取得字元串流或子字串等資料,您可以查看API文件來獲得更詳細的訊息。

    下面這個程式示範基本的檔案存入資料庫並取出另存新檔:
    BLOBCLOBDemo.java

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Blob;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;

    /**
     * @author Administrator
     * 
     * TODO To change the template for this generated type comment go to Window -
     * Preferences - Java - Code Style - Code Templates
     
    */

    public class BLOBCLOBDemo {
        
    public static void main(String[] args) {
            String driver 
    = "com.mysql.jdbc.Driver";
            String url 
    = "jdbc:mysql//localhost:3306/upload?"
                    
    + "useUnicode=true&characterEncoding=gbk";
            String user 
    = "root";
            String password 
    = "123456";
            
    try {
                Class.forName(driver);
                Connection conn 
    = DriverManager.getConnection(url, user, password);
                File file 
    = new File("./logo_phpbb.jpg");
                
    int length = (int) file.length();
                InputStream fin 
    = new FileInputStream(file);
                
    // 存入檔案
                PreparedStatement pstmt = conn
                        .prepareStatement(
    "insert into files values(?, ?)");
                pstmt.setString(
    1"Logo");
                pstmt.setBinaryStream(
    2, fin, length);
                pstmt.executeUpdate();
                pstmt.close();
                fin.close();
                
    // 取出檔案
                Statement stmt = conn.createStatement();
                ResultSet result 
    = stmt.executeQuery("select * from files");
                result.next();
                String description 
    = result.getString(1);
                Blob blob 
    = result.getBlob(2);
                
    // 寫入檔案
                System.out.println("檔案描述: " + description);
                FileOutputStream fout 
    = new FileOutputStream("./logo_phpbb_2.jpg");
                fout.write(blob.getBytes(
    1, (int) blob.length()));
                fout.flush();
                fout.close();
                stmt.close();
                conn.close();
            }
     catch (ClassNotFoundException e) {
                System.
    out.println("找不到驅動程式");
                e.printStackTrace();
            }
     catch (SQLException e) {
                e.printStackTrace();
            }
     catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    posted @ 2005-08-10 22:47 konhon 優華 閱讀(450) | 評論 (0)編輯 收藏

    Hibernate中的實體物件可以分為三種狀態:Transient、Persistent、Detached
    • Transient
    當您直接使用new創建出物件,例如在之前的例子中,User類別所衍生出之物件,在還沒有使用save()之前都是暫存物件,這些物件還沒有與資料庫發生任何的關係,不對應於資料庫中的任一筆資料。

    • Persistent
    當物件與資料庫中的資料有對應關係,並且與Session實例有關聯而Session 實例尚未關閉(close),則它是在Persistent狀態,具體而言,如果您將Transient狀態的物件使用Session的save()方法加以儲存,或是使用Hibernate從資料庫載入資料並封裝為物件(例如使用get()、load()),則該物件為Persistent狀態。

    Persistent狀態的物件對應於資料庫中的一筆資料,物件的id值與資料的主鍵值相同,並且Session實例尚未失效,在這期間您對物件的任何狀態變動,在Session實例關閉(close)或Transaction實例執行commit()之後,資料庫中對應的資料也會跟著更新。

    如果您將Session實例關閉(close),則Persistent狀態的物件會成為Detached狀態。

    如果您使用Session的實例delete()方法刪除資料,Persistent狀態的物件由於失去了對應的資料,則它會成為Transient狀態。
    • Detached
    Detached狀態的物件,其id與資料庫的主鍵值對應,但脫離Session實例的管理,例如在使用load()方法查詢到資料並封裝為物件之後,將Session實例關閉,則物件由Persistent狀態變為Detached狀態,Detached狀態的物件之任何屬性變動,不會對資料庫中的資料造成任何的影響。

    Detached狀態的物件可以使用update()方法使之與資料庫中的對應資料再度發生關聯,此時Detached狀態的物件會變為Persistent狀態。
    簡單的說,Transient與Detached狀態的物件未受Hibernate持久層管理員管理,對這兩個狀態的物件作任何屬性變動,不會對資料庫中的資料有任何的影響,而Persistent狀態的物件受Hibernate持久層管理,對物件的屬性變動,在Session實例關閉(close)或 Transaction實例執行commit()之後,資料庫中對應的資料也會跟著更新。

    Transient與Detached狀態的物件是非管理狀態,而Persistent狀態的物件是管理狀態,又稱為Persistent Object。

    在物件為Persistent時,如果物件的屬性發生變化,並且尚未提交之前,物件所攜帶的資料稱之為Dirty Data,Hibernate會在持久層維護物件的最近讀取版本,並在資料提交時檢查兩個版本的屬性是否有變化,如果有的話,則將資料庫中的資料進行更新。

    posted @ 2005-08-10 22:11 konhon 優華 閱讀(343) | 評論 (0)編輯 收藏

    Session是由SessionFactory所創建,SessionFactory是執行緒安全的(Thread-safe),您可以讓多個執行緒同時存取SessionFactory而不會有資料共用的問題,然而Session則不是設計為執行緒安全的,所以試圖讓多個執行緒共用一個 Session,將會產生因資料共用而發生混亂的問題。

    在Hibernate參考手冊中的 Quickstart with Tomcat 中,示範了一個HibernateUtil,它使用了ThreadLocal類別來建立一個Session管理的輔助類,這是Hibernate的Session管理一個廣為應用的解決方案,ThreadLocal是 Thread-Specific Storage 模式 的一個運作實例。

    由於Thread-Specific Stroage模式可以有效隔離執行緒所使用的資料,所以避開Session的多執行緒之間的資料共用問題,以下列出Hibernate參考手冊中的HibernateUtil類:

    HibernateUtil.java
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;

    /**
     * @author Administrator
     * 
     * TODO To change the template for this generated type comment go to Window -
     * Preferences - Java - Code Style - Code Templates
     
    */

    public class HibernateUtil {
        
    private static Log log = LogFactory.getLog(HibernateUtil.class);

        
    private static final SessionFactory sessionFactory;
        
    static {
            
    try {
                sessionFactory 
    = new Configuration().configure()
                        .buildSessionFactory();
            }
     catch (Throwable ex) {
                log.error(
    "Initial SessionFactory creation failed.", ex);
                
    throw new ExceptionInInitializerError(ex);
            }

        }


        
    public static final ThreadLocal session = new ThreadLocal();

        
    public static Session currentSession() {
            Session s 
    = (Session) session.get();
            
    if (s == null{
                s 
    = sessionFactory.openSession();
                session.
    set(s);
            }

            
    return s;
        }


        
    public static void closeSession() {
            Session s 
    = (Session) session.get();
            
    if (s != null)
                s.clear();
            session.
    set(null);
        }

    }


    在同一個執行緒中,Session被暫存下來了,但無須擔心資料庫連結Connection持續占用問題,Hibernate會在真正需要資料庫操作時才(從連接池中)取得Connection。

    在程式中可以這麼使用HibernateUtil:
    Session session = HibernateUtil.currentSession();
    User user = (User) session.load(User.class, new Integer(1));
    System.out.println(user.getName());
    HibernateUtil.closeSession();

    在Web應用程式中,可以藉助Filter來進行Session管理,在需要的時候開啟Session,並在Request結束之後關閉Session,這個部份,在 JavaWorld 技術論壇Wiki 上有篇 在filter中關閉session 可以參考
    posted @ 2005-08-10 20:14 konhon 優華 閱讀(2239) | 評論 (0)編輯 收藏

         摘要:     1*   2 * QuickExcel.java   3 * 作者:楊慶成   4 * Created on 2004年11月22日, 下午4:05  &n...  閱讀全文
    posted @ 2005-08-09 22:25 konhon 優華 閱讀(532) | 評論 (0)編輯 收藏

    僅列出標題
    共21頁: First 上一頁 13 14 15 16 17 18 19 20 21 下一頁 
    主站蜘蛛池模板: 亚洲国产精品专区| 亚洲精品中文字幕无乱码麻豆| 叮咚影视在线观看免费完整版| 亚洲av无码国产精品夜色午夜| 国产精品久久永久免费| 男男gvh肉在线观看免费| 亚洲午夜久久久久妓女影院 | 无码天堂va亚洲va在线va| 亚洲一区二区三区在线视频| 曰批全过程免费视频播放网站| 国产综合激情在线亚洲第一页| 亚洲AV无码乱码国产麻豆穿越| 大学生美女毛片免费视频| 国产va在线观看免费| 久久精品国产亚洲AV| 久久亚洲精精品中文字幕| 四虎国产精品免费视| 亚洲免费福利视频| 人妻巨大乳hd免费看| 亚洲一级毛片免费在线观看| 国产亚洲成归v人片在线观看| 在线观看无码AV网站永久免费 | 日本免费高清一本视频| 国产成人久久AV免费| 成年大片免费视频播放一级| 亚洲一区二区三区不卡在线播放 | 亚洲国产综合精品| 国产亚洲精品久久久久秋霞 | 亚洲AV无码久久寂寞少妇| 亚洲av无码专区在线观看素人| 日韩免费精品视频| 免费一区二区三区| 国产福利免费视频| 羞羞网站免费观看| 亚洲国产乱码最新视频| 亚洲高清资源在线观看| 亚洲狠狠婷婷综合久久久久| 亚洲偷自拍拍综合网| 国产乱子伦精品免费女| 久久久久久免费视频| 亚洲大片免费观看|