内容


使用 AppFuse 快速构建 J2EE 应用

快速开发,从 AppFuse 开始

Comments

关于 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
installAppGen 的 target。如果你不希望使用 AppGen 帮你生成 dao 类和 service 类以及其他的代码,就使用这个 target。extras/appgen 目录下的 build.xml
install-detailedAppGen 的 target。如果你希望使用 AppGen 帮你生成所有代码,就使用这个 target。extras/appgen 目录下的 build.xml

本文将按如下顺序展开叙述 :

  • 示例介绍
  • 搭建开发环境
  • 新建项目
  • 创建数据库表
  • 用 AppGen 生成代码
  • 根据项目需求调整代码
  • 其他功能
    • 语言国际化
    • 页面布局和样式
    • 系统安全
    • 事务控制
    • 日志
    • 邮件
    • 缓存

示例介绍

本文的示例实现对员工信息的增删查改等基本功能。用 Tapestry 实现表示层,用 Hibernate 开发持久层,用 Spring 提供事务控制等跨模块服务,并用 Acegi 进行安全管理。本示例只用到一个域模型:Employee,下面是它的 UML 图。

图 1. Employee UML 图
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 -- 新建项目
ant new -- 新建项目
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 的初始界面
AppFuse 的初始界面
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
“install-detailed” 执行后的 Eclipse
“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.javaEmployee 类 -- Java Bean
myapp/build/dao/gen/org/appfuse/hr/model/Employee.hbm.xmlEmployee 类的 Hibernate 映射文件
myapp/src/dao/org/appfuse/hr/dao/EmployeeDao.java定义关于 employee 的 dao 层的操作
myapp/src/dao/org/appfuse/hr/dao/hibernate/EmployeeDaoHibernate.javaEmployeeDao 的 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.javaEmployeeManager 的实现类
myapp/src/web/org/appfuse/hr/webapp/action/EmployeeForm.javaemployee 的添加 / 修改页面对应的 tapestry 类
myapp/src/web/org/appfuse/hr/webapp/action/EmployeeList.javaemployee 的列表页面对应的 tapestry 类
myapp/test/dao/org/appfuse/hr/dao/EmployeeDaoTest.javaemployee dao 类的测试用例
myapp/test/service/org/appfuse/hr/dao/EmployeeManagerTest.javaemployee service 类的测试用例
myapp/test/web/org/appfuse/hr/webapp/action/EmployeeFormTest.javaemployee 添加 / 修改页面类的测试用例
myapp/test/web/org/appfuse/hr/webapp/action/EmployeeFormTest.javaemployee 列表页面类的测试用例
myapp/web/pages/hr/employeeForm.htmlemployee 添加 / 修改页面 html 模版文件
myapp/web/pages/hr/employees.htmlemployee 列表页面 html 模版文件
myapp/web/pages/hr/employeeForm.pageemployee 添加 / 修改页面规格文件
myapp/web/pages/hr/employees.pageemployee 列表页面规格文件

不过,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">
      <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 的原始主页面
myapp 的原始主页面
myapp 的原始主页面

点击 “Employee List” 链接,进入“员工信息列表”页面。

图 6. myapp 的原始员工信息列表页面
myapp 的原始员工信息列表页面
myapp 的原始员工信息列表页面

点击“添加”按钮或点击任意一行数据,进入“员工信息添加 / 修改 / 删除”页面。

图 7. myapp 的原始员工信息添加 / 修改 / 删除页面
myapp 的原始员工信息添加 / 修改 / 删除页面
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 主页面
修改后的 myapp 主页面
修改后的 myapp 主页面
图 9. 修改后的 myapp 员工信息列表页面
修改后的 myapp 员工信息列表页面
修改后的 myapp 员工信息列表页面
图 10. 修改后的 myapp 员工信息添加 / 修改 / 删除页面
修改后的 myapp 员工信息添加 / 修改 / 删除页面
修改后的 myapp 员工信息添加 / 修改 / 删除页面
图 11. 修改后的 myapp 用户管理页面
修改后的 myapp 用户管理页面
修改后的 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 的属性窗口
ApplicationResources_zh_CN.properties 的属性窗口
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
应用了 “puzzlewithstyle” 的 myapp
应用了 “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> 
 ...

本文关于系统安全的实现如下:

  1. 在数据库中增加新的角色“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”。
  2. 定义角色名称的中文显示文本:在 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
  3. 配置“安全策略”:在 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。
  4. 将“员工信息维护”菜单关联到指定角色 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-->

    于是,“员工信息维护”的菜单入口只对属于“人事管理”角色的用户显示,对其他用户则隐藏。
  5. 分配角色 “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/
--> 
<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 
  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 开始。


下载资源


相关主题

  • AppFuse:AppFuse 项目主页。
  • 使用 AppFuse 的七个理由(developerWorks,2006 年 8 月):来自项目创始人关于 AppFuse 的特性、架构以及为什么要使用 AppFuse 的介绍。
  • AppFuse Demos:AppFuse 演示和视频
  • AppFuse 快速入门指南:快速入门并使用 AppFuse。
  • AppFuse 教程:深入学习更多有关使用 AppFuse 的知识。
  • CSS Framework:了解更多 AppFuse 中使用到的 CSS Framework 的知识。
  • Ant:下载并学习如何使用 Ant。
  • Eclipse:下载并学习如何使用 Eclipse。
  • Tomcat:下载并学习如何使用 Tomcat。
  • MySQL:下载并学习如何使用 MySQL。
  • Tapestry:优秀的 Web 框架。
  • Spring:强大的轻量级容器。
  • Hibernate:杰出的 ORM 持久化框架。
  • Acegi:了解和学习如何用 Acegi 进行系统安全配置。

评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Java technology, Open source, Web development
ArticleID=169093
ArticleTitle=使用 AppFuse 快速构建 J2EE 应用
publish-date=10192006