电竞比分网-中国电竞赛事及体育赛事平台

分享

JSTL 入門(mén),第4部分: 訪問(wèn)SQL和XML內(nèi)容

 Long_way 2007-07-31

2003 年 8 月 11 日

Web應(yīng)用程序的標(biāo)志是多個(gè)子系統(tǒng)的集成。SQL和XML是在這類子系統(tǒng)之間交換數(shù)據(jù)的兩種最通用的機(jī)制。在本文中,Mark Kolb介紹訪問(wèn)JSP頁(yè)面數(shù)據(jù)庫(kù)和XML內(nèi)容的sql和xml庫(kù)并對(duì)JSTL進(jìn)行了總結(jié)。

Web應(yīng)用程序的模板式(stereotypical)架構(gòu)分為三層:處理請(qǐng)求的Web服務(wù)器、實(shí)施業(yè)務(wù)邏輯的應(yīng)用程序服務(wù)器以及管理永久性數(shù)據(jù)的數(shù)據(jù)庫(kù)。應(yīng)用程序和數(shù)據(jù)庫(kù)層之間的聯(lián)接通常采用關(guān)系數(shù)據(jù)庫(kù)中的SQL調(diào)用格式。當(dāng)業(yè)務(wù)邏輯被寫(xiě)入到Java語(yǔ)言中時(shí),JDBC用于實(shí)現(xiàn)這些調(diào)用。

如果應(yīng)用程序調(diào)用與其它服務(wù)器(本地或遠(yuǎn)程)的集成,我們將需要用于在不同子系統(tǒng)之間交換數(shù)據(jù)的更深層次的機(jī)制。在Web應(yīng)用程序內(nèi)部和應(yīng)用程序之間傳送數(shù)據(jù)采用的越來(lái)越普遍的一種方法是XML文件的交換。

迄今為止,在我們的JSTL之旅中,我們討論了JSTL 表達(dá)式語(yǔ)言(expression language,EL)和 corefmt標(biāo)記庫(kù)。在最后一部分,我們將考慮sql和xml庫(kù)--正如它們的名字表示的一樣 -- 提供定制標(biāo)記來(lái)接入和管理從SQL數(shù)據(jù)庫(kù)和XML文件檢索到的數(shù)據(jù)。

不要遺漏本系列的其它部分

第1部分,“ 表達(dá)式語(yǔ)言” (2003年2月)

第2部分,“ 探討核心”(2003年3月)

第3部分,“ 表示就是一切(Presentation is everything)” (2003年4月)

xml庫(kù)

根據(jù)設(shè)計(jì),XML提供靈活的方式來(lái)表示結(jié)構(gòu)化數(shù)據(jù),這些數(shù)據(jù)同時(shí)準(zhǔn)備進(jìn)行驗(yàn)證,因此它尤其適應(yīng)于在松散聯(lián)合的系統(tǒng)之間交換數(shù)據(jù)。這反過(guò)來(lái)使其成為Web應(yīng)用程序極具吸引力的集成技術(shù)。

與使用XML表示的數(shù)據(jù)進(jìn)行交互的第一步是把數(shù)據(jù)作為一個(gè)XML文件,對(duì)其進(jìn)行檢索并進(jìn)行分解,以創(chuàng)建數(shù)據(jù)結(jié)構(gòu)來(lái)接入該文件中的內(nèi)容。在分解文件后,您可以有選擇的對(duì)其進(jìn)行轉(zhuǎn)換以創(chuàng)建新的XML文件,您可以對(duì)新的XML文件進(jìn)行相同的操作。最終,文件中的數(shù)據(jù)可以被提取,然后顯示或使用作為輸入數(shù)據(jù)來(lái)運(yùn)行其它操作。

這些步驟都在用于控制XML的JSTL標(biāo)記中反映出。根據(jù)我們?cè)诘?部分 探討核心中所討論的,我們使用core庫(kù)中的<c:import>標(biāo)記來(lái)檢索XML文件。然后使用<x:parse>標(biāo)記來(lái)分解該文件,支持標(biāo)準(zhǔn)的XML分解技術(shù),如文件對(duì)象模式(Document Object Model,DOM)和簡(jiǎn)單XML API(Simple API for XML,SAX)。<x:transform>標(biāo)記可用于轉(zhuǎn)換XML文件并依賴標(biāo)準(zhǔn)技術(shù)來(lái)轉(zhuǎn)換XML數(shù)據(jù):擴(kuò)展樣式表語(yǔ)言( Extensible Stylesheet Language,XSL)。最后,我們提供多個(gè)標(biāo)記來(lái)接入和控制分解后的XML數(shù)據(jù),但是所有這一切都依賴于另一種標(biāo)準(zhǔn)- XML路徑語(yǔ)言(XML Path Language,XPath),以引用分解后的XML文件中的內(nèi)容。

