cocoon系列——開發(fā)一個Web站點
Cocoon 2 引入了這些數(shù)據(jù)庫集成功能,但它并沒有被設(shè)計成完整的 Java 應(yīng)用程序服務(wù)器框架。Cocoon 2 不與基于 J2EE 體系結(jié)構(gòu)的服務(wù)器競爭,因為它沒有提供同等級別的資源和事務(wù)管理、負(fù)載均衡和部署選項。Cocoon 2 最適合于少量復(fù)雜業(yè)務(wù)邏輯和處理主要用于內(nèi)容生成的應(yīng)用程序。然而,您仍然可以和 EJB 服務(wù)器一起使用 Cocoon 2。Cocoon 2 可以輕易地充當(dāng)替換表示層,而更常用的 Java Servlet 和 Java Server Pages 則要遜色得多。簡而言之,Cocoon 2 旨在通過從少量的功能提供最大的靈活性來滿足 80/20 規(guī)則。
一、配置DB連接
1.1、web.xml
<init-param>
<param-name>extra-classpath</param-name>
<param-value>WEB-INF/extra-classes1:/ABSOLUTE-PATH-TO-ARCHIVE</param-value>
</init-param>
或者直接將jdbc驅(qū)動扔到tomcat的common\lib中
<init-param>
<param-name>load-class</param-name>
<param-value>
com.mysql.jdbc.Driver
</param-value>
</init-param>
1.2、cocoon.xconf中加:
<datasources>
……
<jdbc logger="core.datasources.personnel" name="ldodds">
<pool-controller max="10" min="5"/>
<dburl>jdbc:mysql://localhost:3306/new_db?autoReconnect=true</dburl>
<user>root</user>
<password>bibi</password>
</jdbc>
……
</datasources>
二、ESQL 邏輯表
ESQL 邏輯表是標(biāo)準(zhǔn) JDBC API 上較“瘦”的一層,它定義了許多映射到特定 JDBC 功能的標(biāo)記。因此,邏輯表是一種為應(yīng)用程序生成 JDBC 代碼的簡單方法。使用 ESQL 邏輯表時,必須使用許多常用結(jié)構(gòu)化元素。其中每個元素都從 JDBC API 中等價的對象中派生出它的功能。在所有情況下,您都可以將 ESQL 標(biāo)記同那些由 XSP 頁面直接輸出的用戶定義標(biāo)記混合在一起。您也可以使用 XSP 標(biāo)記和來自其它邏輯表的標(biāo)記,來定義所需的額外處理。唯一真正的限制是要確保 XSP 頁面保持格式良好。
2.1、esql:connection
esql:connection
等價于 JDBC Connection。
正如所有 JDBC 操作最終都派生自特殊的數(shù)據(jù)庫連接一樣,必需將每個 ESQL 元素都適當(dāng)?shù)厍短自?esql:connection
元素內(nèi)。在單個 XSP 頁面內(nèi)具有多個連接元素是可能的,這樣就允許單個頁面同多個數(shù)據(jù)源交互。連接元素還必須包含定義如何創(chuàng)建數(shù)據(jù)庫連接的其它元素(例如,esql:pool
)。
第一種方法是簡單地引用以前定義的連接池,使用 esql:pool
元素實現(xiàn)這一點:
<esql:connection>
<esql:execute-query>
<esql:pool>myPoolName</esql:pool>
...
</esql:execute-query>
</esql:connection>
第二種方法是直接在 esql:connection
元素內(nèi)定義連接參數(shù)。使用下列元素來實現(xiàn)這一點:
esql:dburl
— JDBC 連接字符串esql:username
— 連接到數(shù)據(jù)庫的用戶名esql:password
— 以上用戶名的密碼esql:driver
— JDBC 驅(qū)動程序esql:autocommit
— 指出應(yīng)當(dāng)自動提交 JDBC 連接
后一種方法的優(yōu)點在于可以動態(tài)生成連接詳細(xì)信息 — 例如,從當(dāng)前會話檢索用戶名和密碼。雖然這樣做提供了極大程度的靈活性,但是也喪失了通過使用數(shù)據(jù)庫池讓 Cocoon 管理連接的性能優(yōu)點。
因此,除非需要這一動態(tài)行為,否則就建議使用 esql:pool
元素定義連接。
2.2、esql:execute-query
esql:execute-query
元素等價于 JDBC PreparedStatement
對象。它定義如何在給定數(shù)據(jù)庫連接內(nèi)執(zhí)行個別查詢以及應(yīng)該如何處理這些查詢的結(jié)果。嵌套個別 esql:execute-query
元素以創(chuàng)建嵌套的數(shù)據(jù)庫查詢是可接受的。
2.3、esql:query
esql:query
元素含有將要使用這一連接執(zhí)行的 SQL 查詢(SELECT、INSERT、UPDATE 或 DELETE)。對查詢結(jié)果的處理取決于執(zhí)行的查詢類型。對 SELECT 語句的處理定義在 esql:results
元素內(nèi),而 INSERT、UPDATE 和 DELETE 的結(jié)果則在 esql:update-results
元素內(nèi)處理。
<esql:query>
select cat_id, name from category
order by cat_id
</esql:query>
2.4、esql:row-results
使用 esql:row-results
元素來定義如何處理查詢結(jié)果中的每一行,該元素是 esql:results
的子元素。該元素的內(nèi)容被轉(zhuǎn)換成由查詢生成的 JDBC ResultSet
中的每一行都執(zhí)行的代碼。
<esql:results>
<esql:row-results>
<category>
<esql:get-columns/>
</category>
</esql:row-results>
</esql:results>
產(chǎn)生下列輸出:
<categories>
<category>
<CAT_ID>1</CAT_ID><NAME>Blues</NAME>
</category>
...more results...
</categories>
2.5、讀方法(getter) 元素
<esql:results>
<esql:row-results>
<category>
...xsp:attribute elements as before...
<xsp:logic>
if (<esql:get-int column="cat_id"/> % 2 == 0)
{
<xsp:attribute name="rowtype">even</xsp:attribute>
}
else
{
<xsp:attribute name="rowtype">odd</xsp:attribute>
}
</xsp:logic>
</category>
</esql:row-results>
</esql:results>
2.6、其它數(shù)據(jù)操作元素
esql:get-column-count
— 返回結(jié)果中列的數(shù)目。請在需要按順序處理列的地方使用該元素來建立循環(huán)。esql:get-metadata
— 返回對ResultSetMetadata
的引用。esql:get-resultset
— 返回對 JDBCResultSet
的引用以供直接操作。esql:get-row-position
— 獲取結(jié)果中當(dāng)前行的位置。請使用該元素來提供表的行數(shù)等功能。esql:get-column-name
— 獲取當(dāng)前列的名稱,必須用該列的位置來引用該列。在按順序處理結(jié)果集中的列時,請使用該元素。esql:is-null
— 測試給定列是否具有 NULL 值。esql:get-xml
— 添加由 JDBCResultSet
提供的功能。檢索指定列的值并將其作為 XML 解析。在解析之前,可以有選擇地將列的值封裝在另一個元素(由root
屬性指定)中。在原始 XML 數(shù)據(jù)存放在數(shù)據(jù)庫中時,請使用該元素。
2.7、處理空結(jié)果和錯誤
前面的這些示例假定查詢總是成功完成并且總是返回結(jié)果。顯然,事情并不總是這樣的:有些查詢可能不返回數(shù)據(jù),也可能發(fā)生數(shù)據(jù)庫錯誤(例如,由于連接故障)。ESQL 邏輯表提供允許您處理這些情形的標(biāo)記。
如果查詢不返回結(jié)果,那么可以通過使用 esql:no-rows
元素來采取行動。
...
<esql:results><results/></esql:results>
<esql:no-results><no-results/></esql:no-results>
...
esql:error-results
元素為處理SQLException
提供了一個鉤接(hook),該異常是在處理查詢結(jié)果期間生成的。
...
<esql:error-results>
<error>
<message><esql:get-message/></message>
<trace><esql:get-stacktrace/></trace>
<string><esql:to-string/></string>
</error>
</esql:error-results>
...
將處理結(jié)果時發(fā)生的異常情形同創(chuàng)建數(shù)據(jù)庫連接或查詢包含語法錯誤時發(fā)生的異常情形區(qū)分開來非常重要。這些更嚴(yán)重的錯誤并不傳遞給 XSP 頁面,而是由 Cocoon 2 自身處理。
2.8、將參數(shù)傳遞給查詢
<esql:query>
select * from album
where cat_id = <xsp-request:get-parameter name="id"/>
</esql:query>
2.9、嵌套查詢
<esql:connection>
<esql:execute-query>
<esql:query/>
<esql:results>
<!-- results from query
one -->
<esql:execute-query>
<esql:query/>
<esql:results>
<!-- results from query
two -->
</esql:results>
</esql:execute-query>
</esql:results>
</esql:execute-query>
</esql:connection>
內(nèi)部查詢引入了一段新 ESQL 語法:
<esql:query>
select alb_id as id, title, artist,
num_tracks as tracks
from album
where cat_id = <esql:get-int column="cat_id" ancestor="1"/>
</esql:query>
在查詢的 WHERE 子句中,esql:get-int
元素用于檢索外部查詢的當(dāng)前類別值。新的 ancestor
元素指示從哪個外面查詢檢索該值 — 例如同第一個 esql:execute-query
ancestor 元素相關(guān)聯(lián)的結(jié)果。
2.10、分組數(shù)據(jù)
esql:group
和esql:member
元素可以利用表連接結(jié)果中的這些模式來將相關(guān)記錄整理在一起。esql:group
元素具有group-on
屬性。該屬性標(biāo)識結(jié)果中可以用來區(qū)別外部元素(換句話就是類別)的列。元素的內(nèi)容定義將對每個不同類別采用的處理,而不是定義對結(jié)果的每一行的處理。esql:member
元素定義對共享由group-on
屬性定義的公共列的每一行的處理。這里,該元素含有建立每個專輯的 XML 結(jié)構(gòu)所需的處理,最終的 XML 結(jié)構(gòu)與嵌套查詢版本生成的結(jié)構(gòu)相同。
<esql:row-results>
<esql:group group-on="cat_id">
<category>
<!-- process category data -->
<albums>
<esql:member>
<album>
<!-- process album data -->
<id><esql:get-string column="alb_id"/></id>
</album>
</esql:member>
</albums>
</category>
</esql:group>
</esql:row-results>
三、表單驗證
3.1描述表單
下面的示例演示了用于描述表單字段、由 Form Validator Action 所支持的 XML 格式的基本語法。
<root>
<!-- field definitions -->
<parameter name="id" type="long"
min="1" max="99999" nullable="no"/>
<parameter name="cat" type="long"
min="1" max="999" nullable="no"/>
<parameter name="title" type="string"
max-len="100" nullable="no"/>
<parameter name="artist" type="string"
max-len="100" nullable="no"/>
<parameter name="tracks" type="long"
max="99" nullable="no"/>
<constraint-set
name="insert-album">
<validate name="id"/>
<validate name="cat"/>
<validate name="title"/>
<validate name="artist"/>
<validate name="tracks"/>
</constraint-set>
</root>
說明:首先,忽略了文檔的根元素,因此它可以具有任何名稱。第二,文檔被分成了兩部分:許多字段定義后跟約束集。
每個字段定義都描述了用戶提交的參數(shù)。參數(shù)都必須有唯一的 name
屬性。字段還必須有類型,類型可以是下列之一:long
、double
或 string
。每個字段接下來可以定義許多指定為附加屬性的驗證規(guī)則:
nullable
— 標(biāo)識字段是否可為空default
— 如果沒有為字段提供值,則標(biāo)識字段的缺省值min
和max
— 表示最小和最大值min-len
和max-len
— 表示最小和最大長度matches-regex
— 定義一個必須正確匹配參數(shù)值的 POSIX 正則表達式;這允許更豐富的內(nèi)容驗證,例如電子郵件地址格式
約束集描述了預(yù)定義字段的組合,對這些字段進行驗證將一遍完成,如下面所描述。約束集中的 validate
元素支持兩種附加屬性:
equals-to
— 定義參數(shù)必須匹配的固定字符串equals-to-param
— 定義另一個應(yīng)該具有相同值的參數(shù)的名稱,該參數(shù)可以完成一些功能,例如檢查用戶是否在一個驗證新密碼的表單上兩次都輸入了相同的密碼。
3.2、驗證字段
3.2.1站點地圖中對它加以聲明
同任何其它 Cocoon 2 組件一樣,在可以使用 Form Validator Action 以前,必須首先在站點地圖中對它加以聲明:
<map:components>
...
<map:actions>
<map:action name="form-validator"
src="org.apache.cocoon.acting.FormValidatorAction"/>
</map:actions>
...
</map:components>
3.2.2向 Cocoon 2 管道添加操作
<map:match pattern="form/insert-album">
<map:act type="form-validator">
<map:parameter name="descriptor"
value="context://insert-album.xml"/>
<map:parameter name="validate-set"
value="insert-album"/>
<!-- if success -->
...
</map:act>
<!-- if fail -->
...
</map:match>
如果驗證成功,則處理 map:act
元素內(nèi)的其它管道組件。就是在這里調(diào)用 insert-album.xsp
,XSP 頁面以插入已知有效的數(shù)據(jù)。
如果驗證不成功,則只執(zhí)行 map:act
元素后面的組件。這樣,Actions 的行為類似于“if”語句:如果它們成功地執(zhí)行了它們的處理,那么將執(zhí)行嵌套在它們之內(nèi)的管道組件塊;否則,就跳過該塊。
3.2.3、使用 Form Validator 邏輯表
您只可以將 Form Validator 邏輯表同 Form Validator Action 一起使用。該邏輯表通常在 XSP 頁面內(nèi)使用,如果表單未能被驗證,就執(zhí)行該頁面。操作將其結(jié)果的詳細(xì)分解作為 HTTP 請求參數(shù)存儲。這一邏輯表為解釋這些結(jié)果提供了一個簡單的基于標(biāo)記的 API。
這一邏輯表的名稱空間是 http://apache.org/xsp/form-validator/2.0
。
下列來自邏輯表的每一元素都接受 name
屬性,該屬性表示正在測試驗證狀態(tài)的字段的名稱。
formval:is-ok
— 返回一個指示字段驗證是否成功的布爾值formval:is-null
— 在字段本不該為空時表示該字段為空formval:is-toosmall
— 表示字段長度比min-len
短或值比min
小formval:is-toolarge
— 表示字段長度比max-len
長或值比max
大formval:is-nomatch
— 表示字段未能匹配所配置的正則表達式
Q : org.apache.avalon.framework.configuration.ConfigurationException: No default type exists for 'pipeline' at file:/C:/code/tech/web/sitemap.xmap………
A: The samples sitemaps are sub sitemaps and inherit the pipelines configuration form the root sitemap. Their you will find a map:pipes with a default type configured.
Q: Caused by: org.xml.sax.SAXParseException: The reference to entity "password" must end with the ';' delimiter.
A: “ jdbc:mysql://192.168.0.1:3306/school?useUnicode=true&characterEncoding=GB2312 “ 中的"&"必須用它的轉(zhuǎn)義字符&
Q: Communication failure during handshake. Is there a server running on localhost:3306?
A: 嘗試下一個新版本的驅(qū)動:http://dev.mysql.com/downloads/
Class.forName("org.gjt.mm.mysql.Driver") 可以嘗試換成
Class.forName("com.mysql.jdbc.Driver")
PS: 暈菜,被這個問題搞了兩個小時。在這之前mysql和jdbc連接一直是可以用的,不過前幾天升級了一下mysql,但版本差別不大,版本號前面都有一個5。另外因為是第一次在cocoon配置,以為是配置文件搞錯了,就在那里瞎折騰。到最后,才決定要看看究竟是不是mysql的JDBC驅(qū)動版本引起的,就寫了一個簡單的JSP測試頁,結(jié)果竟然連接不成功,出現(xiàn)如上提示