本文内容:
本文以一个 J2EE 开发者的角度,借助一个简单的应用示例,在融合了个人经验的基础上介绍了如何用
AppFuse 一步步地构建 J2EE 项目。通过阅读本文,读者不仅能够学会用 AppFuse 进行开发,而且能够充分体会到 AppFuse
提供的“快速开发”的优越性。
关于 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 图。
图 1. 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应用》 进行必要的设置。以下是两个你可能需要进行的配置:
AppFuse 默认连接 MySQL 的用户名是 root,密码为空。如果你的 root 密码不是空,需要修改
C:\opt\myapp\build.properties 中的 database.admin.password 项,记得将注释去掉。
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 的初始界面
或许此时,你已惊奇地发现,自己不过只运行了一次 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; |
回页首
用 AppGen 生成代码
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" 生成的主要文件。
表 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 的原始员工信息添加/修改/删除页面
不难看出,虽然 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 员工信息列表页面
图 10. 修改后的 myapp 员工信息添加/修改/删除页面
图 11. 修改后的 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,能够很方便的修改系统的整体布局和样式,因为 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
中找到如下代码: //
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=人事管理
AppFuse 默认在用户管理界面上显示的角色的名称是表 role 中的名称,这样无论切换到何种语言,角色名称都是
“admin”、"user"、“hr” 等等,角色名称不能根据 Locale 用相应的语言显示。因此,本文将角色的名称用
Resource Bundle 文件定义,数据库中存储 “key” 值。修改后的效果见 图 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 这个角色可以访问形如 “/employees.html*”
的 url。
将“员工信息维护”菜单关联到指定角色 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的时候会看到如下页面:
图 14. “访问被拒绝”页面
图 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
开始。 |