引言
大家知道,开发一个基于Java的Web应用越来越难了。尽管我们可以避开使用以其难度而著称的EJB来开发J2EE应用,在一个没有EJB的Java Web应用中,我们还有许多的棘手问题需要处理。如,从大的方面讲,我们要选择Spring + Hibernate + JavaServer Faces的组合,那么,我们必须花费许多时间来集成这些大的框架。尽管我们对这些框架可能已经非常熟悉,但要集成它们,使它们能协调工作,恐怕不是一件容易的事情。例如,在一个已经调试好的只使用Hibernate的应用中,我们使用了Hibernate的lazy fetch功能,一旦与Spring集成后,我们会遇到一些突出的新问题,如怎样在Spring中做到open session in view,如何在Spring中有效地捕获包括数据库操作异常在内的各种异常, Spring的bean又如何与JavaServer Faces的managed bean相互通信,等等。如果我们还想加入一些其他有名的框架(为什么不呢?站在巨人的肩膀上总是一件好事),集成问题就会越来越尖锐了。此时,系统集成的难度已经大大超过了单独学习与掌握这些框架的难度。
我们不愿因这些集成的问题而舍弃在Java领域中丰富的开源项目资源,却返回到最原始的Servlet及JSP的方式中。此时,如果有一个现成的应用,已经集成了这些框架,该有多好!这样,我们就可以通过分析其配置,学习如何有效地集成各个开源框架。甚至,如果这个应用可以用作一个框架,直接就可以在上面快速地开发Java Web应用,那就更加妙不可言了。就像三国时期,刘备已经拥有五虎大将,却不能做到有效地使用与指挥这些虎将,此时,我们需要找到一个知人善用的诸葛亮。而这个诸葛亮,在Java领域中就是AppFuse。
AppFuse可从http://appfuse.org/下载。AppFuse是一个快速开发J2EE应用的初始应用。首先,它已经集成了Ant, XDoclet, Spring, Hibernate (或者iBATIS), JUnit, jMock, StrutsTestCase, Canoo's WebTest, Struts Menu, Display Tag Library, OSCache, JSTL及Struts (或者Spring MVC, WebWork, Tapestry及JSF)等各大框架。其次,它是一个可以马上就可以运行的Java Web应用。最后,我们可以在其基础上,快速地开发出一个功能齐全,架框稳健,维护方便的产品级应用。
但是,AppFuse也有一些不足。主是在于:一是其发行形式采用了Ant脚本构建方式,一切的操作均以命令行窗口的方式进行,无法直接在具体的IDE中进行开发。二是其安装时限制较多,不仅容易使人困惑,还容易使人出错。
本文针对AppFuse的这两个不足,通过分析AppFuse构建脚本的功能与作用,对其作了一些的适当的改进,使其安装与使用更加容易。最后,演示了如何将AppFuse导入NetBeans中,从而充分利用NetBeans的编辑、调试Java源码的功能,让AppFuse发出更亮丽的光彩。
一、 AppFuse的Ant脚本分析:
分析AppFuse的Ant脚本,是学好用好AppFuse来快速开发Java Web应用的关键所在。因此,在第一部分中,先以纲要的形式列出各个targets的功能及依赖关系,读者可快速地扫过一遍即可,在以后开发应用中,需要时再回过头来参考此部分。
AppFuse的Ant脚本targets中均位于build.xml文件中,而build.xml又导入了同级目录下面的properties.xml文件,properties.xml文件又使用了lib文件夹下的lib.properties文件。(这些文件在第二部分中均做适当的改动。)
AppFuse的build.xml的targets非常丰富,但有许多是被一些主要targets内部调用的,依据AppFuse的QuickStart(http://raibledesigns.com/wiki/AppFuseQuickStart.html),开发前的准备工作只需调用3个targets,即new,setup,及test-all。下面对这三个targets及所依赖的targets逐一简要说明。
1. ant new: 根据用户的输入,生成一个新的应用。依赖于clean, init
a) ant clean: 删除build、dist路径及database.properties.
b) ant init: 定义任务,检测Ant、JUnit及Tomcat
c) ant new:
1) 从命令行中接受四个参数:
1. app.name:应用的名称,拟输入“myapp”
2. db.name:数据库名称,拟输入“appfuse”
3. new.pkg.name:包名,拟输入“com.sarkuya”
4. web.framework:拟使用的MVC架构,默认为“struts”
2) 将appfuse目录下的所有文件拷贝到../myapp下面,排除一些文件
3) 将appfuse/extras目录下的所有文件拷贝到../myapp/extras下面
4) 将../myapp下面中一些文件中包含appfuse字符的改成myapp
5) 将appfuse.iml拷为../myapp/myapp.iml,将appfuse.ipr拷为../myapp/myapp.ipr
2. 如果转入myapp目录,运行ant setup test-all
a) ant setup: 初始安装,依赖于setup-db, setup-tomcat, deploy
1) ant setup-db: 安装数据库,依赖于db-create, db-prepare, db-load
1. ant db-create: 依赖于init, 创建数据库及授权
2. ant db-prepare: 依赖于clean, package-dao
a) ant clean: 删除build、dist路径及database.properties.
b) ant package-dao: 依赖于prepare, compile-dao
①. ant prepare: 创建build/appfuse/WEB-INF等web目录及检查下面文件是否最新
②. ant compile-dao: 依赖于hibernatedoclet
i. ant hibernatedoclet: 依赖于prepare,在build/dao中生成hibernate映射文件
ii. ant compile-dao: 将appfuse/src/dao下面的文件,生成到appfuse/build/dao/classes中,将生成hibernate映射文件到appfuse/build/dao/gen中
③. ant package-dao: 在appfuse/build/dao/gen/META-INF目录下生成applicationContext-hibernate.xml文件,即Spring用以配置Hibernate及各种dao的配置文件。在appfuse/dist下生成myapp-dao.jar文件
c) ant db-prepare: 根据映射文件生成数据库中的表
①. 根据build.properties在appfuse目录下生成database.properties
②. 生成app_user表,role表,user_role表
3. ant db-load: 依赖于prepare,将appfuse/metadata/sql/sample-data.xml中的文件插入到数据库的表中
4. ant setup-db: 本身什么也不执行。
2) ant setup-tomcat: 将相关资源部署到tomcat中,依赖于init。将metadata/conf/tomcat-context-5.5.xml复制到%CATALINA_HOME%/ conf/Catalina/localhost目录中,并将其更名为appfuse.xml,此将成为localhost的context。
3) ant deploy: 部署tomcat,依赖于package-web。
1. ant package-web: 打包war文件,依赖于compile-web, compile-jsp
a) ant compile-web: 编译web模块,依赖于package-service, stage-web
①. ant package-service: 依赖于compile-service
i. ant compile-service: 编译service模块,依赖于package-dao (参见2 -> a) -> 1) -> 2 -> b)
ii. package-service: 在appfuse/dist目录下面创建appfuse-service.jar
②. ant stage-web: 依赖于copy-resources, copy-web-files
i. ant copy-resources: 依赖于prepare (参见2 –> a) – 1) -> 2 -> b) -> ①),拷贝相应文件到appfuse/build/web/classes中,并根据build.properties在appfuse下生成database.properties文件。
ii. ant copy-web-files: 依赖于prepare(参见2 –> a) – 1) -> 2 -> b) -> ①),拷贝各种静态的web资源文件到appfuse/build/appfuse中
iii. ant stage-web: 自身未做任何工作
③. ant compile-web: 编译web模块
b) ant compile-jsp: 使用jspc编译jsp文件,依赖于jsp-2
①. ant jsp-2: 依赖于webdoclet
i. ant webdoclet: 主要在appfuse/build/appfuse下面生成appfuse.tld文件,依赖于compile-web (参见2 -> a) -> 3) -> 1. -> a) )
ii. ant jsp-2: 主要是将jsp1.0的tags,如JSTL,转换为jsp2.0,以及将web.xml的版本从2.3 DTD转换为2.4 XSD
②. ant compile-jsp: 使用jspc编译jsp文件
c) ant package-web: 打包war文件
2. ant deploy: 将应用打包成war文件后,部署到tomcat的webapps文件夹中 [注意:使用NetBeans时应注意,因为NetBeans不将war文件直接打包到tomcat的webapps文件夹中,而是打包到C:/Documents and Settings/<username>/.netbeans/5.0/jakarta-tomcat-5.5.9_base/webapps中]
4) ant setup: 自身未做任何工作
b) ant test-all: 在tomcat尚未运行的状态下,进行所有的测试。依赖于test-dao, test-service, test-web, test-jsp。
1) ant test-dao: 测试dao模块。依赖于copy-resources, package-dao, db-load, check-debug
1. ant copy-resources: (参见2 -> a) -> 3) -> 1. -> a) -> ② -> i.)
2. ant package-dao: (参见2 -> a) -> 1) -> 2 -> b)
3. ant db-load: (参见 2 -> a) -> 1 -> 3)
4. ant check-debug: 依赖于with-debug, no-debug
a) ant with-debug: 如果在命令行输入 ant test-dao -Dappfuse-debug=true,就会触发此开关,转入调试模式。
b) ant no-debug: 如果没有命令行的appfuse-debug=true,触发此开关,保持非调试模式。
c) ant check-debug: 自身未做任何工作
5. ant test-dao: 测试dao模块。
2) ant test-service: 依赖于copy-resources, compile-service, check-debug
1. ant copy-resources: (参见2 -> a) -> 3) -> 1. -> a) -> ② -> i.)
2. ant compile-service: (参见2 -> a) -> 3) -> 1. -> a) -> ① -> i. )
3. ant check-debug: (参见2 -> b) -> 1) -> 4. )
4. ant test-service: 测试service模块
3) ant test-web: 依赖于webdoclet, db-load, check-debug
1. ant webdoclet: (参见2 -> a) -> 3) -> 1. -> b) -> ① -> i. )
2. ant db-load: (参见 2 -> a) -> 1 -> 3)
3. ant check-debug: (参见2 -> b) -> 1) -> 4. )
4. ant test-web: 测试web模块
4) ant test-jsp: 使用Cargo运行Canoo WetTests,依赖于war, check-debug
1. ant war: 是package-web的别名,参见(参见2 -> a) -> 3) -> 1. )
2. ant check-debug: (参见2 -> b) -> 1) -> 4. )
3. ant test-jsp: 使用Cargo运行Canoo WebTests。调用了test-canoo的任务。
a) ant test-canoo:
b) ant test-jsp:
5) ant test-all: 通过调用db-load,注入示范数据。
大概了解了AppFuse的targets的功能及依赖关系后,下一步,我们准备修改其相应的设置。较大的改动是将AppFuse中所使用的MySql数据库改为HSQLDB,原因主要有以下几点:
Ø 由于HSQLDB是一个100%使用Java来开发的数据库,在Java测试环境中, 具有更加快速的优势。
Ø HSQLDB对中文支持得很好。
Ø 对HSQLDB的各个操作,可以很好地转换为Ant脚本,从而与AppFuse衔接得更为紧湊。具体原理请访问本人博客(http://blog.matrix.org.cn/page/Sarkuya)中《HSQLDB的持续化构建》一文。
Ø 将数据库改为另一个数据库,可使读者更加理解AppFuse设置数据库的原理,对以后自行改成个人喜好的数据库有一定的帮助。
二、 安装、修改与设置:
1. 下载AppFuse,并将其解压到一个文件夹中,如D:/appfuse中(为方便说明,本文下载的是appfuse-1.9.1-src.zip,地址为:https://appfuse.dev.java.net/files/documents/1397/32816/appfuse-1.9.1-src.zip,集成了Spring,Hibernate及Struts等框架)。
2. 安装JDK,并设JAVA_HOME路径
3. 安装Tomcat,并设CATALINA_HOME路径
4. 安装Ant,并设ANT_HOME路径
5. 将appfuse/lib/junit3.8.1/junit.jar复制到ANT_HOME/lib下面
[以上步骤,在appfuse目录下面使用ant init测试是否成功]
6. 将数据库更改至HSQLDB
a) 在appfuse/lib下面新建一文件夹hsqldb-1.8.0
b) 下载HSQLDB(http://prdownloads.sourceforge.net/hsqldb/hsqldb_1_8_0_4.zip?download),将lib文件夹下的hsqldb.jar复制到appfuse/lib/hsqldb-1.8.0之下
c) 修改appfuse/lib/lib.properties文件,MySQL块之下增加:
#
# hsqldb - http://www.hsqldb.org/
#
hsqldb.version=1.8.0
hsqldb.dir=${lib.dir}/hsqldb-${hsqldb.version}
hsqldb.jar=${hsqldb.dir}/hsqldb.jar
d) 修改appfuse/properties.xml文件,将database.properties块修改如下:
<!-- Defaults for database.properties -->
<property name="database.jar" location="${hsqldb.jar}"/>
<property name="database.dir" location="${hsqldb.dir}/db"/>
<property name="database.type" value="hsqldb"/>
<property name="database.name" value="appfuse"/>
<property name="database.host" value="localhost"/>
<property name="database.username" value="sa"/>
<property name="database.password" value=""/>
e) 在properties.xml文件中找到<!-- database URL for creating other dbs - used in db-create target -->块,修改如下:
<!-- database URL for creating other dbs - used in db-create target -->
<property name="database.admin.url" value="jdbc:${database.type}://${database.host}/hsqldb"/>
<property name="database.admin.username" value="sa"/>
<property name="database.admin.password" value=""/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="database.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="database.url"
value="jdbc:${database.type}:hsql://${database.host}/${database.name}"/>
<property name="database.show_sql" value="true"/>
<property name="database.schema" value=""/>
f) 在appfuse/build.xml文件中找到<target name=”db-create” …>模块,把原来的<else></else>部分改为:
<else>
<echo message="Detected HsqlDb, creating database..."/>
<echo level="info">Starting HsqlDb Server...</echo>
<java
classname="org.hsqldb.Server"
classpath="${database.jar}"
fork="true"
failonerror="true">
<arg value="-database.0" />
<arg value="file:${database.dir}/${database.name}" />
<arg value="-dbname.0" />
<arg value="${database.name}" />
</java>
</else>
g) 在<target name="db-create"…>这个target的</target>之后加入:
<!-- =================================================================== -->
<!-- Close HSQLDB -->
<!-- =================================================================== -->
<target name="shutdownServer">
<echo level="info">Shutdown HsqlDb Server...</echo>
<echo>URL: ${database.jar}</echo>
<java
jar="${database.jar}"
classpath="${database.jar}"
fork="true"
failonerror="true">
<arg value="--sql" />
<arg value="shutdown" />
<arg value="localhost-sa" />
</java>
</target>
<!-- =================================================================== -->
<!-- Browse HSQLDB -->
<!-- =================================================================== -->
<target name="browseServer"
description="Browse Database Server">
<echo level="info">Opening HsqlDb ManagerSwing...</echo>
<java
classname="org.HSQLDB.util.DatabaseManagerSwing"
classpath="${database.jar}"
fork="true"
failonerror="true">
<arg value="-url"/>
<arg value="jdbc:hsqldb:hsql://localhost/${database.name}" />
</java>
</target>
h) 在C:/Documents and Settings/<username>目录下面新建一个sqltool.rc文件,内容如下:
urlid localhost-sa
url jdbc:hsqldb:hsql://localhost/appfuse
username sa
password
当我们使用browseServer或shutdownServer与HSQLDB联系时,HSQLDB通过此文件验证用户信息。
i) 修改build.xml文件中的setup-db的target,改为:
<target name="setup-db" depends="db-prepare,db-load"
description="creates database and populates by calling other tasks"/>
让其不再依赖于db-create,因为我们将在一个单独进程中启动HSQLDB的服务器, 以Server的方式提供服务。
j) 修改appfuse/web/WEB-INF/web.xml,将encodingFilter的filter的encoding的值改为gb2312。
k) 修改build.xml文件,在Start Tomcat下面,增加一个关闭Tomcat的指令。
<!-- =================================================================== -->
<!-- ShutDown Tomcat -->
<!-- =================================================================== -->
<target name="stop.tomcat"
description="stop tomcat in the current console window" depends="check-debug">
<java classname="org.apache.catalina.startup.Bootstrap" fork="yes">
<jvmarg value="-Dcatalina.home=${tomcat.home}"/>
<jvmarg line="${run.myapp.test.debugargline}"/>
<arg value="stop"/>
<classpath>
<pathelement path="${java.home}/../lib/tools.jar"/>
<fileset dir="${tomcat.home}">
<include name="bin/bootstrap.jar"/>
</fileset>
</classpath>
</java>
</target>
7. 安装Tomcat的管理包
a) 下载apache-tomcat-5.5.17-admin.zip,解压到一个文件夹,将conf/Catalina/localhost/admin.xml文件复制到%CATALINA_HOME%/conf/Catalina/localhost下。
b) 将server/webapps/admin整个文件夹复制到%CATALINA_HOME%/server/webapps中。
c) 运行Tomcat,并在浏览器中打开http://localhost:8080/admin,使用帐号为admin,密码为admin登录。登录后,点击左边Service(Catalina)节点,再点击Connector(8080)节点,在右边的URI Encoding中输入gb2312。点击save,再点击Commit Changes。退出。
d) 关闭Tomcat。
三、 运行
1. 新建一个命令行窗口,切换到appfuse当前目录下面,运行
ant new
然后分别输入四个参数:myapp,appfuse,com.sarkuya,jsf
2. 在命令行窗口,切换到../myapp目录下面,运行
ant db-create
此target将根据HSQLDB的特点,在appfuse/lib/hsqldb-1.8.0/db下面新建名为appfuse的数据库,并启动数据库服务器,以Server方式对外提供服务。在下面的的步骤中,我们需要此服务器保持打开状态。
3. 因此,再新开一个命令行窗口,切换到appfuse当前目录下面,运行
ant setup
从上文可知,setup包含了setup-db, setup-tomcat, deploy三个target,其目标分别为准备数据库数据,将相关资源部署至tomcat,打包应用并部署至tomcat。此时,一切就绪。
4. 在第二个命令行窗口中输入:
ant start.tomcat
Tomcat将自动运行。
5. 打开一个浏览器,在地址栏中输入:
http://localhost:8080/myapp
就能看到以下界面:
图1. AppFuse的登录界面
用户名中输入“mraible”(管理员身份,即AppFuse的作者)或“tomcat”(普通用户),密码输入“tomcat”,或者按“申请”的链接,注册一个帐号,就可以登录了。登录后,可以看到主界面只有两个栏目:编辑信息与上传文件。注意到在注册窗口所录入的中文全都成了乱码,这是因为jsp网页的编码为UTF-8所致。需要将相应的编码改为gb2312即可。
好,我们的AppFuse已经可以通过命令行的形式运行了。下面我们的任务是进一步研究其原理,正确中文化,以及加入新的应用功能。而这些工作,如果有一个好的IDE前来助力,将会起来事半功倍的作用。
从上面的操作可以看出,AppFuse大量使用了Ant指令来简化工作任务,因此,即使是转到IDE中,也必须能够充分使用Ant指令。目前一些好的IDE都很好地集成Ant,如Eclipse, IntelliJ, NetBeans等等。本文将选用NetBeans来学习、编辑与创建源码。
在使用NetBeans之前,我们先清理一下现场。
a) 关闭浏览器。
b) 关闭Tomcat。新开一个命令行窗口,切换到myapp当前目录下面,运行
ant stop.tomcat
注意第二个命令行窗口显示正在退出Tomcat,然后转入到接受Dos指令的状态。
c) 关闭HSQLDB数据库服务器。在第二或第三个命令行窗口中输入
ant shutdownServer
发现在第一个命令行窗口,HSQLDB也退出了监听模式,窗口返回到命令行指令状态。
d) 清理AppFuse自动生成的资源。在任何一个已经打开的命令行窗口中输入
ant clean
清理所有自动生成的资源,主要是build及dist目录,database.properties及create-tables.sql文件。
e) 将所有窗口及命令行窗口均关闭。跟命令行彻底说Bye-bye。
在过足了类似于UNIX环境下运指如飞的瘾后,下面,将是NetBeans登场亮相的时候了。
四、 在Netbeans中编辑AppFuse
NetBeans中Web应用包括三种,如图2,下面简要说明。
第一种是Web应用程序,将创建一个空的Web应用,并使用IDE自动生成的Ant脚本指令。
第二种是包含现有源代码的Web应用程序,将原有的源代码导入IDE中,也是使用IDE自动生成的Ant脚本指令。
第三种是包含现有Ant脚本的Web应用程序,将原有的源代码导入IDE中,并使用原来的Ant脚本指令。这种格式也称为自由格式(Freeform)。
显然,第三种格式非常适合我们编辑与运行AppFuse应用。
图2. NetBeans中的3种Web应用
1. 将AppFuse导入Web自由格式项目中。
a) 启动NetBeans,新建一项目,如图2,在类别中选Web,在项目中选“包含现有Ant脚本的Web应用程序”。下一步。
b) 在“位置”文本框中,点击“浏览”,选中AppFuse项目所在文件夹,如F:/CodeTest/myapp。选择后,NetBeans自动为我们填充了剩下的内容,确认“设置为主项目”已经打勾。下一步。
c) NetBeans读取myapp下面的build.xml文件,将所有的targets都列在相应的下拉列表框中,并且很聪明地根据相应的功能选择了最相匹配的target。由此可见,我们以后在制定自己的target时,最好能遵循一些基本的惯例。在“生成项目”文本框中,选择“compile”;在“清除项目”中选择“clean”;在“生成Javadoc”中选择“javadoc”;在“运行项目”中选择“deploy”(build.xml文件中有一个start指令,主要是在Tomcat中开始一个已经部署完毕而又停止的模块,并不是很适合于NetBeans中的“运行项目”,所以我们这里先选deploy与之关联,以后再来修改它);在“测试项目”中选“test-all”;在“部署项目”中选“deploy”。下一步。
d) 在“上下文路径”中填上“myapp”。下一步。
图3. 项目属性中的Java源代码设置
e) “源包文件夹”中已有一个“src/dao”,针对AppFuse的特点,我们还需要增加“src/service”及“src/web”的源包文件夹。点其右边的“添加文件夹”,分别加上这两个源包。“测试包文件夹”依此操作。确认下面的“源级别”已经选了“JDK 1.5”。结果如图3。下一步。
f) 这是设置Java源代码类路径的窗口,主要为NetBeans自动导入(import)所引用的类、自动完成代码以及重构时提供类路径。我们需要在此分别为“src/dao”、“src/service”、“src/web”、“test/dao”、“test /service”及“test /web”提供两种类路径:一种是myapp/lib下面各种类路径;另一种是IDE所需的,存放于E:/Program Files/netbeans-5.0/enterprise2/jakarta-tomcat-5.5.9/common/lib中。但在这一步中,我们只需要为“src/dao”选择这两种类路径。以后会告诉你如何“偷懒”。 J
确认“源包文件夹中”选择了“src/dao [src/dao]”,点击“添加JAR/文件夹…”,选择“myapp/lib/ant-contrib-1.0b1/ant-contrib-1.0b1.jar”,再点击“添加JAR/文件夹…”,选择“myapp/lib/cargo-0.7/cargo-ant-0.7.jar”……依此方法,分别添加lib中各个文件夹下的各个jar文件。在一些文件夹中有多个jar文件的,配合键盘上Ctrl键或Shift键进行多项选择。有些文件夹中又有子文件夹的,也必须要进入到该文件新夹中,如果有jar文件,也要选择。注意,在jakarta-taglibs文件夹中共有两个文件夹,这是两个不同的版本,我们只需选择standard-1.1.2下的jar文件就行了。
选择myapp/lib下各个jar文件后,再次点击“添加JAR/文件夹…”,选E:/Program Files/netbeans-5.0/enterprise2/jakarta-tomcat-5.5.9/common/lib下面的所有jar文件。结果如图4所示。
图4. 项目属性中的Java源代码类路径
大家会发现这项工作非常累人,如果AppFuse的各个jar文件只存放在一个文件夹中,如果AppFuse只有1个源包与1个测试包,如果NetBeans支持选择最上层的父文件夹,再如果笔者在修改build.xml文件时进行了改进,这一切就不会发生。但不幸的是,这些如果都没有发生。笔者认为,有了这段难忘的经历,以后读者再遇到类似问题,就不会束手无措了。
下一步。
g) 此窗口设置Web源文件类路径。我们看到,“Java源代码类路径”已经自动添加到此窗口的类路径中。点击“完成”按钮。
2. 在NetBeans下工作
a) 项目导入后,我们先来熟悉一下NetBeans的环境。
图5. 项目导入后NetBeans的主界面
从图5看出,NetBeans的GUI简单明了。项目工作区中,有3个源包与3个测试包,Web页中存放Web有关的资源。最下面是我们在导入项目前与之打交道最多的文件build.xml,用鼠标选中后,导航区中按字母排列顺序自动列出了其所有的targets,可帮助我们快速定位targets。生成主项目、清除并生成主项目与运行主项目这3个按钮是开发过程中经常用到的,我们在导入工程时的c)步骤中,已经相应地为其指定不同的targets。其中,生成主项目对应于compile,清除并生成主项目对应于clean + compile,运行主项目对应于deploy。可以看出,这个三按钮对应的targets,从右到左,依赖于其前面的targets。
b) 在NetBeans下运行myapp
目前,在NetBeans下运行myapp与在Dos下通过Ant脚本运行的步骤基本一致。
1. 在“导航区”中找到“db-create”的target,对此target按右键,选“运行任务”,启动HsqlDb服务器(此target的名称由改制build.xml中而来,与启动HsqlDb服务器的目标不太相符,下面将集中一个地方改动相应的targets)。
2. 找到“setup”的target,运行
3. 找到并运行 “start.tomcat”的target
4. 打开一个浏览器,在地址栏中输入:
http://localhost:8080/myapp
你会看到曾经看到的图1。因为所有的数据已经在setup中被初始化,所以你得重新注册一个新用户。
你可能会说,我们幸幸苦苦地将项目转入到NetBeans,难道就是仅此而已?与Dos下有何区别?目前为止,将项目转入NetBeans后,你已经得到几个好处:
①. 定位targets非常方便。尤其是如果要在build.xml中寻找“${webapp.dist}”的属性值是什么,利用NetBeans源码工作区中工具栏的“查找选择”功能,你会发现简直太方便了,因为它可以同时在不同的文件中寻找并自动加亮查找结果。
②. 不用拚命地打储如ant start.tomcat之类的命令了,鼠标的点击就可以轻松完成任务
③. 所有独立进程的任务,如db-create与start.tomcat将不再占用你单独的命令行窗口,当它们运行时,如果你在“运行环境区”中展开“进程”,就会发现它们老老实实地呆在这里,悄悄地对外提供服务功能。作为回报,你的Windows任务栏是将不再特别拥挤而杂乱了。
④. Ant自动化构建与IDE的编程辅助功能是两个完全不同的概念,在各自的领域内,谁都无法因为自己多优秀而取代对方。目前只有为数不多的IDE真正做到这一点,正如你所见,在NetBeans中运行Ant脚本太方便了,简直与在Dos下没什么区别!
⑤. 而在编程领域中,自动化构建只是一个方面,更重要的是,你随时都在编写代码,修改代码,调试代码。这一块是IDE的专长。
总而言之,在拥有一个很好的Ant构建脚本的基础上,充分利用好NetBeans IDE,我们将同时拥有构建及编码的长处。
c) 解决NetBeans中特定的问题
项目导入NetBeans中后,有一些小问题,尽管我总想为NetBeans“遮羞”,但还是不得不老实地告诉你,毕竟,你有知情权。然后,我们再一起研究如何解决。
1. 打开这两个文件,一个是src/dao/org/appfuse/dao/UserDAO.java,另一个是test/dao/org/appfuse/dao/BaseDAOTestCase.java,你会发现,前者非常干净,而后者则长满了红色的波浪线,而每条线线的左边均有一个红色的叉叉,出错了!如果把鼠标放在这些波浪线上面,NetBeans会告诉我们发生了什么错误,尽是些什么“文件不存在”,或是“找不到标识符”错误。
我们不是已经在NetBeans中运行了应用程序吗?怎么还会有此错误?是的,程序没有错误,否则程序会运行不了。但我们的程序是通过Ant脚本来运行的,Ant十分了解各个所需的类在哪里,所以编译通过。但NetBeans比较腼腆,还不习惯向Ant获取这些知识,因此,尽管它与一位博士在一起,它还是一问三不知。
UserDAO.java属于src/dao的包,还记得我们前面在导入项目时噩梦般地为src/dao添加的两种类路径吧?这份幸劳通过UserDAO.java得到了回报。如果我们回过头去再为test/dao重复这项恼人的工作,BaseDAOTestCase.java肯定长得比UserDAO更为白净!但我们不会,太累了。那好,我们就另辟溪径吧。
选中“项目工作区”右边的“文件工作区”,这里老老实实地记录着所有在myapp下面的所有子目录及文件。展开“nbproject”目录,双击打开“project.xml”文件。
正如build.xml通过properties.xml、build.properties等文件配置属性,NetBeans的Freeform格式的工程通过此project.xml文件来配置与IDE有关的属性。可惜太长太乱了,不知从何看起。试一下Ctrl + Shift + -(减号)的快捷键吧,文件马上被全部折叠起来了。逐项展开,你会发现<project>下面有<type>及<configuration>,<configuration>主要由<general-data>、<java-data>及<web-data>构成。
看一下<general-data>下面的< folders >及<general-data>下面的<view>,点击项目工作区,展开myapp树形控件,你就会明白,这两处控制着项目工作区中项目的子视图。
再看<general-data>下面的<ide-actions>,不错,这是映射NetBeans的内建命令与build.xml文件中常用Ant脚本的地方。找到“rebuild”的action,发现原来将“clean”与“compile”同时映射于它居然这么简单!下面附出NetBeans所有的内建命令:
² build - 生成项目 (F11)
² rebuild - 清除并生成项目 (Shift-F11)
² compile.single - 编译选定的文件 (F9)
² clean - 清除项目
² run - 运行项目 (F6)
² run.single - 运行选定的文件 (Shift-F6)
² redeploy - 对于 Web 应用程序项目,会生成项目,将项目从服务器中卸下,然后重新将项目部署到服务器上
² test - 为项目运行 JUnit 测试 (Alt-F6)
² test.single - 为选定的文件运行 JUnit 测试 (Ctrl-F6)
² debug.test.single - 为选定的文件调试 JUnit 测试 (Ctrl-Shift-F6)
² debug - 在调试器中运行项目 (F5)
² debug.single - 调试选定的文件 (Ctrl-Shift-F5)
² debug.fix - 在调试会话期间运行“应用代码更改”命令以重新装入选定的文件
² debug.stepinto - 在调试器中执行一行项目主类,然后暂停 (F7)
² javadoc - 为项目生成 Javadoc
我们的答案藏在<java-data>节点中。在其下面,都有一个<compilation-unit>对应着我们的6个源包,其中,只有“src/dao”设了classpath,而<source-level>表明将使用JDK 1.5来编译该包。现在,将“src/dao”的classpath复制到其他5个包中。在复制到测试包时,注意将classpath复制到<unit-tests/>的下方。一存盘,NetBeans的右下角就会出现正在“扫描项目类路径”的提示。
再回去看BaseDAOTestCase.java,问题果真解决了。
2. 单独编译Java源文件的问题。
我们在编辑Java源文件过程中,有时只想编译当前的源文件,而不是图5所示的“生成主项目”来编译整个项目。打开BaseDAOTestCase.java,按F9键,准备单独编译当前源文件。NetBeans弹出一个窗口,提示“必须为编译文件操作产生生成目标”,意思为NetBeans需要在nbproject目录中生成一个名为“ide-file-targets.xml”文件,主要是确定此文件应将编译后生成的.class文件输出到哪个目录下面。按“生成”按钮,NetBeans自动生成了该文件,并打开。我们只需根据上面TODO所示,添加相应的属性即可。
3. ApplicationResources.properties的乱码问题
ApplicationResources.properties存放于myapp/web/WEB-INF/classes文件夹下,在NetBeans中双击打开时只能看到默认的英文。对其按右键打开,可看到里面有许多的语言包,有英文、西班牙文、法文、意大利文、荷兰文、葡萄牙文、葡萄牙文(巴西)、繁体中文、简体中文等。可是,我们目前最关心的中文居然是乱码!
在项目工作区中展开其下面的各种语言,删除西班牙文、法文、意大利文、荷兰文、葡萄牙文、葡萄牙文(巴西),然后按对ApplicationResources.properties按右键打开编辑,根据键值,重新在简体中文包中输入相应的汉字,保存即可。
通过这种方式,NetBeans将为我们转换为正确的编码。
至此,我们已经成功地将AppFuse导入了NetBeans中,从而可以在NetBeans的环境中更加方便地开发Java Web应用了。以后的过程,则主要是如何开发AppFuse应用,感兴趣的读者请进一步参考AppFuse站点中的Tutorials(http://raibledesigns.com/wiki/Wiki.jsp?page=Articles)。
结语
Ant构建是应用开发过程中实现自动持续化构建的一个重要方式(另一个在构建领域中类似于Ant的是Maven),AppFuse通过大量地使用了Ant脚本,将许多优秀、实用的开源项目有机地整合在一起,为我们学习与快速开发Java Web应用提供了一个非常优秀的范本。而NetBeans作为一个优秀的IDE,可以很方便地编辑与调试代码。NetBeans在与Ant的整合上做得非常出色,在标准格式中我们可以通过修改build.xml文件来改造与完善现有的功能,我们甚至可以通过自由格式(就像本文所述),直接创建我们自己的build文件,并能做到与NetBeans中的内建指令很好地结合起来。一旦我们将Ant构建与NetBeans有机地结合起来,无疑将大大地方便我们开发大型的应用。