本文內容:
本文以一個 J2EE 開發者的角度,藉助一個簡單的應用示例,在融合了個人經驗的基礎上介紹瞭如何用 AppFuse 一步步地構建 J2EE 項目。通過閱讀本文,讀者不僅能夠學會用 AppFuse 進行開發,而且能夠充分體會到 AppFuse 提供的“快速開發”的優越性。
關於 AppFuse 的特性、架構以及爲什麼要使用 AppFuse,AppFuse 的創始人 Matt Raible 在 《使用 AppFuse 的七個理由》一文中已經做了很詳盡的闡述,這裏就不再贅言。本文將着力於實踐,即如何運用 AppFuse 開發 J2EE 應用。
關於 AppFuse 的特性、架構以及爲什麼要使用 AppFuse,AppFuse 的創始人 Matt Raible 在 《使用 AppFuse 的七個理由》一文中已經做了很詳盡的闡述,這裏就不再贅言。本文將着力於實踐,即如何運用 AppFuse 開發 J2EE 應用。
使用 AppFuse,你需要對 Ant 有一些基本的瞭解,比如什麼叫 target、什麼是 build.xml 以及如何運行 Ant,等等。如果你現在還不知道 Ant 是什麼,就需要找些相關資料學習一下。下表列出了本文中用到的也是較爲常用的 AppFuse 的 target:
表 1. Ant 中常用的 AppFuse target
target | 說明 | 所在文件 |
new | 這個 target 是使用 AppFuse 必須要用到的,它用來在 AppFuse 同級的目錄下創建一個新項目。創建過程是交互式的,會讓用戶輸入項目名稱、數據庫名稱以及根包路徑。 | AppFuse 安裝目錄下的 build.xml |
setup | 用於初始化一個新的項目,它包含了從數據庫創建、Tomcat 設置到 war 文件的生成和部署等一系列操作。 | 項目根目錄下的 build.xml |
deploy | 如果你修改的代碼不涉及到數據庫的更改,那麼可以使用這個 target,因爲它只負責生成並重新部署 war 包。 | 項目根目錄下的 build.xml |
setup-db | 如果你只是要對數據庫進行更改,使用這個 target。比如,重新創建數據庫,重新加載樣本數據等操作。 |
項目根目錄下的 build.xml |
install | AppGen 的 target。如果你不希望使用 AppGen 幫你生成 dao 類和 service 類以及其他的代碼,就使用這個 target。 | extras/appgen 目錄下的 build.xml |
install-detailed | AppGen 的 target。如果你希望使用 AppGen 幫你生成所有代碼,就使用這個 target。 | extras/appgen 目錄下的 build.xml |
本文將按如下順序展開敘述:
- 示例介紹
- 搭建開發環境
- 新建項目
- 創建數據庫表
- 用 AppGen 生成代碼
- 根據項目需求調整代碼
其他功能
語言國際化
頁面佈局和樣式
系統安全
事務控制
日誌
郵件
緩存
回頁首
示例介紹
示例介紹
本文的示例實現對員工信息的增刪查改等基本功能。用 Tapestry 實現表示層,用 Hibernate 開發持久層,用 Spring 提供事務控制等跨模塊服務,並用 Acegi 進行安全管理。本示例只用到一個域模型:Employee,下面是它的 UML 圖。
本文的代碼開發平臺採用的是 Windows 操作系統,因此,以下環境設置也是針對 Windows 操作系統的。
- 從 AppFuse 下載頁面 下載 appfuse-tapestry-1.9.3-src.zip,並解壓縮在任意目錄下。這個 zip 已經定製了使用 Tapestry 作爲表現層的實現框架,因而使用起來較爲直接。
- 從 http://java.sun.com 下載最新的 JDK,並安裝或解壓縮到任意目錄下。本文采用 JDK 1.5.0。設置環境變量 JAVA_HOME 指向 JDK 所在的目錄,並在 PATH 中添加 %JAVA_HOME%/bin。
- 從 http://jakarta.apache.org/tomcat 下載最新版的 Tomcat,並安裝或解壓縮到任意目錄下。本文采用 Tomcat 5.5.17。設置環境變量 CATALINA_HOME 指向 Tomcat 的安裝目錄。
- 從 http://ant.apache.org下載最新版的 Ant,並解壓縮到任意目錄下。AppFuse 要求的最低版本是 1.6.2,本文采用的是 1.6.5。設置 ANT_HOME 指向 Ant 所在的目錄,並在 PATH 中添加 %ANT_HOME%/bin。另外,要拷貝一個 junit.jar 到 %ANT_HOME%/lib 下,如果 lib 下沒有 junit.jar,AppFuse 的腳本在運行時會給出警告信息。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 裏運行。有關如何在 Eclipse 裏執行 Ant 腳本,請參考《用Eclipse開發AppFuse應用》。到此,我們已經爲 AppFuse 開發應用準備好了環境,下面讓我們開始使用 AppFuse 創建項目。
AppFuse 的便捷與強大之處在於它已經爲我們提供了多種開源框架的集成,並且通過使用 Ant 將所有的構建過程自動化。另外,AppFuse 利用 XDoclet 能夠爲我們生成絕大多數重要的代碼,例如 dao 類、service 類以及測試用例,等等,並且能夠將大量的配置文件也一併生成好,從而極大地節省了開發人員的時間。
用 AppFuse 進行開發通常有三種模式:“自上而下”,“自下而上”以及“混合模式”。採用“自上而下”(由 Java 對象向數據庫對象創建的過程)的方式固然比較符合“面向對象”的設計思維,但是爲此要編寫大量的 XDoclet 的 tag 也確是一件痛苦的事情。相比較而言,採用“自下而上”(由數據庫對象生成 Java 對象的過程)就顯得簡單許多 -- 只需要提供數據庫表結構。然而,對於較爲複雜的系統,尤其是類之間具有大量的關聯的情形,仍然需要採用“自上而下”的創建模式。因此,在實際的項目開發中,將兩種模式進行混合使用比較常見,這也就是“混合”模式。本文采用“自下而上”的模式。
本文的 AppFuse 安裝在 "c:\opt" 下面。打開命令行控制檯,進入 "c:\opt\appfuse",運行 “ant new”,爲簡單起見,所有參數選用默認值,見圖 2。
圖 2. ant new -- 新建項目
腳本運行成功後,新項目創建在 c:\opt\myapp 下(與 AppFuse 目錄同級),myapp 是 AppFuse 默認的項目名稱。將該項目導入到 Eclipse 中,並根據 《用Eclipse開發AppFuse應用》 進行必要的設置。以下是兩個你可能需要進行的配置:
腳本運行成功後,新項目創建在 c:\opt\myapp 下(與 AppFuse 目錄同級),myapp 是 AppFuse 默認的項目名稱。將該項目導入到 Eclipse 中,並根據 《用Eclipse開發AppFuse應用》 進行必要的設置。以下是兩個你可能需要進行的配置:
AppFuse 默認連接 MySQL 的用戶名是 root,密碼爲空。如果你的 root 密碼不是空,需要修改 C:\opt\myapp\build.properties 中的 database.admin.password 項,記得將註釋去掉。
AppFuse 默認不是用 utf-8 創建數據庫,如果你需要支持多語言,需要修改 C:\opt\myapp\metadata\sql\mysql-create.sql 中的創建數據庫的語句,修改如下:
AppFuse 默認不是用 utf-8 創建數據庫,如果你需要支持多語言,需要修改 C:\opt\myapp\metadata\sql\mysql-create.sql 中的創建數據庫的語句,修改如下:
清單 1. 創建數據庫語句
create database if not exists @DB-NAME@ CHARACTER SET utf8 COLLATE utf8_general_ci; |
注:AppFuse 會在構建期將 @DB-NAME@ 替換成你指定的數據庫名(本文中爲“mydb”)。
在 c:\opt\myapp 下運行“ant setup test-all”。“setup” 完成了很多“設置”工作:創建數據庫、構建 dao 和 serive 類、加載樣本數據、創建 war 文件並部署到 tomcat,等等。“test-all” 運行所有的測試用例:對 dao,service 以及頁面的測試。如果這個腳本運行成功,說明開發環境一切就緒。這時,啓動 Tomcat,通過訪問 http://localhost:8080/myapp 就能夠看到 AppFuse 的登錄界面了。AppFuse 預定義了兩個用戶:mraible 和 tomcat,密碼都是 tomcat。mraible 屬於管理員角色(能夠管理用戶信息),tomcat 屬於普通用戶角色。用 mraible 登錄可以看到 圖 3的界面。
圖 3. AppFuse 的初始界面
在 c:\opt\myapp 下運行“ant setup test-all”。“setup” 完成了很多“設置”工作:創建數據庫、構建 dao 和 serive 類、加載樣本數據、創建 war 文件並部署到 tomcat,等等。“test-all” 運行所有的測試用例:對 dao,service 以及頁面的測試。如果這個腳本運行成功,說明開發環境一切就緒。這時,啓動 Tomcat,通過訪問 http://localhost:8080/myapp 就能夠看到 AppFuse 的登錄界面了。AppFuse 預定義了兩個用戶:mraible 和 tomcat,密碼都是 tomcat。mraible 屬於管理員角色(能夠管理用戶信息),tomcat 屬於普通用戶角色。用 mraible 登錄可以看到 圖 3的界面。
圖 3. AppFuse 的初始界面
或許此時,你已驚奇地發現,自己不過只運行了一次 Ant 腳本,但是系統已經擁有“用戶管理”、“郵件”、“文件上傳” 等功能 -- 這就是 AppFuse “開箱即用”的優勢。接下來讓我們開始開發前述的應用示例。
在 mydb 數據庫中執行如下語句創建 employee 表:
清單 2. 創建 employee 語句
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; |
AppFuse 自帶了一個代碼生成工具 -- AppGen,它位於 c:\opt\myapp\extras\appgen 目錄下面。AppGen 可以生成絕大部分我們需要的代碼,比如 dao 類,service 類,菜單、增刪改的 web 頁面、配置文件、樣本數據,等等。AppGen 利用 XDoclet 生成代碼,因此可以在 extras/appgen/src 看到很多 .xdt 文件,這些就是 XDoclet 的模版定義文件。如果你希望自己編寫 dao 和 service 類,就運行“install”這個 target,否則就用 “install-detailed” ,它可以幫你搞定一切。下面就讓我們來運行 “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 ... |
前兩個問題都很直觀:選擇從 table 生成代碼,表名是 employee。第三個問題是讓用戶輸入使用的模塊名,如果你希望 AppFuse 幫你按模塊生成代碼的話,就需要輸入一個模塊名稱。這裏,我們輸入“hr”。如果運行成功,在 Eclipse 中會看到如下的目錄結構:
圖 4. “install-detailed” 執行後的 Eclipse
表 2 列出了 "install-detailed" 生成的主要文件。
圖 4. “install-detailed” 執行後的 Eclipse
表 2 列出了 "install-detailed" 生成的主要文件。
表 2. "install-detailed" 生成的主要文件列表
文件 | 說明 |
myapp/src/dao/org/appfuse/dao/hibernate/applicationContext-hibernate.xml | 在其中增加了 employeeDao 的聲明 |
myapp/src/dao/org/appfuse/hr/model/Employee.java | Employee 類 -- Java Bean |
myapp/build/dao/gen/org/appfuse/hr/model/Employee.hbm.xml |
Employee 類的 Hibernate 映射文件 |
myapp/src/dao/org/appfuse/hr/dao/EmployeeDao.java | 定義關於 employee 的 dao 層的操作 |
myapp/src/dao/org/appfuse/hr/dao/hibernate/EmployeeDaoHibernate.java |
EmployeeDao 的 Hibernate 實現類 |
myapp/src/service/org/appfuse/service/applicationContext-service.xml | 在其中增加了employeeManager的聲明 |
myapp/src/service/org/appfuse/hr/service/EmployeeManager.java | 定義關於 employee 的 service 層的操作 |
myapp/src/service/org/appfuse/hr/service/impl/EmployeeManagerImpl.java | EmployeeManager 的實現類 |
myapp/src/web/org/appfuse/hr/webapp/action/EmployeeForm.java | employee 的添加/修改頁面對應的 tapestry 類 |
myapp/src/web/org/appfuse/hr/webapp/action/EmployeeList.java | employee 的列表頁面對應的 tapestry 類 |
myapp/test/dao/org/appfuse/hr/dao/EmployeeDaoTest.java |
employee dao 類的測試用例 |
myapp/test/service/org/appfuse/hr/dao/EmployeeManagerTest.java |
employee service 類的測試用例 |
myapp/test/web/org/appfuse/hr/webapp/action/EmployeeFormTest.java |
employee 添加/修改頁面類的測試用例 |
myapp/test/web/org/appfuse/hr/webapp/action/EmployeeFormTest.java | employee 列表頁面類的測試用例 |
myapp/web/pages/hr/employeeForm.html | employee 添加/修改頁面 html 模版文件 |
myapp/web/pages/hr/employees.html |
employee 列表頁面 html 模版文件 |
myapp/web/pages/hr/employeeForm.page |
employee 添加/修改頁面規格文件 |
myapp/web/pages/hr/employees.page | employee 列表頁面規格文件 |
不過,AppFuse 並不知道開發者需要加載哪些 hbm 文件,所以要手工將 Employee.hbm.xml 文件添加到配置文件中:打開 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”。打開 “http://localhost:8080/myapp”,用 mraible/tomcat 登錄,“Employee List” 已經被添加到菜單裏了。
圖 5. myapp 的原始主頁面
點擊 “Employee List” 鏈接,進入“員工信息列表”頁面。
圖 6. myapp 的原始員工信息列表頁面
點擊“添加”按鈕或點擊任意一行數據,進入“員工信息添加/修改/刪除”頁面。
圖 7. myapp 的原始員工信息添加/修改/刪除頁面
點擊 “Employee List” 鏈接,進入“員工信息列表”頁面。
圖 6. myapp 的原始員工信息列表頁面
點擊“添加”按鈕或點擊任意一行數據,進入“員工信息添加/修改/刪除”頁面。
圖 7. myapp 的原始員工信息添加/修改/刪除頁面
不難看出,雖然 AppFuse 幫我們生成了頁面,但是這些頁面並非那麼“理想”,我們仍然需要根據實際的需求做些調整。
在本文中,做了如下代碼修改:
- 將所有頁面文字翻譯成中文:AppFuse 中用到的所有 Resource Bundle 文件位於 myapp/web/WEB-INF/classes 目錄下(以ApplicationResources開頭的properties文件)。更改 ApplicationResources_zh_CN.properties 的文件編碼方式爲“UTF-8”。然後,把 ApplicationResources.properties 中 “# -- Employee-START” 和 “# -- Employee-END” 之間的項拷貝到 ApplicationResources_zh_CN.properties 中,並逐項翻譯成中文。AppFuse 會在腳本運行的時候自動用 native2ascii 進行編碼轉換。另外,AppFuse 默認對 “button.done” 的翻譯是“做”,這不太合適,所以改爲“完成”。
- 在“員工信息列表頁面”去掉了 id 列,並調整了列的順序:只要修改 employees.html 就可以。
- 在“員工信息添加/修改/刪除頁面”,將“所在部門”、“職位”、“狀態”改爲下拉列表:需要修改 employeeForm.html、employeeForm.page、EmployeeForm.java。用 PropertySelection 組件實現下拉列表,用 Resource Bundle 文件定義真正顯示的選項文本。
- 增加了一個“人事管理”的角色,用來執行員工信息管理的權限控制:具體介紹見“系統安全”。
- 添加了一個新的主題 “mytheme”(只是更改了界面的顏色):具體介紹見“頁面佈局和樣式”。
應用了上述修改後,在 c:\opt\myapp 中運行 “ant deploy” 重新打包整個項目併發布。以下是修改後的界面截圖:
圖 8. 修改後的 myapp 主頁面
圖 9. 修改後的 myapp 員工信息列表頁面
一個系統除了包含核心邏輯之外,還有其他一些輔助功能,它們也是非常重要的。下面,讓我們來看看如何在 AppFuse 中開發這些功能。
語言國際化
如果你的系統不僅僅支持一種語言,那麼就需要考慮這個問題。在 AppFuse 中,Resource Bundle 文件是位於 web\WEB-INF\classes 目錄下的以 ApplicationResources 開頭的 properties 文件。Tapestry 有自己的國際化文本機制。但是在 AppFuse 中,並不全是 Tapestry 頁面,仍有些地方使用 jsp,而這些頁面使用 JSTL 的 fmt 標籤顯示國際化文本。不過,AppFuse 已經將這二者的“源頭”進行了整合,因此,對用戶而言,只需要在 ApplicationResources*.properties 中定義需要國際化的文本。
但是,在 Eclipse 中可以看到,AppFuse 的 properties 文件默認的編碼不是 UTF-8,而是 ISO-8859-1,這樣會導致最後通過 native2ascii 轉換後的文件都是 “???”,所以用戶需要自己把這些文件轉成 UTF-8。轉換的方法很簡單:在 properties 文件上點右鍵,在右鍵菜單上選擇 Properties,打開屬性窗口後,更改 “Text file encoding” 爲 UTF-8。在修改編碼前,最好先把已有的文字拷貝出來,轉換好之後再粘貼回去,否則會導致原先翻譯好的文字變成亂碼。
圖 12. ApplicationResources_zh_CN.properties 的屬性窗口
AppFuse 在發佈項目的時候,會自動用 native2ascii 轉換這些資源文件。如果你想使用其他資源文件名,可以修改 web\WEB-INF\web.xml 中的 “javax.servlet.jsp.jstl.fmt.localizationContext” 的參數值。
AppFuse 在發佈項目的時候,會自動用 native2ascii 轉換這些資源文件。如果你想使用其他資源文件名,可以修改 web\WEB-INF\web.xml 中的 “javax.servlet.jsp.jstl.fmt.localizationContext” 的參數值。
頁面佈局和樣式
使用 AppFuse,能夠很方便的修改系統的整體佈局和樣式,因爲 AppFuse 使用了一種強大的 “CSS框架”。項目創建好之後,在 web\styles 目錄下,有三個目錄:andreas01,puzzlewithstyle 和 simplicity。這些是 AppFuse 自帶的三種主題,目錄名即 CSS 框架的主題名。屬於“管理員”角色的用戶可以在登錄後通過在 url 後面添加形如 "?theme=andreas01" 的參數更改系統使用的主題。如下圖:
圖 13. 應用了 “puzzlewithstyle” 的 myapp
系統默認使用的主題由 web\WEB-INF\web.xml 中的 “theme” 參數指定,AppFuse 默認使用的主題是 “simplicity”。更改或創建新的主題也很簡單,只要在 web\styles 目錄下,新建一個自己的目錄,並參照已有主題的編寫規範定義自己的主題。本文中,拷貝了 simplicity 目錄,更名爲 “mytheme”,然後將裏面的字體顏色從“藍色”基調改成了“綠色”基調,並修改 web.xml 中的 theme 參數值爲 “mytheme”,這樣 myapp 默認使用的就是 mytheme 的主題了,如圖 8所示。你也可以從 http://css.appfuse.org/themes/ 得到更多關於 “CSS框架” 的信息。
系統安全
AppFuse 使用 Acegi 進行安全管理。Acegi 的配置信息位於 web\WEB-INF\classes\security.xml。事實上,Acegi 是被集成到 Spring 當中的,因此這個文件是 Spring 的配置文件格式。在 web\WEB-INF\web.xml 中,該文件被指定在應用啓動前會被加載:
清單 5. web.xml 關於 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> ... |
本文關於系統安全的實現如下:
在數據庫中增加新的角色“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”,樣本數據被重新加載。這樣,我們就在數據庫中定義了一個新的角色記錄 “hr”。
定義角色名稱的中文顯示文本:在 myapp/sr/web/webapp/action/UserForm.java 的方法 pageBeginRender 中找到如下代碼: //
定義角色名稱的中文顯示文本:在 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 中增加角色名稱的定義: rolelabel_admin=系統管理員
rolelabel_user=普通用戶
rolelabel_hr=人事管理
rolelabel_user=普通用戶
rolelabel_hr=人事管理
AppFuse 默認在用戶管理界面上顯示的角色的名稱是表 role 中的名稱,這樣無論切換到何種語言,角色名稱都是 “admin”、"user"、“hr” 等等,角色名稱不能根據 Locale 用相應的語言顯示。因此,本文將角色的名稱用 Resource Bundle 文件定義,數據庫中存儲 “key” 值。修改後的效果見 圖 10。
配置“安全策略”:在 web\WEB-INF\security.xml 的 bean "filterInvocationInterceptor" 聲明中增加如下“黑體”的一行: <bean id="filterInvocationInterceptor"
配置“安全策略”:在 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 這個角色可以訪問形如 “/employees.html*” 的 url。
將“員工信息維護”菜單關聯到指定角色 hr:在 web\WEB-INF\menu-config.xml 中在 “EmployeeMenu” 的定義中增加 “roles='hr'”:
將“員工信息維護”菜單關聯到指定角色 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--> |
於是,“員工信息維護”的菜單入口只對屬於“人事管理”角色的用戶顯示,對其他用戶則隱藏。
分配角色 “hr” 給 tomcat:將“人事管理”角色分配給某一用戶,例如 tomcat。則 tomcat能夠看見並訪問“員工信息維護”相關頁面,而其他用戶的界面上則沒有“員工信息維護”這個菜單入口。並且,如果用戶試圖通過url訪問 employees.html的時候會看到如下頁面:
分配角色 “hr” 給 tomcat:將“人事管理”角色分配給某一用戶,例如 tomcat。則 tomcat能夠看見並訪問“員工信息維護”相關頁面,而其他用戶的界面上則沒有“員工信息維護”這個菜單入口。並且,如果用戶試圖通過url訪問 employees.html的時候會看到如下頁面:
圖 14. “訪問被拒絕”頁面
圖 14是 AppFuse 提供的默認“訪問被拒絕”頁面,你可以通過修改 web\403.jsp 把它定製成自己喜歡的頁面。
事務控制
圖 14是 AppFuse 提供的默認“訪問被拒絕”頁面,你可以通過修改 web\403.jsp 把它定製成自己喜歡的頁面。
事務控制
AppFuse 利用 Spring 的事務管理機制。Spring 可以以聲明的方式,對方法進行事務控制,並且可以根據實際的需要,調整控制粒度。“聲明方式”的好處在於:核心代碼只需要關注業務邏輯,而將事務控制完全交由配置文件管理,一方面是核心代碼簡潔清晰,另一方面也便於進行集中配置管理。
事務控制一般是定義在 service 類的方法上的。AppFuse 的所有 service 類都聲明在 src\service\applicationContext-service.xml 中,該文件中包含有一個 “txProxyTemplate” bean 的聲明,它定義了基本事務策略。其它的 service 類從 “txProxyTemplate” 繼承,並可以“重寫”事務策略。例如,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 提供了大量的參數和選項使開發者能夠靈活地管理事務。有關 Spring 使用方面的知識,請參閱 Spring 的文檔。另外,《Spring in Action》也是一個不錯的選擇。
日誌
AppFuse 集成了 Log4j 進行日誌管理,log4j.properties 位於 web\WEB-INF\classes 目錄下。AppFuse 已經在絕大多數基類(諸如,BasePage.java、BaseDaoHibernate.java 以及 BaseManager.java 等)中加入瞭如下用於輸出日誌的成員變量:
protected final Log log = LogFactory.getLog(getClass()); |
因此,開發者只需要在自己的代碼中調用 log 的方法就可以了,例如:“log.debug("entered 'delete' method");”。
郵件
AppFuse 集成了 Spring 的發送郵件的功能。發送郵件需要用的參數,如主機、端口等信息在 web\WEB-INF\classes\mail.properties 中進行配置。和發送郵件相關的 bean 已經在 applicationContext-service.xml 中聲明:mailEngine、mailSender、velocityEngine 以及 mailMessage。用戶只需要在自己的類中 “注入” mainSender 的實例,就可以發送郵件了。具體使用方法,請參閱Spring的文檔。
緩存
AppFuse 對緩存機制的支持源自 Hibernate 對緩存的支持。Hibernate 提供了對五種緩存機制的集成,AppFuse 默認提供了其中的兩種:Ehcache 和 Oscache。開發者也可以根據需要自行添加和配置。Acegi 默認提供了對 Ehcache 支持的實現,所以 Ehcache 是較好的選擇。ehcache.xml 和 oscache.properties 位於 web\WEB-INF\classes 中。
使用 AppFuse 創建 Web 應用,步驟非常簡單,你只需要瞭解如何運行 Ant 就能夠使用 AppFuse;使用 AppFuse 創建 Web 應用,非常快速,因爲 AppFuse 已經幫我們完成大部分代碼生成/集成/配置的工作;使用 AppFuse 創建 Web 應用,非常省力,因爲 AppFuse 已經提供了很多“開箱即用”的功能。體驗快速開發,從 AppFuse 開始。