分解XML

<x:parse>標(biāo)記有多種格式,取決于用戶希望的分解類型。這一項(xiàng)操作最基本的格式使用以下語(yǔ)法:

<x:parse xml="
                        expression" var="
                        name" scope="
                        scope"
                        filter="
                        expression" systemId="
                        expression"/>
                        

在這五種屬性中,只有xml屬性是需要的,其值應(yīng)該是包含要分解的XML文件的字符串,或者是java.io.Reader實(shí)例,通過(guò)它可以讀取要被分解的文件。此外,您可以使用以下語(yǔ)法,根據(jù)<x:parse>標(biāo)記的主體內(nèi)容來(lái)規(guī)定要被分解的文件:

<x:parse var="
                        name" scope="
                        scope"
                        filter="
                        expression" systemId="
                        expression">
                        body content
                        </x:parse>
                        

var和scope屬性規(guī)定存儲(chǔ)分解后的文件的scoped變量。然后xml庫(kù)中的其它標(biāo)記可以使用這一變量來(lái)運(yùn)行其它操作。注意,當(dāng)var和 scope 屬性存在時(shí),JSTL用于表示分解后的文件的數(shù)據(jù)結(jié)構(gòu)類型以實(shí)施為導(dǎo)向,從而廠商可以對(duì)其進(jìn)行優(yōu)化。

如果應(yīng)用程序需要對(duì)JSTL提供的分解后的文件進(jìn)行處理,它可以使用另一種格式的<x:parse>,它要求分解后的文件堅(jiān)持使用一個(gè)標(biāo)準(zhǔn)接口。在這種情況下,該標(biāo)記的語(yǔ)法如下:

<x:parse xml="
                        expression" varDom="
                        name" scopeDom="
                        scope"
                        filter="
                        expression" systemId="
                        expression"/>
                        

當(dāng)您使用<x:parse>的這一版本時(shí),表示分解后的XML文件的對(duì)象必須使用org.w3c.dom.Document接口。當(dāng)根據(jù)<x:parse>中的主體內(nèi)容來(lái)規(guī)定XML文件時(shí),您還可以使用varDom和scopeDom屬性來(lái)代替var 和 scope屬性,語(yǔ)法如下:

<x:parse varDom="
                        name" scopeDom="
                        scope"
                        filter="
                        expression" systemId="
                        expression">
                        body content
                        </x:parse>
                        

其它兩個(gè)屬性filter 和 systemId 可以實(shí)現(xiàn)對(duì)分解流程的精確控制。filter 屬性規(guī)定org.xml.sax.XMLFilter類的一個(gè)實(shí)例,以在分解之前對(duì)文件進(jìn)行過(guò)濾。如果要被分解的文件非常大,但目前的工作只需要處理一小部分內(nèi)容時(shí)這一屬性尤其有用。systemId屬性表示要被分解的文件的URI并解析文件中出現(xiàn)的任何相關(guān)的路徑。當(dāng)被分解的XML文件使用相關(guān)的URL來(lái)引用分解流程中需要接入的其它文件或資源時(shí)需要這種屬性

清單1展示了<x:parse> 標(biāo)記的使用,包括與 <c:import>的交互。此處<c:import> 標(biāo)記用于檢索眾所周知的Slashdot Web 網(wǎng)站的RDF Site Summary (RSS)反饋,然后使用<x:parse>分解表示RSS 反饋的XML文件,表示分解后的文件的以實(shí)施為導(dǎo)向的數(shù)據(jù)結(jié)構(gòu)被保存到名為rss的變量(帶有page 范圍)中。


清單1:<x:parse>與<c:import>的交互
<c:import var="rssFeed" url="http:///slashdot.rdf"/>
                        <x:parse var="rss" xml="${rssFeed}"/>
                        

轉(zhuǎn)換XML

XML通過(guò)XSL樣式表來(lái)轉(zhuǎn)換。JSTL使用<x:transform>標(biāo)記來(lái)支持這一操作。與<x:parse>的情況一樣,<x:transform> 標(biāo)記支持多種不同的格式。<x:transform> 最基本的格式的語(yǔ)法是:

<x:transform xml="
                        expression" xslt="
                        expression"
                        var="
                        name" scope="
                        scope"
                        xmlSystemId="
                        expression" xsltSystemId="
                        expression">
                        <x:param name="
                        expression" value="
                        expression"/>
                        ...
                        </x:transform>
                        

關(guān)于 RSS

