??所以,你可以先定義一些商務(wù)API(business API),這些API就是簡單的Java類。你可以傳遞一些參數(shù)給這些對象,并從這些對象返回一個Java Bean或者Java Bean的集合。這個Action類負(fù)責(zé)調(diào)用這些對象,并把它們返回的值傳遞給web/表示層。
??通常,你可以為每一個你需要調(diào)用的商務(wù)方法/商務(wù)類API創(chuàng)建一個Action類。理想情況下,所有的數(shù)據(jù)庫訪問代碼都被封裝進(jìn)了這些商務(wù)API類里,所以Struts并不知道你正在使用的持久層(persistent layer)(甚至都不知道你使用了持久層)。它只需要傳遞一個主鍵(Key)或者一個查詢參數(shù),然后處理返回的結(jié)果bean或者bean集合。這樣,你就可以在其他的應(yīng)用環(huán)境里復(fù)用這些商務(wù)API類,你還可以對這些獨立于Struts或HTTP環(huán)境的商務(wù)API進(jìn)行單體測試。
??開始的時候,最簡單的方法就是設(shè)計一個1:1的方案,為你的每一個商務(wù)API入口(entry-point)定義一個Action類。當(dāng)你的經(jīng)驗豐富了以后,你也可以使用DispatchAction組合這些Action類。你甚至可以定義一個簡單的"框架"Action,用來調(diào)用所有的這些商務(wù)類。你可以在contrib目錄里找到Scaffold設(shè)計的ProcessAction,這是一個"框架"Action的完整實現(xiàn)。使用這種方案可以使用更少的Action類,但你必須對Struts和MVC框架的底層實現(xiàn)有較深的理解。不要害怕在開始的時候定義過多的Action,Struts的配置方案可以給予你充分的自由在以后重構(gòu)你的設(shè)計,因為你可以靈活的改變你的Action類,而不會對應(yīng)用程序造成影響。
??在理想情況下,商務(wù)邏輯層(business logic layer)應(yīng)該封裝所有的數(shù)據(jù)訪問細(xì)節(jié),包括數(shù)據(jù)庫連接的獲得。但是,一些應(yīng)用程序的設(shè)計要求調(diào)用者可以從一個DataSource對象來獲得數(shù)據(jù)庫連接。遇到這種情況時,Struts DataSource管理器可以使你在需要的時候配置這些DataSource資源。
??Struts DataSource管理器在Struts配置文件(Struts-config.xml)里定義。這個管理器可以用來分發(fā)和配置任何實現(xiàn)了javax.sql.DataSource接口的數(shù)據(jù)庫連接池(connection pool)。如果你的DBMS或者容器內(nèi)置了符合這些要求的連接池,你可以優(yōu)先選用它。
[Jakarta的公共連接池實現(xiàn) - BasicDataSource]
??如果你的手頭沒有連接池的本地(native)實現(xiàn),你可以使用Jakarta提供的公共連接池實現(xiàn)[org.apache.commons.dbcp.BasicDataSource],它可以和DataSource管理器"合作"的很好。另外,Struts還在它的util包里包含了一個GenericDataSource類,這也是一個連接池實現(xiàn)。但是這只是一個非常簡單的實現(xiàn)方案,不推薦使用,因為它可能在Struts的以后版本中被BasicDataSource或其它的數(shù)據(jù)源實現(xiàn)替換掉。
??下面是一段Struts-config.xml配置文件中的數(shù)據(jù)源配置(使用GenericDataSource數(shù)據(jù)源實現(xiàn)),你可以更改相應(yīng)的設(shè)置以適合你自己的系統(tǒng)。
<!-- configuration for GenericDataSource wrapper -->
<data-sources>
???????? <data-source>
?????????? <set-property
???????????????? property="autoCommit"
???????????????? value="false"/>
?????????? <set-property
???????????????? property="description"
???????????????? value="Example Data Source Configuration"/>
?????????? <set-property
???????????????? property="driverClass"
???????????????? value="org.postgresql.Driver"/>
?????????? <set-property
???????????????? property="maxCount"
???????????????? value="4"/>
?????????? <set-property
???????????????? property="minCount"
???????????????? value="2"/>
?????????? <set-property
???????????????? property="password"
???????????????? value="mypassword"/>
?????????? <set-property
???????????????? property="url"
???????????????? value="jdbc:postgresql://localhost/mydatabase"/>
?????????? <set-property
???????????????? property="user"
???????????????? value="myusername"/>
???????? </data-source>
</data-sources>
使用BasicDataSource數(shù)據(jù)源實現(xiàn)的配置方案如下:
<data-sources>
????????<!-- configuration for commons BasicDataSource -->
????????<data-source type="org.apache.commons.dbcp.BasicDataSource">
????????????????<set-property
??????????????????property="driverClassName"
??????????????????value="org.postgresql.Driver" />
????????????????<set-property
??????????????????property="url"
??????????????????value="jdbc:postgresql://localhost/mydatabase" />
????????????????<set-property
??????????????????property="username"
??????????????????value="me" />
????????????????<set-property
??????????????????property="password"
??????????????????value="test" />
????????????????<set-property
??????????????????property="maxActive"
??????????????????value="10" />
????????????????<set-property
??????????????????property="maxWait"
??????????????????value="5000" />
????????????????<set-property
??????????????????property="defaultAutoCommit"
??????????????????value="false" />
????????????????<set-property
??????????????????property="defaultReadOnly"
??????????????????value="false" />
????????????????<set-property
??????????????????property="validationQuery"
??????????????????value="SELECT COUNT(*) FROM market" />
????????</data-source>
</data-sources>
??注意,你可以在你的應(yīng)用系統(tǒng)中定義不止一個數(shù)據(jù)源,你可以根據(jù)需要定義多個數(shù)據(jù)源,并為它們分別起一個邏輯名(logical name)。這樣做可以給你的應(yīng)用系統(tǒng)提供更好的安全性和可測量性(scalability),你還可以定義一個專用于測試的數(shù)據(jù)源。
??配置好DataSource以后,你就可以在你的應(yīng)用系統(tǒng)中使用這些數(shù)據(jù)源了。下面這段代碼演示了怎樣在Action類的execute方法中通過這些數(shù)據(jù)源來生成數(shù)據(jù)庫連接。
需要3個包(別忘了數(shù)據(jù)庫驅(qū)動包)
commons-collections-3.1.jar
commons-dbcp-1.2.1.jar
commons-pool-1.2.jar
public ActionForward execute(
????????ActionMapping mapping,
????????ActionForm form,
????????HttpServletRequest request,
????????HttpServletResponse response)
????????throws Exception
{
????????DataSource dataSource;
????????Connection cnn;
????????try
????????{
????????????????dataSource = getDataSource(request);
????????????????cnn = dataSource.getConnection();
????????????????// 數(shù)據(jù)連接已經(jīng)建立了,你可以做你想做的事情了
????????}
????????catch (SQLException e)
????????{
????????????????getServlet().log("處理數(shù)據(jù)庫連接", e);
????????}
????????finally
????????{
????????????????// 在finally塊里包含這些代碼
????????????????// 用以保證連接最后會被關(guān)閉
????????????????try
????????????????{
????????????????????????cnn.close();
????????????????}
????????????????catch (SQLException e)
????????????????{
????????????????????????getServlet().log("關(guān)閉數(shù)據(jù)庫連接", e);
????????????????}
????????}
}
??注意:如果你使用公共的BasicDataSource,你提供給pingQuery屬性的查詢語句(如果你設(shè)置了話)必須至少要能返回一行記錄。
例子:SELECT COUNT(*) FROM VALIDTABLE
你可以把VALIDTABLE替換成你的數(shù)據(jù)庫中包含的任何有效的表。
數(shù)據(jù)庫連接字符串
SQLServer2000:
??driverClassName:com.microsoft.jdbc.sqlserver.SQLServerDriver
??url:?jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=databasename
MySql:
???driverClassName:com.mysql.jdbc.Driver
??url:?jdbc:mysql://localhost/databasename
[使用多個數(shù)據(jù)源]
如果你需要在模塊(Module)中使用多于一個的數(shù)據(jù)源,你可以在配置文件的<data-source>元素里包含一個key屬性。
<data-source>
????????<data-source key="A" type="org.apache.commons.dbcp.BasicDataSource">
????????????????…屬性配置略, 同上…
????????</data-source>
????????<data-source key="B" type="org.apache.commons.dbcp.BasicDataSource">
????????????????…屬性配置略, 同上…
????????</data-source>
</data-source>
你代碼里,你可以通過這些key獲得不同的數(shù)據(jù)源。代碼如下:
…
try
{
????????dataSourceA = getDataSource(request, "A");
????????dataSourceB = getDataSource(request, "B");
…
你可以根據(jù)需要為每一個模塊設(shè)置多個數(shù)據(jù)源。但同一模塊里每個數(shù)據(jù)源的key屬性必須唯一,因為Struts模塊系統(tǒng)是以每一個模塊為單位管理命名空間的。