ANT构建工具入门知识介绍

ANT构建工具入门知识介绍

这是我在传智播客上课的第一天,上午张老师讲了ANT ,看了张老师讲的ANT构建工具我首先基本了解了,在开发项目的时候极有可能会遇到
编写过的程序再回来增加一些新的功能,而如果将这些类一起再编译一遍无形中会浪费大量的时间和资源,此时ANT构建工具的优势就显现出来
了(以下演示的只是ANT的基本功能),它能够通过效验.java文件名来判断.java文件是否已经修改?(注意:由于这个原因,
我们的每个.java文件中最好只存放一个class类,这也非常符合我们的编码规范)

1、ANT构建工具的准备

在执行ANT构建工具之前我们要确保我们的计算机里面有apache-ant(文章中使用的ANT版本是apache-ant-1.6.5) ,将ANT构建工具解压到自己指定的一个文件夹中。

1>设置环境变量

ANT环境变量的设置有两个方法:

第一、就是我们熟悉的在系统的环境变量Path中设置,我ANT的解压路径是C:/apache-ant-1.6.5

C:/apache-ant-1.6.5/bin(bin目录是存放ant.bat的文件夹)将这个绝对路径粘贴在我的电脑右键属性->高级->环境变量->系统变量 点击Path->编辑,在变量值文本框的文本路径后面加上“;”再把刚才的绝对路径“C:/apache-ant-1.6.5/bin”拷贝到后面。

第二、在CMD中设置,开始->运行输入cmd 在命令行输入set path=C:/apache-ant-1.6.5/bin;%path%回车。(注意:此时不要关闭命令行窗口,将其保留)

至此我们的ANT构建工具环境变量的设置就完成了。

2>编写build.xml

通过学习我们了解到ant.bat会查找一个名为build.xml的文件这就是构建工具所需要的命令文件(这个文件会告诉ant.bat应该做什么,但是实际上是ant.bat会读取build.xml这个文件)下面我们就编写一个build.xml

<project name="myXml" default="init" basedir="."> 这是一个最简单的ANT,他的工程名字为myXml,默认执行init目标basedir代表当前目录下
< target name="init">目标名为init
<mkdir="dest"/>我们需要他在当前目录下来构建一个文件夹dest
</target>

</project>

此时我们保存上面的代码为build.xml,保存在我们需要运行的工程目录下,将cmd打开(如果刚才使用命令行设置的环境变量,那么继续使用刚才的cmd窗口)进入到工程文件的盘符下,比如c:/MyTest ,执行ant命令,然后回到windows窗口检查工程目录下是不是多了一个dest文件夹。

2、ANT构建工具的执行

现在也许会有人问,难道ANT就能干这些东西啊?那也太简单了。呵呵,让我们来看看更深入一点的吧。

编译java文件