RDF Site Summary (RSS) 是許多以新聞為導(dǎo)向的網(wǎng)站公布的XML文件格式,它列出它們當(dāng)前的標(biāo)題,提供鏈接到相關(guān)文章的URL。同樣,它提供在Web上聯(lián)合新聞的簡(jiǎn)單機(jī)制。關(guān)于RSS的更詳細(xì)信息,請(qǐng)參閱 參考資料。

此處,xml 屬性規(guī)定要被轉(zhuǎn)換的文件,xslt 屬性規(guī)定定義這次轉(zhuǎn)換的樣式表。這兩種屬性是必要的,其它屬性為可選。

與<x:parse>的xml屬性一樣,<x:transform>的xml 屬性值可以是包含XML文件的字符串,或者是接入這類文件的Reader。此外,它還可以采用 org.w3c.dom.Document 類或javax.xml.transform.Source 類的實(shí)例格式。最后,它還可以是使用<x:parse> 操作的var或varDom屬性分配的變量值。

而且,您可以根據(jù)<x:transform> 操作的主體內(nèi)容來(lái)包含要被轉(zhuǎn)換的XML文件。在這種情況下,<x:transform> 的語(yǔ)法是:

<x:transform xslt="
                        expression"
                        var="
                        name" scope="
                        scope"
                        xmlSystemId="
                        expression" xsltSystemId="
                        expression">
                        body content
                        <x:param name="
                        expression" value="
                        expression"/>
                        ...
                        </x:transform>
                        

在這兩種情況下,規(guī)定XSL 樣式表的xslt 屬性應(yīng)是字符串、Reader或javax.xml.transform.Source實(shí)例。

如果var 屬性存在,轉(zhuǎn)換后的XML文件將分配給相應(yīng)的scoped變量,作為org.w3c.dom.Document 類的一個(gè)實(shí)例。通常,scope屬性規(guī)定這類變量分配的范圍。

<x:transform> 標(biāo)記還支持將轉(zhuǎn)換結(jié)果存儲(chǔ)到j(luò)avax.xml.transform.Result 類的一個(gè)實(shí)例中,而不是作為org.w3c.dom.Document的一個(gè)實(shí)例。如果var 和 scope 屬性被省略,result對(duì)象規(guī)定作為result屬性的值,<x:transform>標(biāo)記將使用該對(duì)象來(lái)保存應(yīng)用該樣式表的結(jié)果。清單2中介紹了使用<x:transform> 的result屬性的這兩種語(yǔ)法的變化:


清單2:使用result屬性來(lái)提供javax.xml.transform.Result實(shí)例時(shí),<x:transform>操作的語(yǔ)法變化
<x:transform xml="
                        expression" xslt="
                        expression"
                        result="
                        expression"
                        xmlSystemId="
                        expression" xsltSystemId="
                        expression">
                        <x:param name="
                        expression" value="
                        expression"/>
                        ...
                        </x:transform>
                        <x:transform xslt="
                        expression"
                        result="
                        expression"
                        xmlSystemId="
                        expression" xsltSystemId="
                        expression">
                        body content
                        <x:param name="
                        expression" value="
                        expression"/>
                        ...
                        </x:transform>
                        

無(wú)論您采用這兩種<x:transform>格式中的那一種,您都必須從定制標(biāo)記單獨(dú)創(chuàng)建javax.xml.transform.Result對(duì)象。該對(duì)象自身作為result屬性的值提供。

如果既不存在var 屬性,也不存在result屬性,轉(zhuǎn)換的結(jié)果將簡(jiǎn)單地插入到JSP頁(yè)面,作為處理<x:transform> 操作的結(jié)果。當(dāng)樣式表用于將數(shù)據(jù)從XML轉(zhuǎn)換成HTML時(shí)尤其有用,如清單3所示:


清單3:在JSP頁(yè)面直接顯示轉(zhuǎn)換的XML數(shù)據(jù)
<c:import var="rssFeed" url="http:///slashdot.rdf"/>
                        <c:import var="rssToHtml" url="/WEB-INF/xslt/rss2html.xsl"/>
                        <x:transform xml="${rssFeed}" xslt="${rssToHtml}"/>
                        

在本例中,使用 <c:import> 標(biāo)記來(lái)讀取RSS反饋和適當(dāng)?shù)臉邮奖?。樣式表的輸出結(jié)果是HTML,通過(guò)忽略<x:transform>的var和result 屬性來(lái)直接顯示。圖1顯示了實(shí)例結(jié)果:


圖1:清單3的輸出結(jié)果
Output of Listing 3

與<x:parse>的systemId 屬性一樣,<x:transform>的xmlSystemId 和 xsltSystemId 屬性用于解析XML文件中相關(guān)的路徑。在這種情況下,xmlSystemId 屬性應(yīng)用于根據(jù)標(biāo)記的 xml屬性值提供的文件,而xsltSystemId 屬性用于解析根據(jù)標(biāo)記的xslt屬性規(guī)定的樣式表中的相關(guān)路徑。

