關(guān)于 AppFuse 的特性、架構以及為什么要使用 AppFuse,AppFuse 的創(chuàng )始人 Matt Raible 在 《使用 AppFuse 的七個(gè)理由》一文中已經(jīng)做了很詳盡的闡述,這里就不再贅言。本文將著(zhù)力于實(shí)踐,即如何運用 AppFuse 開(kāi)發(fā) J2EE 應用。
使用 AppFuse,你需要對 Ant 有一些基本的了解,比如什么叫 target、什么是 build.xml 以及如何運行 Ant,等等。如果你現在還不知道 Ant 是什么,就需要找些相關(guān)資料學(xué)習一下。下表列出了本文中用到的也是較為常用的 AppFuse 的 target:
表 1. Ant 中常用的 AppFuse target | target | 說(shuō)明 | 所在文件 |
| new | 這個(gè) target 是使用 AppFuse 必須要用到的,它用來(lái)在 AppFuse 同級的目錄下創(chuàng )建一個(gè)新項目。創(chuàng )建過(guò)程是交互式的,會(huì )讓用戶(hù)輸入項目名稱(chēng)、數據庫名稱(chēng)以及根包路徑。 | AppFuse 安裝目錄下的 build.xml |
| setup | 用于初始化一個(gè)新的項目,它包含了從數據庫創(chuàng )建、Tomcat 設置到 war 文件的生成和部署等一系列操作。 | 項目根目錄下的 build.xml |
| deploy | 如果你修改的代碼不涉及到數據庫的更改,那么可以使用這個(gè) target,因為它只負責生成并重新部署 war 包。 | 項目根目錄下的 build.xml |
| setup-db | 如果你只是要對數據庫進(jìn)行更改,使用這個(gè) target。比如,重新創(chuàng )建數據庫,重新加載樣本數據等操作。 | 項目根目錄下的 build.xml |
| install | AppGen 的 target。如果你不希望使用 AppGen 幫你生成 dao 類(lèi)和 service 類(lèi)以及其他的代碼,就使用這個(gè) target。 | extras/appgen 目錄下的 build.xml |
| install-detailed | AppGen 的 target。如果你希望使用 AppGen 幫你生成所有代碼,就使用這個(gè) target。 | extras/appgen 目錄下的 build.xml |
本文將按如下順序展開(kāi)敘述:
- 示例介紹
- 搭建開(kāi)發(fā)環(huán)境
- 新建項目
- 創(chuàng )建數據庫表
- 用 AppGen 生成代碼
- 根據項目需求調整代碼
- 其他功能
- 語(yǔ)言國際化
- 頁(yè)面布局和樣式
- 系統安全
- 事務(wù)控制
- 日志
- 郵件
- 緩存
示例介紹
本文的示例實(shí)現對員工信息的增刪查改等基本功能。用 Tapestry 實(shí)現表示層,用 Hibernate 開(kāi)發(fā)持久層,用 Spring 提供事務(wù)控制等跨模塊服務(wù),并用 Acegi 進(jìn)行安全管理。本示例只用到一個(gè)域模型:Employee,下面是它的 UML 圖。
圖 1. Employee UML 圖 搭建開(kāi)發(fā)環(huán)境
本文的代碼開(kāi)發(fā)平臺采用的是 Windows 操作系統,因此,以下環(huán)境設置也是針對 Windows 操作系統的。
- 從 AppFuse 下載頁(yè)面 下載 appfuse-tapestry-1.9.3-src.zip,并解壓縮在任意目錄下。這個(gè) zip 已經(jīng)定制了使用 Tapestry 作為表現層的實(shí)現框架,因而使用起來(lái)較為直接。
- 從 http://java.sun.com 下載最新的 JDK,并安裝或解壓縮到任意目錄下。本文采用 JDK 1.5.0。設置環(huán)境變量 JAVA_HOME 指向 JDK 所在的目錄,并在 PATH 中添加 %JAVA_HOME%/bin。
- 從 http://jakarta.apache.org/tomcat 下載最新版的 Tomcat,并安裝或解壓縮到任意目錄下。本文采用 Tomcat 5.5.17。設置環(huán)境變量 CATALINA_HOME 指向 Tomcat 的安裝目錄。
- 從 http://ant.apache.org下載最新版的 Ant,并解壓縮到任意目錄下。AppFuse 要求的最低版本是 1.6.2,本文采用的是 1.6.5。設置 ANT_HOME 指向 Ant 所在的目錄,并在 PATH 中添加 %ANT_HOME%/bin。另外,要拷貝一個(gè) junit.jar 到 %ANT_HOME%/lib 下,如果 lib 下沒(méi)有 junit.jar,AppFuse 的腳本在運行時(shí)會(huì )給出警告信息。junit.jar 可以從 http://www.junit.org 獲得,也可以從 %AppFuse%/lib/junit3.8.1 目錄下獲得。
- 從 http://www.mysql.com 下載最新版的 MySQL,并安裝或解壓縮到任意目錄下。本文采用的是 5.0。
- 從 http://www.eclipse.org 下載 Eclipse 3.1 或 3.2,安裝到任意目錄下。
AppFuse 的 Ant 腳本可以在命令行中運行,也可以在 Eclipse 里運行。有關(guān)如何在 Eclipse 里執行 Ant 腳本,請參考《用Eclipse開(kāi)發(fā)AppFuse應用》。到此,我們已經(jīng)為 AppFuse 開(kāi)發(fā)應用準備好了環(huán)境,下面讓我們開(kāi)始使用 AppFuse 創(chuàng )建項目。
新建項目
AppFuse 的便捷與強大之處在于它已經(jīng)為我們提供了多種開(kāi)源框架的集成,并且通過(guò)使用 Ant 將所有的構建過(guò)程自動(dòng)化。另外,AppFuse 利用 XDoclet 能夠為我們生成絕大多數重要的代碼,例如 dao 類(lèi)、service 類(lèi)以及測試用例,等等,并且能夠將大量的配置文件也一并生成好,從而極大地節省了開(kāi)發(fā)人員的時(shí)間。
用 AppFuse 進(jìn)行開(kāi)發(fā)通常有三種模式:“自上而下”,“自下而上”以及“混合模式”。采用“自上而下”(由 Java 對象向數據庫對象創(chuàng )建的過(guò)程)的方式固然比較符合“面向對象”的設計思維,但是為此要編寫(xiě)大量的 XDoclet 的 tag 也確是一件痛苦的事情。相比較而言,采用“自下而上”(由數據庫對象生成 Java 對象的過(guò)程)就顯得簡(jiǎn)單許多 -- 只需要提供數據庫表結構。然而,對于較為復雜的系統,尤其是類(lèi)之間具有大量的關(guān)聯(lián)的情形,仍然需要采用“自上而下”的創(chuàng )建模式。因此,在實(shí)際的項目開(kāi)發(fā)中,將兩種模式進(jìn)行混合使用比較常見(jiàn),這也就是“混合”模式。本文采用“自下而上”的模式。
本文的 AppFuse 安裝在 "c:\opt" 下面。打開(kāi)命令行控制臺,進(jìn)入 "c:\opt\appfuse",運行 “ant new”,為簡(jiǎn)單起見(jiàn),所有參數選用默認值,見(jiàn)圖 2。
圖 2. ant new -- 新建項目 腳本運行成功后,新項目創(chuàng )建在 c:\opt\myapp 下(與 AppFuse 目錄同級),myapp 是 AppFuse 默認的項目名稱(chēng)。將該項目導入到 Eclipse 中,并根據 《用Eclipse開(kāi)發(fā)AppFuse應用》 進(jìn)行必要的設置。以下是兩個(gè)你可能需要進(jìn)行的配置:
- AppFuse 默認連接 MySQL 的用戶(hù)名是 root,密碼為空。如果你的 root 密碼不是空,需要修改 C:\opt\myapp\build.properties 中的 database.admin.password 項,記得將注釋去掉。
- AppFuse 默認不是用 utf-8 創(chuàng )建數據庫,如果你需要支持多語(yǔ)言,需要修改 C:\opt\myapp\metadata\sql\mysql-create.sql 中的創(chuàng )建數據庫的語(yǔ)句,修改如下:
清單 1. 創(chuàng )建數據庫語(yǔ)句
create database if not exists @DB-NAME@ CHARACTER SET utf8 COLLATE utf8_general_ci; |
注:AppFuse 會(huì )在構建期將 @DB-NAME@ 替換成你指定的數據庫名(本文中為“mydb”)。
在 c:\opt\myapp 下運行“ant setup test-all”。“setup” 完成了很多“設置”工作:創(chuàng )建數據庫、構建 dao 和 serive 類(lèi)、加載樣本數據、創(chuàng )建 war 文件并部署到 tomcat,等等。“test-all” 運行所有的測試用例:對 dao,service 以及頁(yè)面的測試。如果這個(gè)腳本運行成功,說(shuō)明開(kāi)發(fā)環(huán)境一切就緒。這時(shí),啟動(dòng) Tomcat,通過(guò)訪(fǎng)問(wèn) http://localhost:8080/myapp 就能夠看到 AppFuse 的登錄界面了。AppFuse 預定義了兩個(gè)用戶(hù):mraible 和 tomcat,密碼都是 tomcat。mraible 屬于管理員角色(能夠管理用戶(hù)信息),tomcat 屬于普通用戶(hù)角色。用 mraible 登錄可以看到 圖 3的界面。
圖 3. AppFuse 的初始界面 或許此時(shí),你已驚奇地發(fā)現,自己不過(guò)只運行了一次 Ant 腳本,但是系統已經(jīng)擁有“用戶(hù)管理”、“郵件”、“文件上傳” 等功能 -- 這就是 AppFuse “開(kāi)箱即用”的優(yōu)勢。接下來(lái)讓我們開(kāi)始開(kāi)發(fā)前述的應用示例。
創(chuàng )建數據庫表
在 mydb 數據庫中執行如下語(yǔ)句創(chuàng )建 employee 表:
清單 2. 創(chuàng )建 employee 語(yǔ)句 CREATE TABLE `employee` ( `id` bigint(20) NOT NULL auto_increment, `code` varchar(10) NOT NULL, `dept` varchar(50) NOT NULL, `name` varchar(20) NOT NULL, `status` varchar(10) NOT NULL, `telephone` varchar(20) default NULL, `title` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
用 AppGen 生成代碼
AppFuse 自帶了一個(gè)代碼生成工具 -- AppGen,它位于 c:\opt\myapp\extras\appgen 目錄下面。AppGen 可以生成絕大部分我們需要的代碼,比如 dao 類(lèi),service 類(lèi),菜單、增刪改的 web 頁(yè)面、配置文件、樣本數據,等等。AppGen 利用 XDoclet 生成代碼,因此可以在 extras/appgen/src 看到很多 .xdt 文件,這些就是 XDoclet 的模版定義文件。如果你希望自己編寫(xiě) dao 和 service 類(lèi),就運行“install”這個(gè) target,否則就用 “install-detailed” ,它可以幫你搞定一切。下面就讓我們來(lái)運行 “install-detailed” 生成代碼。在 c:\opt\myapp\extras\appgen 下運行 “ant install-detailed”。
清單 3. 運行 install-detailed ... [input] Would you like to generate code from a table or POJO? (table,pojo) table [input] What is the name of your table (i.e. person)? employee [input] What is the name, if any, of the module for your table (i.e. organization)? hr ... |
前兩個(gè)問(wèn)題都很直觀(guān):選擇從 table 生成代碼,表名是 employee。第三個(gè)問(wèn)題是讓用戶(hù)輸入使用的模塊名,如果你希望 AppFuse 幫你按模塊生成代碼的話(huà),就需要輸入一個(gè)模塊名稱(chēng)。這里,我們輸入“hr”。如果運行成功,在 Eclipse 中會(huì )看到如下的目錄結構:
圖 4. “install-detailed” 執行后的 Eclipse 表 2 列出了 "install-detailed" 生成的主要文件。
表 2. "install-detailed" 生成的主要文件列表 | 文件 | 說(shuō)明 |
| myapp/src/dao/org/appfuse/dao/hibernate/applicationContext-hibernate.xml | 在其中增加了 employeeDao 的聲明 |
| myapp/src/dao/org/appfuse/hr/model/Employee.java | Employee 類(lèi) -- Java Bean |
| myapp/build/dao/gen/org/appfuse/hr/model/Employee.hbm.xml | Employee 類(lèi)的 Hibernate 映射文件 |
| myapp/src/dao/org/appfuse/hr/dao/EmployeeDao.java | 定義關(guān)于 employee 的 dao 層的操作 |
| myapp/src/dao/org/appfuse/hr/dao/hibernate/EmployeeDaoHibernate.java | EmployeeDao 的 Hibernate 實(shí)現類(lèi) |
| myapp/src/service/org/appfuse/service/applicationContext-service.xml | 在其中增加了employeeManager的聲明 |
| myapp/src/service/org/appfuse/hr/service/EmployeeManager.java | 定義關(guān)于 employee 的 service 層的操作 |
| myapp/src/service/org/appfuse/hr/service/impl/EmployeeManagerImpl.java | EmployeeManager 的實(shí)現類(lèi) |
| myapp/src/web/org/appfuse/hr/webapp/action/EmployeeForm.java | employee 的添加/修改頁(yè)面對應的 tapestry 類(lèi) |
| myapp/src/web/org/appfuse/hr/webapp/action/EmployeeList.java | employee 的列表頁(yè)面對應的 tapestry 類(lèi) |
| myapp/test/dao/org/appfuse/hr/dao/EmployeeDaoTest.java | employee dao 類(lèi)的測試用例 |
| myapp/test/service/org/appfuse/hr/dao/EmployeeManagerTest.java | employee service 類(lèi)的測試用例 |
| myapp/test/web/org/appfuse/hr/webapp/action/EmployeeFormTest.java | employee 添加/修改頁(yè)面類(lèi)的測試用例 |
| myapp/test/web/org/appfuse/hr/webapp/action/EmployeeFormTest.java | employee 列表頁(yè)面類(lèi)的測試用例 |
| myapp/web/pages/hr/employeeForm.html | employee 添加/修改頁(yè)面 html 模版文件 |
| myapp/web/pages/hr/employees.html | employee 列表頁(yè)面 html 模版文件 |
| myapp/web/pages/hr/employeeForm.page | employee 添加/修改頁(yè)面規格文件 |
| myapp/web/pages/hr/employees.page | employee 列表頁(yè)面規格文件 |
不過(guò),AppFuse 并不知道開(kāi)發(fā)者需要加載哪些 hbm 文件,所以要手工將 Employee.hbm.xml 文件添加到配置文件中:打開(kāi) applicationContext-hibernate.xml,在 “sessionFactory” 的 bean 聲明中,找到 “mappingResources” 屬性的定義,增加 “<value>org/appfuse/hr/model/Employee.hbm.xml</value>”。
清單 4. applicationContext-hibnerate.xml 中添加 Employee.hbm.xml ... <beans> <!-- Hibernate SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> |-------- XML error: The previous line is longer than the max of 90 characters ---------| <property name="dataSource" ref="dataSource"/> <property name="mappingResources"> <list> <value>org/appfuse/hr/model/Employee.hbm.xml</value> <value>org/appfuse/model/Role.hbm.xml</value> <value>org/appfuse/model/User.hbm.xml</value> </list> </property> ... |
在 c:\opt\myapp 下運行 “ant deploy”。打開(kāi) “http://localhost:8080/myapp”,用 mraible/tomcat 登錄,“Employee List” 已經(jīng)被添加到菜單里了。
圖 5. myapp 的原始主頁(yè)面 點(diǎn)擊 “Employee List” 鏈接,進(jìn)入“員工信息列表”頁(yè)面。
圖 6. myapp 的原始員工信息列表頁(yè)面 點(diǎn)擊“添加”按鈕或點(diǎn)擊任意一行數據,進(jìn)入“員工信息添加/修改/刪除”頁(yè)面。
圖 7. myapp 的原始員工信息添加/修改/刪除頁(yè)面 不難看出,雖然 AppFuse 幫我們生成了頁(yè)面,但是這些頁(yè)面并非那么“理想”,我們仍然需要根據實(shí)際的需求做些調整。
根據項目需求調整代碼
在本文中,做了如下代碼修改:
- 將所有頁(yè)面文字翻譯成中文:AppFuse 中用到的所有 Resource Bundle 文件位于 myapp/web/WEB-INF/classes 目錄下(以ApplicationResources開(kāi)頭的properties文件)。更改 ApplicationResources_zh_CN.properties 的文件編碼方式為“UTF-8”。然后,把 ApplicationResources.properties 中 “# -- Employee-START” 和 “# -- Employee-END” 之間的項拷貝到 ApplicationResources_zh_CN.properties 中,并逐項翻譯成中文。AppFuse 會(huì )在腳本運行的時(shí)候自動(dòng)用 native2ascii 進(jìn)行編碼轉換。另外,AppFuse 默認對 “button.done” 的翻譯是“做”,這不太合適,所以改為“完成”。
- 在“員工信息列表頁(yè)面”去掉了 id 列,并調整了列的順序:只要修改 employees.html 就可以。
- 在“員工信息添加/修改/刪除頁(yè)面”,將“所在部門(mén)”、“職位”、“狀態(tài)”改為下拉列表:需要修改 employeeForm.html、employeeForm.page、EmployeeForm.java。用 PropertySelection 組件實(shí)現下拉列表,用 Resource Bundle 文件定義真正顯示的選項文本。
- 增加了一個(gè)“人事管理”的角色,用來(lái)執行員工信息管理的權限控制:具體介紹見(jiàn)“系統安全”。
- 添加了一個(gè)新的主題 “mytheme”(只是更改了界面的顏色):具體介紹見(jiàn)“頁(yè)面布局和樣式”。
應用了上述修改后,在 c:\opt\myapp 中運行 “ant deploy” 重新打包整個(gè)項目并發(fā)布。以下是修改后的界面截圖:
圖 8. 修改后的 myapp 主頁(yè)面 圖 9. 修改后的 myapp 員工信息列表頁(yè)面 圖 10. 修改后的 myapp 員工信息添加/修改/刪除頁(yè)面 圖 11. 修改后的 myapp 用戶(hù)管理頁(yè)面 其他功能
一個(gè)系統除了包含核心邏輯之外,還有其他一些輔助功能,它們也是非常重要的。下面,讓我們來(lái)看看如何在 AppFuse 中開(kāi)發(fā)這些功能。
語(yǔ)言國際化
如果你的系統不僅僅支持一種語(yǔ)言,那么就需要考慮這個(gè)問(wèn)題。在 AppFuse 中,Resource Bundle 文件是位于 web\WEB-INF\classes 目錄下的以 ApplicationResources 開(kāi)頭的 properties 文件。Tapestry 有自己的國際化文本機制。但是在 AppFuse 中,并不全是 Tapestry 頁(yè)面,仍有些地方使用 jsp,而這些頁(yè)面使用 JSTL 的 fmt 標簽顯示國際化文本。不過(guò),AppFuse 已經(jīng)將這二者的“源頭”進(jìn)行了整合,因此,對用戶(hù)而言,只需要在 ApplicationResources*.properties 中定義需要國際化的文本。
但是,在 Eclipse 中可以看到,AppFuse 的 properties 文件默認的編碼不是 UTF-8,而是 ISO-8859-1,這樣會(huì )導致最后通過(guò) native2ascii 轉換后的文件都是 “???”,所以用戶(hù)需要自己把這些文件轉成 UTF-8。轉換的方法很簡(jiǎn)單:在 properties 文件上點(diǎn)右鍵,在右鍵菜單上選擇 Properties,打開(kāi)屬性窗口后,更改 “Text file encoding” 為 UTF-8。在修改編碼前,最好先把已有的文字拷貝出來(lái),轉換好之后再粘貼回去,否則會(huì )導致原先翻譯好的文字變成亂碼。
圖 12. ApplicationResources_zh_CN.properties 的屬性窗口 AppFuse 在發(fā)布項目的時(shí)候,會(huì )自動(dòng)用 native2ascii 轉換這些資源文件。如果你想使用其他資源文件名,可以修改 web\WEB-INF\web.xml 中的 “javax.servlet.jsp.jstl.fmt.localizationContext” 的參數值。
頁(yè)面布局和樣式
使用 AppFuse,能夠很方便的修改系統的整體布局和樣式,因為 AppFuse 使用了一種強大的 “CSS框架”。項目創(chuàng )建好之后,在 web\styles 目錄下,有三個(gè)目錄:andreas01,puzzlewithstyle 和 simplicity。這些是 AppFuse 自帶的三種主題,目錄名即 CSS 框架的主題名。屬于“管理員”角色的用戶(hù)可以在登錄后通過(guò)在 url 后面添加形如 "?theme=andreas01" 的參數更改系統使用的主題。如下圖:
圖 13. 應用了 “puzzlewithstyle” 的 myapp 系統默認使用的主題由 web\WEB-INF\web.xml 中的 “theme” 參數指定,AppFuse 默認使用的主題是 “simplicity”。更改或創(chuàng )建新的主題也很簡(jiǎn)單,只要在 web\styles 目錄下,新建一個(gè)自己的目錄,并參照已有主題的編寫(xiě)規范定義自己的主題。本文中,拷貝了 simplicity 目錄,更名為 “mytheme”,然后將里面的字體顏色從“藍色”基調改成了“綠色”基調,并修改 web.xml 中的 theme 參數值為 “mytheme”,這樣 myapp 默認使用的就是 mytheme 的主題了,如圖 8所示。你也可以從 http://css.appfuse.org/themes/ 得到更多關(guān)于 “CSS框架” 的信息。
系統安全
AppFuse 使用 Acegi 進(jìn)行安全管理。Acegi 的配置信息位于 web\WEB-INF\classes\security.xml。事實(shí)上,Acegi 是被集成到 Spring 當中的,因此這個(gè)文件是 Spring 的配置文件格式。在 web\WEB-INF\web.xml 中,該文件被指定在應用啟動(dòng)前會(huì )被加載:
清單 5. web.xml 關(guān)于 Spring 配置文件的定義 ... <!-- Context Configuration locations for Spring XML files --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext-*.xml,/WEB-INF/security.xml</param-value> </context-param> ... |
本文關(guān)于系統安全的實(shí)現如下:
- 在數據庫中增加新的角色“hr”:編輯 myapp\metadata\sample-data.xml 文件,增加如下黑體的部分:
清單 6. sample-data.xml 中角色 “hr” 的記錄
... <table name=‘role‘> <column>id</column> <column>name</column> <column>description</column> <row> <value>1</value> <value>admin</value> <value><![CDATA[Administrator role (can edit Users)]]></value> </row> <row> <value>2</value> <value>user</value> <value><![CDATA[Default role for all Users]]></value> </row> <row> <value>3</value> <value>hr</value> <value><![CDATA[Role for employee mangement]]></value> </row> </table> ... |
AppFuse 使用 dbunit 加載樣本數據到數據庫中,sample-data.xml 為 dbunit 提供樣本數據定義。修改完 sample-data.xml,在 c:\opt\myapp\ 下運行 “ant db-load”,樣本數據被重新加載。這樣,我們就在數據庫中定義了一個(gè)新的角色記錄 “hr”。 - 定義角色名稱(chēng)的中文顯示文本:在 myapp/sr/web/webapp/action/UserForm.java 的方法 pageBeginRender 中找到如下代碼:
// initialize drop-downs if (getAvailableRoles() == null) { List roles = (List) getServletContext().getAttribute(Constants.AVAILABLE_ROLES); setAvailableRoles(new RoleModel(roles)); } |
將其做如下修改: // initialize drop-downs if (getAvailableRoles() == null) { List roles = (List) getServletContext().getAttribute(Constants.AVAILABLE_ROLES); for(int i=0;i<roles.size();i++){ LabelValue role=(LabelValue) roles.get(i); role.setLabel(getText("rolelabel_"+role.getValue())); } setAvailableRoles(new RoleModel(roles)); } |
并在 web\WEB-INF\classes\ApplicationResources_zh_CN.properties 中增加角色名稱(chēng)的定義: rolelabel_admin=系統管理員 rolelabel_user=普通用戶(hù) rolelabel_hr=人事管理 |
AppFuse 默認在用戶(hù)管理界面上顯示的角色的名稱(chēng)是表 role 中的名稱(chēng),這樣無(wú)論切換到何種語(yǔ)言,角色名稱(chēng)都是 “admin”、"user"、“hr” 等等,角色名稱(chēng)不能根據 Locale 用相應的語(yǔ)言顯示。因此,本文將角色的名稱(chēng)用 Resource Bundle 文件定義,數據庫中存儲 “key” 值。修改后的效果見(jiàn) 圖 10。 - 配置“安全策略”:在 web\WEB-INF\security.xml 的 bean "filterInvocationInterceptor" 聲明中增加如下“黑體”的一行:
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager"/> <property name="accessDecisionManager" ref="accessDecisionManager"/> <property name="objectDefinitionSource"> <value> PATTERN_TYPE_APACHE_ANT /clickstreams.jsp*=admin /flushCache.*=admin /passwordHint.html*=ROLE_ANONYMOUS,admin,user /reload.*=admin /signup.html*=ROLE_ANONYMOUS,admin,user /users.html*=admin /employees.html*=hr /**/*.html*=admin,user </value> </property> </bean> |
“/employees.html*=hr” 的意思是:只有 hr 這個(gè)角色可以訪(fǎng)問(wèn)形如 “/employees.html*” 的 url。 - 將“員工信息維護”菜單關(guān)聯(lián)到指定角色 hr:在 web\WEB-INF\menu-config.xml 中在 “EmployeeMenu” 的定義中增加 “roles=‘hr‘”:
<!--Employee-START--> <Menu name="EmployeeMenu" title="employeeList.title" page="/employees.html" roles="hr"/> <!--Employee-END--> |
于是,“員工信息維護”的菜單入口只對屬于“人事管理”角色的用戶(hù)顯示,對其他用戶(hù)則隱藏。 - 分配角色 “hr” 給 tomcat:將“人事管理”角色分配給某一用戶(hù),例如 tomcat。則 tomcat能夠看見(jiàn)并訪(fǎng)問(wèn)“員工信息維護”相關(guān)頁(yè)面,而其他用戶(hù)的界面上則沒(méi)有“員工信息維護”這個(gè)菜單入口。并且,如果用戶(hù)試圖通過(guò)url訪(fǎng)問(wèn)employees.html的時(shí)候會(huì )看到如下頁(yè)面:
圖 14. “訪(fǎng)問(wèn)被拒絕”頁(yè)面
圖 14是 AppFuse 提供的默認“訪(fǎng)問(wèn)被拒絕”頁(yè)面,你可以通過(guò)修改 web\403.jsp 把它定制成自己喜歡的頁(yè)面。
事務(wù)控制
AppFuse 利用 Spring 的事務(wù)管理機制。Spring 可以以聲明的方式,對方法進(jìn)行事務(wù)控制,并且可以根據實(shí)際的需要,調整控制粒度。“聲明方式”的好處在于:核心代碼只需要關(guān)注業(yè)務(wù)邏輯,而將事務(wù)控制完全交由配置文件管理,一方面是核心代碼簡(jiǎn)潔清晰,另一方面也便于進(jìn)行集中配置管理。
事務(wù)控制一般是定義在 service 類(lèi)的方法上的。AppFuse 的所有 service 類(lèi)都聲明在 src\service\applicationContext-service.xml 中,該文件中包含有一個(gè) “txProxyTemplate” bean 的聲明,它定義了基本事務(wù)策略。其它的 service 類(lèi)從 “txProxyTemplate” 繼承,并可以“重寫(xiě)”事務(wù)策略。例如,AppFuse 對 userManager 的聲明如下:
<!-- Transaction template for Managers, from: http://blog.exis.com/colin/archives/2004/07/31/concise-transaction-definitions-spring-11/ --> |-------- XML error: The previous line is longer than the max of 90 characters ---------| <bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <props> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="remove*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean> <!-- Transaction declarations for business services. To apply a generic transaction proxy to |-------- XML error: The previous line is longer than the max of 90 characters ---------| all managers, you might look into using the BeanNameAutoProxyCreator --> <bean id="userManager" parent="txProxyTemplate"> <property name="target"> <bean class="org.appfuse.service.impl.UserManagerImpl"> <property name="userDao" ref="userDao"/> </bean> </property> <!-- Override default transaction attributes b/c of UserExistsException --> <property name="transactionAttributes"> <props> <prop key="save*">PROPAGATION_REQUIRED,-UserExistsException</prop> <prop key="remove*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> <!-- This property is overriden in applicationContext-security.xml to add method-level role security --> <property name="preInterceptors"> <list> <ref bean="userSecurityInterceptor"/> </list> </property> </bean> |
Spring 提供了大量的參數和選項使開(kāi)發(fā)者能夠靈活地管理事務(wù)。有關(guān) Spring 使用方面的知識,請參閱 Spring 的文檔。另外,《Spring in Action》也是一個(gè)不錯的選擇。
日志
AppFuse 集成了 Log4j 進(jìn)行日志管理,log4j.properties 位于 web\WEB-INF\classes 目錄下。AppFuse 已經(jīng)在絕大多數基類(lèi)(諸如,BasePage.java、BaseDaoHibernate.java 以及 BaseManager.java 等)中加入了如下用于輸出日志的成員變量:
protected final Log log = LogFactory.getLog(getClass()); |
因此,開(kāi)發(fā)者只需要在自己的代碼中調用 log 的方法就可以了,例如:“log.debug("entered ‘delete‘ method");”。
郵件
AppFuse 集成了 Spring 的發(fā)送郵件的功能。發(fā)送郵件需要用的參數,如主機、端口等信息在 web\WEB-INF\classes\mail.properties 中進(jìn)行配置。和發(fā)送郵件相關(guān)的 bean 已經(jīng)在 applicationContext-service.xml 中聲明:mailEngine、mailSender、velocityEngine 以及 mailMessage。用戶(hù)只需要在自己的類(lèi)中 “注入” mainSender 的實(shí)例,就可以發(fā)送郵件了。具體使用方法,請參閱Spring的文檔。
緩存
AppFuse 對緩存機制的支持源自 Hibernate 對緩存的支持。Hibernate 提供了對五種緩存機制的集成,AppFuse 默認提供了其中的兩種:Ehcache 和 Oscache。開(kāi)發(fā)者也可以根據需要自行添加和配置。Acegi 默認提供了對 Ehcache 支持的實(shí)現,所以 Ehcache 是較好的選擇。ehcache.xml 和 oscache.properties 位于 web\WEB-INF\classes 中。
結束語(yǔ)
使用 AppFuse 創(chuàng )建 Web 應用,步驟非常簡(jiǎn)單,你只需要了解如何運行 Ant 就能夠使用 AppFuse;使用 AppFuse 創(chuàng )建 Web 應用,非??焖?,因為 AppFuse 已經(jīng)幫我們完成大部分代碼生成/集成/配置的工作;使用 AppFuse 創(chuàng )建 Web 應用,非常省力,因為 AppFuse 已經(jīng)提供了很多“開(kāi)箱即用”的功能。體驗快速開(kāi)發(fā),從 AppFuse 開(kāi)始。
下載
| 描述 | 名字 | 大小 | 下載方法 |
| myapp 項目代碼(不含lib目錄) | myapp.zip | 3531KB | HTTP |
參考資料
學(xué)習獲得產(chǎn)品和技術(shù)關(guān)于作者
|
| | | 沈銳在 J2EE 項目開(kāi)發(fā)方面有多年的經(jīng)驗,目前在 IBM CSDL 從事 IBM Workplace Dashboard Framework 產(chǎn)品的開(kāi)發(fā)工作。他對 Java 的開(kāi)源技術(shù)有著(zhù)濃厚的興趣,歡迎使用 shenrui@cn.ibm.com 與他交流。 |