编译java文件需要我们再做一些准备工作,就是设置java命令的classpath,如javac、java,这回的设置就简单多了,我们接着使用刚才的cmd,在命令行输入我们机器中安装的JDK的绝对路径,我的JDK路径是C:/Program Files/Java/jdk1.5.0_01(此时也许有人会问我,为什么不像ANT环境变量一样把/bin目录也写上?那好我们来一起分析一下ant.bat批处理文件

这是ant批处理文件的第80和81行

if "%JAVA_HOME%" == "" goto noJavaHome 这句话的大概意思是如果没有设置JAVA_HOME路径
if not exist "%JAVA_HOME%/bin/java.exe" goto noJavaHome这个批处理文件就给你指定一个当前路径下的/bin/java.exe路径,所以我们直接指定到/bin目录前就行了,他会自己加上后面的路径的。

此时在命令行输入set JAVA_HOME=C:/Program Files/Java/jdk1.5.0_01回车就行了,好了javac和java的环境变量设置好了,我们就来一个深入的体验吧。继续编写那个build.xml

<project name="myXml" default="star" basedir=".">
<target name="init">
<mkdir dir="dest"/>
</target>

<target name="compile" depends="init">
<javac srcdir="src" destdir="dest" includes="Main7.java"/>
</target>

<target name="star" depends="compile">
<java classname="Main7">
<classpath>
<pathelement path="dest"/>
</classpath>
</java>
</target>

<target name="clean">
<delete dir="dest" />
</target>
</project>


我从第二个目标来解释一下,目标名为“compile”他依赖(depends)init就是执行compile的时候会首先执行init,<javac srcdir="src" destdir="dest" includes="Main7.java"/>这句话的意思是执行javac.exe程序从目标文件夹src执行完之后将javac编译的.class文件存储在dest文件夹(此时就知道了为什么这个目标会依赖init目标了吧,init目标建立完文件夹dest之后,才可以在dest文件夹下存储.class文件)。提高,includes属性的意思是只包含Main7.java(此时我的src文件夹下有好几个*.java文件,这个属性的意义就是单独编译Main7.java文件)
<target name="star" depends="compile">
<java classname="Main7">
<classpath>
<pathelement path="dest"/>
</classpath>
</java>
</target>
第三个目标名为star,依赖于compile,<java classname="Main7">这句话的意思是使用java.exe命令来执行刚才编译好的Main7.class(我们知道java.exe命令执行的时候不能输入后面的.class后缀,所以我们这里就不写.class了

<classpath>
<pathelement path="dest"/>
</classpath>
通过查看ANT的文档我知道了java命令在执行的时候需要指定.class文件的路径,此时我们.class的路径是在dest下,此时我们就指定路径元素pathelement 的path属性值为dest,但是我还忽略了一点就是build.xml文件的第一行project name="myXml" default="star" basedir=".">将刚才的默认的init启动,改为default="star"启动,现在在build.xml所在的目录下建立一个名为src的文件夹,在src下放2、3个.java文件,在命令行上执行ant试试,是不是执行了Main7.class文件呢?
注意:我在测试的时候犯了一个错误,我们大家都知道.java文件存在main()方法类的修饰符应该是public,但是如果不写也可以执行,我要执行的Main7.java就没有写public class Main7{...},而是写的class Main7{...},呵呵,报错了,找了半天才知道ANT只会运行类访问修饰符为public的.java文件(这同时又提醒我们,注意严格的编码规范)

今天的Blog就写道这里了,本文只是个人学习心得,希望大家批评指正,谢谢^_^。

06年8月23日更新

大家在对ANT构建工具初步了解之后,我今天再介绍几个知识点,excludes与includes的功能正好相反,就是不包含。
<target name="javac" depends="init">
<javac srcdir="${src.dir}" destdir="${dest.dir}" excludes="${excludes}" includes="${includes}"/>
</target>
这时大家是不是有点看不太懂了?${src.dir}这都是什么意思啊?其实这就要引申出一个知识了,就是property

<project name="day2" default="run">

<!--
<property name="src.dir" value="src"/>
<property name="dest.dir" value="dest"/>
<property name="excludes" value="dest/*.java"/>
<property name="includes" value="TestString.java"/>
<property name="classname" value="TestString"/>
-->

<property file="test.property"/>

<target name="init">
<mkdir dir="${dest.dir}"/>
</target>

<target name="javac" depends="init">
<javac srcdir="${src.dir}" destdir="${dest.dir}" excludes="${excludes}" includes="${includes}"/>
</target>

<target name="run" depends="javac">
<java classname="${classname}" classpath="${dest.dir}"/>
</target>

<target name="clean">
<delete dir="${dest.dir}"/>
</target>

</project>

这是我的test.property文件
src.dir = src
dest.dir = dest
classname = TestString
includes = TestString.java
excludes = dest/*.java


大家别急啊让我先来分析一下ANT关于property的英文文档
Sets a property (by name and value), or set of properties (from file or resource) in the project.
Properties are case sensitive.
大概的意思是property固定有两个属性一个是name 另一个是value (就是在设置property 标签的时候必须写这两个属性)
这个标签可以在工程中设置如

<property name="src.dir" value="src"/>
<property name="dest.dir" value="dest"/>
<property name="excludes" value="dest/*.java"/>
<property name="includes" value="TestString.java"/>
<property name="classname" value="TestString"/>

也可以来自于文件如

<property file="test.property"/>
它是一个非常好用的工具。

大家在编写*.property文件的时候可以新建一个文本文件,将它的*.txt改为*.property就可以了,我的是test.property
那要如何调用property内部的元素呢?使用"${}"引用就行了如
<target name="init">
<mkdir dir="${dest.dir}"/>
</target>
我要新建一个文件夹引用property属性中name为dest.dir的元素就可以了,build会自己调用它的value值,是不是很简单啊,但是
在目标少的时候它的作用不能够完全体现出来,如果我们有一个需要构建100多个java类文件的build时,我们想修改其中的文件名
直接在property里面修改就行了,是不是很像java中的常量啊?

现在基本就明白
excludes="${excludes}" 不包含dest文件夹下的所有*java文件

includes="${includes}"(只包含TestString.java)的意思了吧。。。

再介绍一个ANT的命令,就是echo,看代码。。。^_^

<target name="output">
<echo message="Hello!"/>
</target>

这个指令就是打印输出一条信息“Hello!”

好了,今天的Blog就写道这里吧,明天见^_^~。。

<project name="test" default="report">
<property name="src.java.dir" value="src/java"/>
<property name="src.test.dir" value="src/test"/>
<property name="classes.java.dir" value="class/java" />
<property name="classes.test.dir" value="class/test" />


<target name="init">
<mkdir dir="${classes.java.dir}" />
<mkdir dir="${classes.test.dir}" />
</target>

<target name="javacJava" depends="init">
<javac srcdir="${src.java.dir}/cn/itcast" destdir="${classes.java.dir}" />
</target>


<target name="javacTest" depends="init">
<javac srcdir="${src.test.dir}/cn/itcast" destdir="${classes.test.dir}" >
<classpath>
<pathelement location="${classes.java.dir}" />
</classpath>
</javac>
</target>

<target name="javacAll" depends="javacJava,javacTest"/>

<target name="run" depends="javacAll">
<mkdir dir="reports"/>
<mkdir dir="html"/>
<junit fork="true" printsummary="on">
<classpath>
<pathelement location="C:/junit3.8.1/junit.jar" />
<pathelement location="${classes.test.dir}" />
<pathelement location="${classes.java.dir}" />
</classpath>

<batchtest fork="yes" todir="reports">
<fileset dir="${src.test.dir}">
<include name="**/*Test*.java"/>
<exclude name="**/AllTests.java"/>
</fileset>
</batchtest>
<!--usefile="false"-->
<formatter type="brief" />
<formatter type="plain"/>
<formatter type="xml"/>
</junit>
</target>

<target name="report" depends="run">
<junitreport todir=".">
<fileset dir="./reports">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="./html"/>
</junitreport>
</target>


<target name="clean">
<delete dir="${classes.test.dir}" />
<delete dir="${classes.java.dir}" />
</target>

</project>

-----------------------------------

package cn.itcast;
import junit.framework.*;

public class TestMyNewClass extends TestCase
{
private String massage = "Hi! I`m fine.";
private String errormassage = "Hello! friend.";
private MyNewClass mnc;

public void setUp()
{
mnc = new MyNewClass();
}

public void testprintMassage()
{
int num = mnc.printMassage(errormassage);
assertEquals(num,1);
}
public void testerror()
{
int num = mnc.printMassage(massage);
assertEquals(num,0);
}
public void testprintError()
{
mnc.printError(null);
fail();
}
}

--------------------------------------

package cn.itcast;
import java.lang.IllegalArgumentException;


public class MyNewClass
{
public int printMassage(String massage)
{
if(massage.equals("Hello! friend."))
{
System.out.print(massage);
return 1;
}
else
{
System.out.print(massage);
return 0;
}

}
public void printError(MyNewClass obj)
{
if(obj == null)
{
throw new IllegalArgumentException();
//obj = new MyNewClass();
//obj.printMassage("Hello!");
}
else
{
obj.printMassage("This is printError()");
}
}

}