如果正在推動(dòng)文件轉(zhuǎn)換的樣式表使用了參數(shù),我們使用<x:param> 標(biāo)記來(lái)規(guī)定這些參數(shù)。如果參數(shù)存在,那么這些標(biāo)記必須在<x:transform> 標(biāo)記主體內(nèi)顯示。如果根據(jù)主體內(nèi)容規(guī)定了要被轉(zhuǎn)換的XML文件,那么它必須先于任何 <x:param> 標(biāo)記。

<x:param> 標(biāo)記有兩種必要的屬性 -- name 和 value -- 就象本系列 第2部分第3部分中討論的<c:param> 和 <fmt:param> 標(biāo)記一樣。

處理XML內(nèi)容

XML文件的分解和轉(zhuǎn)換操作都是基于整個(gè)文件來(lái)進(jìn)行。但是,在您將文件轉(zhuǎn)換成一種可用的格式之后,一項(xiàng)應(yīng)用程序通常只對(duì)文件中包含的一部分?jǐn)?shù)據(jù)感興趣。鑒于這一原因,xml 庫(kù)包括多個(gè)標(biāo)記來(lái)接入和控制XML文件內(nèi)容的各個(gè)部分。

如果您已經(jīng)閱讀了本系列第2部分( 探討核心),您將對(duì)這些xml 標(biāo)記的名字非常熟悉。它們都基于JSTL core 庫(kù)相應(yīng)的標(biāo)記。但是,這些core 庫(kù)標(biāo)記使用EL表達(dá)式,通過(guò)它們的value屬性來(lái)接入JSP容器中的數(shù)據(jù),而它們?cè)趚ml 庫(kù)中的副本使用XPath表達(dá)式,通過(guò)select屬性接入XML文件中的數(shù)據(jù)。

XPath是引用XML文件中元素及它們的屬性值和主體內(nèi)容的標(biāo)準(zhǔn)化符號(hào)。正如其名字代表的一樣,這種符號(hào)與文件系統(tǒng)路徑的表示方法類似,使用短斜線來(lái)分開(kāi)XPath語(yǔ)句的組分。這些組分對(duì)映于XML文件的節(jié)點(diǎn),連續(xù)的組分匹配嵌套的Element。此外,星號(hào)可以用于作為通配符來(lái)匹配多個(gè)節(jié)點(diǎn),括號(hào)內(nèi)的表達(dá)式可以用于匹配屬性值和規(guī)定索引。有多種在線參考資料介紹XPath和它的使用(見(jiàn) 參考資料)。

要顯示XML文件的數(shù)據(jù)的一個(gè)Element,使用<x:out> 操作,它與core 庫(kù)的<c:out> 標(biāo)記類似。 但是,<c:out> 使用名為value 和escapeXml的屬性,<x:out> 的屬性為select 和escapeXml:

<x:out select="
                        XPathExpression" escapeXml="
                        boolean"/>
                        

當(dāng)然,兩者的區(qū)別在于<x:out> 的select 屬性值必須是XPath表達(dá)式,而<c:out> 的value 屬性必須是EL表達(dá)式。兩種標(biāo)記的escapeXml 屬性的意義是相同的。

清單4顯示了<x:out> 操作的使用。注意,規(guī)定用于select 屬性的XPath表達(dá)式由一個(gè)EL表達(dá)式規(guī)定為scoped變量,尤其是$rss。這一EL表達(dá)式根據(jù)將被求值的XPath語(yǔ)句來(lái)識(shí)別分解后的XML文件。該語(yǔ)句在此處查找名為title且父節(jié)點(diǎn)名為channel的Element,從而選擇它找到的第一個(gè)Element(根據(jù)表達(dá)式尾部[1]索引規(guī)定)。這一<x:out> 操作的結(jié)果是顯示這一Element的主體內(nèi)容,關(guān)閉正在轉(zhuǎn)義(Escaping)的XML字符。


清單4:使用<x:out>操作來(lái)顯示XML Element的主體內(nèi)容
<c:import var="rssFeed" url="http:///slashdot.rdf"/>
                        <x:parse var="rss" xml="${rssFeed}"/>
                        <x:out select="$rss//*[name()=‘channel‘]/*[name()=‘title‘][1]"
                        escapeXml="false"/>
                        

除了<x:out>之外,JSTL xml 庫(kù)包括以下控制XML數(shù)據(jù)的標(biāo)記:

  • <x:set> ,向JSTL scoped 變量分配XPath表達(dá)式的值
  • <x:if> ,根據(jù)XPath表達(dá)式的布爾值來(lái)?xiàng)l件化內(nèi)容
  • <x:choose>、<x:when>和<x:otherwise>,根據(jù)XPath表達(dá)式來(lái)實(shí)施互斥的條件化
  • <x:forEach> ,迭代根據(jù)XPath表達(dá)式匹配的多個(gè)Elements

每個(gè)這些標(biāo)記的操作與core庫(kù)中相應(yīng)的標(biāo)記類似。例如,清單5中顯示的<x:forEach>的使用, <x:forEach> 操作用于迭代XML文件中表示RSS反饋的所有名為item 的Element。注意,<x:forEach>主體內(nèi)容中嵌套的兩個(gè)<x:out> 操作中的XPath表達(dá)式與<x:forEach>標(biāo)記正在迭代的節(jié)點(diǎn)相關(guān)。它們用于檢索每個(gè)item element的子節(jié)點(diǎn)link 和 title。


清單5:使用<x:out> 和<x:forEach>操作來(lái)選擇和顯示XML數(shù)據(jù)
<c:import var="rssFeed" url="http:///slashdot.rdf"/>
                        <x:parse var="rss" xml="${rssFeed}"/>
                        <a href="<x:out select="$rss//*[name()=‘channel‘]/*[name()=‘link‘][1]"/>"
                        ><x:out select="$rss//*[name()=‘channel‘]/*[name()=‘title‘][1]"
                        escapeXml="false"/></a>
                        <x:forEach select="$rss//*[name()=‘item‘]">
                        <li> <a href="<x:out select="./*[name()=‘link‘]"/>"
                        ><x:out select="./*[name()=‘title‘]" escapeXml="false"/></a>
                        </x:forEach>
                        

清單5中JSP程序代碼的輸出結(jié)果與 清單3類似,它在 圖1中顯示。xml 庫(kù)以XPath為導(dǎo)向的標(biāo)記提供備選的樣式表來(lái)轉(zhuǎn)換XML內(nèi)容,尤其是當(dāng)最后的輸出結(jié)果是HTML的情況。





回頁(yè)首


sql庫(kù)

JSTL第4個(gè)也是最后一個(gè)操作是sql定制標(biāo)記庫(kù)。正如其名字代表的一樣,該庫(kù)提供與關(guān)系數(shù)據(jù)庫(kù)交互的標(biāo)記。尤其是sql 庫(kù)定義規(guī)定數(shù)據(jù)源、發(fā)布查詢和更新以及將查詢和更新編組到事務(wù)處理中的標(biāo)記。

Datasource
Datasource是獲得數(shù)據(jù)庫(kù)連接的工廠。它們經(jīng)常實(shí)施某些格式的連接庫(kù)來(lái)最大限度地降低與創(chuàng)建和初始化連接相關(guān)的開(kāi)銷(xiāo)。Java 2 Enterprise Edition (J2EE)應(yīng)用程序服務(wù)器通常內(nèi)置了Datasource支持,通過(guò) Java命名和目錄接口( Java Naming and Directory Interface,JNDI)它可用于J2EE應(yīng)用程序。

JSTL的sql 標(biāo)記依賴于Datasource來(lái)獲得連接。實(shí)際上包括可選的dataSource 屬性以明確規(guī)定它們的連接工廠作為 javax.sql.DataSource 接口實(shí)例,或作為JNDI名。

您可以使用<sql:setDataSource> 標(biāo)記來(lái)獲得javax.sql.DataSource 實(shí)例,它采用以下兩種格式:

<sql:setDataSource dataSource="
                        expression"
                        var="
                        name" scope="
                        scope"/>
                        <sql:setDataSource url="
                        expression" driver="
                        expression"
                        user="
                        expression" password="
                        expression"
                        var="
                        name" scope="
                        scope"/>
                        

第一種格式只需要dataSource 屬性,而第二種格式只需要url 屬性。

通過(guò)提供JNDI名作為dataSource屬性值,您可以使用第一種格式來(lái)接入與JNDI名相關(guān)的datasource。第二種格式將創(chuàng)建新的datasource,使用作為url屬性值提供的JDBC URL。可選的driver 屬性規(guī)定實(shí)施數(shù)據(jù)庫(kù)driver的類的名稱,同時(shí)需要時(shí)user 和 password 屬性提供接入數(shù)據(jù)庫(kù)的登錄證書(shū)。

對(duì)于<sql:setDataSource>的任何一種格式而言,可選的var 和 scope 屬性向scoped變量分配特定的datasource。如果var屬性不存在,那么 <sql:setDataSource> 操作設(shè)置供sql 標(biāo)記使用的缺省 datasource,它們沒(méi)有規(guī)定明確的datasource。

您還可以使用javax.servlet.jsp.jstl.sql.dataSource 參數(shù)來(lái)配置sql 庫(kù)的缺省datasource。在實(shí)踐中,在應(yīng)用程序的Web.xml文件中添加與清單6中顯示的類似的程序代碼是規(guī)定缺省datasource最方便的方式。使用<sql:setDataSource> 來(lái)完成這一操作要求使用JSP頁(yè)面來(lái)初始化該應(yīng)用程序,因此可以以某種方式自動(dòng)運(yùn)行這一頁(yè)面。


清單6:使用JNDI名來(lái)設(shè)置JSTL在web.xml部署描述符中的缺省datasource
<context-param>
                        <param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name>
                        <param-value>jdbc/blog</param-value>
                        </context-param>
                        

提交查詢和更新

在建立了datasource接入之后,您可以使用<sql:query> 操作來(lái)執(zhí)行查詢,同時(shí)使用<sql:update> 操作來(lái)執(zhí)行數(shù)據(jù)庫(kù)更新。查詢和更新使用SQL語(yǔ)句來(lái)規(guī)定,它可以是使用基于JDBC的java.sql.PreparedStatement 接口的方法來(lái)實(shí)現(xiàn)參數(shù)化。參數(shù)值使用嵌套的<sql:param> 和 <sql:dateParam> 標(biāo)記來(lái)規(guī)定。

支持以下三種<sql:query> 操作:

<sql:query sql="
                        expression" dataSource="
                        expression"
                        var="
                        name" scope="
                        scope"
                        maxRows="
                        expression" startRow="
                        expression"/>
                        <sql:query sql="
                        expression" dataSource="
                        expression"
                        var="
                        name" scope="
                        scope"
                        maxRows="
                        expression" startRow="
                        expression">
                        <sql:param value="
                        expression"/>
                        ...
                        </sql:query>
                        <sql:query dataSource="
                        expression"
                        var="
                        name" scope="
                        scope"
                        maxRows="
                        expression" startRow="
                        expression">
                        SQL statement
                        <sql:param value="
                        expression"/>
                        ...
                        </sql:query>
                        

前兩種格式只要求sql 和 var 屬性,第三種格式只要求var 屬性。

var 和 scope 屬性規(guī)定存儲(chǔ)查詢結(jié)果的scoped 變量。maxRows 屬性可以用于限制查詢返回的行數(shù),startRow 屬性允許忽略一些最開(kāi)始的行數(shù)(如當(dāng)結(jié)果集(Result set)由數(shù)據(jù)庫(kù)來(lái)構(gòu)建時(shí)忽略)。

在執(zhí)行了查詢之后,結(jié)果集被分配給scoped變量,作為javax.servlet.jsp.jstl.sql.Result 接口的一個(gè)實(shí)例。這一對(duì)象提供接入行、列名稱和查詢的結(jié)果集大小的屬性,如表1所示:

表1:javax.servlet.jsp.jstl.sql.Result 接口定義的屬性

屬性 說(shuō)明
rows 一排SortedMap 對(duì)象,每個(gè)對(duì)象對(duì)映列名和結(jié)果集中的單行
rowsByIndex 一排數(shù)組,每個(gè)對(duì)應(yīng)于結(jié)果集中的單行
columnNames 一排對(duì)結(jié)果集中的列命名的字符串,采用與rowsByIndex屬性相同的順序
rowCount 查詢結(jié)果中總行數(shù)
limitedByMaxRows 如果查詢受限于maxRows 屬性值為真

在這些屬性中,rows 尤其方便,因?yàn)槟梢允褂盟鼇?lái)在整個(gè)結(jié)果集中進(jìn)行迭代和根據(jù)名字訪問(wèn)列數(shù)據(jù)。我們?cè)?清單7中闡述了這一操作,查詢的結(jié)果被分配到名為queryResults的scoped變量中,然后使用core 庫(kù)中的<c:forEach>標(biāo)記來(lái)迭代那些行。嵌套的<c:out> 標(biāo)記利用EL內(nèi)置的Map 收集支持來(lái)查找與列名稱相對(duì)應(yīng)的行數(shù)據(jù)。(記得在 第1部分 ,${row.title}和${row["title"]} 是相等的表達(dá)式。)

清單7還展示了使用<sql:setDataSource> 來(lái)關(guān)聯(lián)datasource 和scoped變量,它由<sql:query> 操作通過(guò)其dataSource 屬性隨后接入。


清單7:使用<sql:query>來(lái)查詢數(shù)據(jù)庫(kù),使用<c:forEach>來(lái)迭代整個(gè)結(jié)果集
<sql:setDataSource var="dataSrc"
                        url="jdbc:mysql:///taglib" driver="org.gjt.mm.mysql.Driver"
                        user="admin" password="secret"/>
                        <sql:query var="queryResults" dataSource="${dataSrc}">
                        select * from blog group by created desc limit ?
                        <sql:param value="${6}"/></sql:query>
                        <table border="1">
                        <tr>
                        <th>ID</th>
                        <th>Created</th>
                        <th>Title</th>
                        <th>Author</th>
                        </tr>
                        <c:forEach var="row" items="${queryResults.rows}">
                        <tr>
                        <td><c:out value="${row.id}"/></td>
                        <td><c:out value="${row.created}"/></td>
                        <td><c:out value="${row.title}"/></td>
                        <td><c:out value="${row.author}"/></td>
                        </tr>
                        </c:forEach>
                        </table>
                        

圖2顯示了清單7中JSTL程序代碼的實(shí)例頁(yè)面輸出結(jié)果。注意:清單7中<sql:query>操作主體中出現(xiàn)的SQL語(yǔ)句為參數(shù)化語(yǔ)句。


圖2:清單7的輸出
Output of Listing 7

在<sql:query> 操作中,SQL語(yǔ)句根據(jù)主體內(nèi)容來(lái)規(guī)定,或者使用?字符,通過(guò)sql 屬性實(shí)現(xiàn)參數(shù)化。對(duì)于SQL語(yǔ)句中每個(gè)這樣的參數(shù)來(lái)說(shuō),應(yīng)有相應(yīng)的<sql:param> 或 <sql:dateParam> 操作嵌套到<sql:query> 標(biāo)記的主體中。<sql:param> 標(biāo)記只采用一種屬性 -- value --來(lái)規(guī)定參數(shù)值。此外,當(dāng)參數(shù)值為字符串時(shí),您可以忽略value 屬性并根據(jù)<sql:param> 標(biāo)記的主體內(nèi)容來(lái)提供參數(shù)值。

表示日期、時(shí)間或時(shí)間戳的參數(shù)值使用<sql:dateParam> 標(biāo)記來(lái)規(guī)定,使用以下語(yǔ)法:

<sql:dateParam value="
                        expression" type="
                        type"/>
                        

對(duì)于<sql:dateParam>來(lái)說(shuō),value 屬性的表達(dá)式必須求 java.util.Date 類實(shí)例的值,同時(shí)type 屬性值必須是date、time或timestamp,由SQL語(yǔ)句需要那類與時(shí)間相關(guān)的值來(lái)決定。

與<sql:query> 一樣,<sql:update> 操作支持三種格式:

<sql:update sql="
                        expression" dataSource="
                        expression"
                        var="
                        name" scope="
                        scope"/>
                        <sql:update sql="
                        expression" dataSource="
                        expression"
                        var="
                        name" scope="
                        scope">
                        <sql:param value="
                        expression"/>
                        ...
                        </sql:update>
                        <sql:update dataSource="
                        expression"
                        var="
                        name" scope="
                        scope">
                        SQL statement
                        <sql:param value="
                        expression"/>
                        ...
                        </sql:update>
                        

sql 和dataSource 屬性有與<sql:query>相同的<sql:update> 語(yǔ)義。同樣,var 和 scope 屬性可以用于規(guī)定scoped變量,但在這種情況下,分配給scoped變量的值將是java.lang.Integer 的一個(gè)實(shí)例,顯示作為數(shù)據(jù)庫(kù)更新結(jié)果而更改的行數(shù)。

管理事務(wù)處理

事務(wù)處理用于保護(hù)作為一個(gè)組必須成功或失敗的一系列數(shù)據(jù)庫(kù)操作。事務(wù)處理支持已經(jīng)嵌入到JSTL的sql 庫(kù)中,通過(guò)將相應(yīng)的<sql:query>和<sql:update>操作嵌套到<sql:transaction>標(biāo)記的主體內(nèi)容中,從而將一系列查詢和更新操作打包到一個(gè)事務(wù)處理中也就顯得微不足道了。

<sql:transaction> 語(yǔ)法如下:

<sql:transaction dataSource="
                        expression" isolation="
                        isolationLevel">
                        <sql:query .../>
                        or  <sql:update .../>
                        ...
                        

<sql:transaction> 操作沒(méi)有必需的屬性。如果您忽略了dataSource 屬性,那么使用JSTL的缺省datasource。isolation 屬性用于規(guī)定事務(wù)處理的隔離級(jí)別,它可以是read_committed、read_uncommitted、repeatable_read或serializable。如果您未規(guī)定這一屬性,事務(wù)處理將使用datasource的缺省隔離級(jí)別。

您可能希望所有嵌套的查詢和更新必須使用與事務(wù)處理相同的datasource。實(shí)際上,嵌套到<sql:transaction>操作中的<sql:query> 或 <sql:update> 不能用于規(guī)定dataSource 屬性。它將自動(dòng)使用與周?chē)?lt;sql:transaction>標(biāo)記相關(guān)的datasource (顯性或隱性)。

清單8顯示了如何使用<sql:transaction> 的一個(gè)實(shí)例:


清單:使用<sql:transaction>來(lái)將數(shù)據(jù)庫(kù)更新聯(lián)合到事務(wù)處理中
<sql:transaction>
                        <sql:update sql="update blog set title = ? where id = ?">
                        <sql:param value="New Title"/>
                        <sql:param value="${23}"/>
                        </sql:update>
                        <sql:update sql="update blog set last_modified = now() where id = ?">
                        <sql:param value="${23}"/>
                        </sql:update>
                        </sql:transaction>
                        





回頁(yè)首


注意事項(xiàng)

JSTL的xml 和 sql 庫(kù)使用定制標(biāo)記,從而能夠在JSP頁(yè)面上實(shí)施復(fù)雜的功能,但是在您的表示層實(shí)施這類功能可能不是最好的方法。

對(duì)于多位開(kāi)發(fā)人員長(zhǎng)期編寫(xiě)的大型應(yīng)用程序來(lái)說(shuō),實(shí)踐證明,用戶接口、基本的業(yè)務(wù)邏輯和數(shù)據(jù)倉(cāng)庫(kù)之間的嚴(yán)格分離能夠長(zhǎng)期簡(jiǎn)化軟件維護(hù)。廣泛流行的模式/視圖/控制器( Model-View-Controller,MVC)設(shè)計(jì)模板是這一“最佳實(shí)踐”的公式化。在J2EE Web應(yīng)用程序領(lǐng)域中,模式是應(yīng)用程序的業(yè)務(wù)邏輯,視圖是包含表示層的JSP頁(yè)面。(控制器是form handlers和其它服務(wù)器端機(jī)制,使瀏覽器操作能夠開(kāi)始更改模式并隨后更新視圖。) MVC規(guī)定應(yīng)用程序的三個(gè)主要elements--模式、視圖和控制器 --相互之間有最小的相關(guān)性,從而限制相互之間的交互到統(tǒng)一、精心定義的接口。

應(yīng)用程序依賴XML文件來(lái)進(jìn)行數(shù)據(jù)交換以及關(guān)系數(shù)據(jù)庫(kù)來(lái)提供數(shù)據(jù)永久性都是應(yīng)用程序業(yè)務(wù)邏輯(也就是其模式)的特征。因此,使用MVC設(shè)計(jì)模板建議無(wú)需在應(yīng)用程序的表示層(也就是其視圖)反映這些實(shí)施細(xì)節(jié)。如果JSP用于實(shí)施表示層,那么使用 xml 和 sql 庫(kù)將違反MVC,因?yàn)樗鼈兊氖褂脤⒁馕吨诒硎緦觾?nèi)暴露基本業(yè)務(wù)邏輯的elements。

鑒于這一原因,xml 和 sql 庫(kù)最適用于小型項(xiàng)目和原型工作。應(yīng)用程序服務(wù)器對(duì)JSP頁(yè)面的動(dòng)態(tài)編譯也使得這些庫(kù)中的定制標(biāo)記可以用于作為調(diào)試工具。





回頁(yè)首


結(jié)束語(yǔ)

在本系列中,我們討論了4個(gè)JSTL定制標(biāo)記庫(kù)的功能及它們的使用。在 第1部分第2部分,我們討論通過(guò)El和core 庫(kù)標(biāo)記的使用,您如何在許多常見(jiàn)情況下避免JSP腳本程序。 第3部分 關(guān)注使用fmt 庫(kù)來(lái)本地化Web內(nèi)容。

在最后一部分,我們討論了xml 和 sql 庫(kù)的功能。如果您愿意接受將業(yè)務(wù)邏輯包含到表示層的結(jié)果,這兩個(gè)庫(kù)中的標(biāo)記都使其能夠非常輕松地將XML文件和關(guān)系數(shù)據(jù)庫(kù)中的內(nèi)容結(jié)合到JSP頁(yè)面。這兩個(gè)庫(kù)還展示了當(dāng)集成<sql:query> 和<c:forEach>時(shí),JSTL庫(kù)如何構(gòu)建和集成,以及xml 庫(kù)利用<c:import> 操作的能力。



參考資料



關(guān)于作者

 

Mark Kolb 是一位在德克薩斯州奧斯汀市(Austin)工作的軟件工程師。他常就服務(wù)器端 Java 這一主題在業(yè)界演講,而且還是 Web Development with JavaServer Pages, 第二版 一書(shū)的合著者??梢酝ㄟ^(guò) mak@taglib.com與 Mark聯(lián)系。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多