Ant
ant为自动化构建工具,在项目根目录中添加build.xml文件,ant可以按照该文件进行编译、测试、打包、执行等工作。
在build.xml文件中,包含一个project和若干个target子元素,而每个target又可以包含若干task元素。build.xml文件结构如下
<?xml version="1.0" encoding="UTF-8"?>
<project>
<target name="clean">
<delete dir="build"></delete>
</target>
<target name="init" depends="clean">
<mkdir dir="build"/>
</target>
</project>
1、 构建过程
使用ant进行项目构建的一般过程为:
1) 构建文件组织结构
在使用ant进行构建时,最好保持源代码与生产文件的分离,一般按照如下格式来组织文件结构:
-project
-build
-build-src
-build-classes
-build-dist
l build:放置所有的文件
l src:源码文件
l classes:编译后的类文件
l dist:打包后的jar文件
2) 编译
3) 测试
4) 打包
5) 发布
一个简单的javase项目构建文件如下
<?xml version="1.0" encoding="UTF-8"?>
<project default="execute">
<!--文件集-->
<fileset id="src.path" dir="src">
<include name="**/*.*"/>
<exclude name="**/*.properties"/>
</fileset>
<!--清除文件-->
<target name="clean">
<delete dir="build"/>
</target>
<!--构建文件结构-->
<target name="init" depends="clean">
<mkdir dir="build"/>
<mkdir dir="build/src"/>
<mkdir dir="build/classes"/>
<mkdir dir="build/dist"/>
</target>
<!--复制源代码-->
<target name="copy" depends="init">
<copy todir="build/src">
<fileset refid="src.path"/>
</copy>
</target>
<!--编译-->
<target name="compile" depends="init">
<javac srcdir="src" destdir="build/classes"/>
</target>
<!--打包-->
<target name="jar" depends="compile">
<jar destfile="build/dist/Main.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="main.Main"/>
<attribute name="Build-By" value="ssl"/>
</manifest>
</jar>
</target>
<!--运行-->
<target name="execute" depends="copy,jar">
<echo>基于class文件执行</echo>
<java classname="main.Main" classpath="build/classes">
<arg value="ssl"/>
<arg value="lff"/>
</java>
<echo>基于jar文件执行</echo>
<java jar="build/dist/Main.jar" fork="true">
<arg value="ssl"/>
<arg value="lff"/>
</java>
</target>
</project>
2、 标签
在使用ant进行构建时,会涉及到文件夹、路径、编译、打包等基本操作,为了更好的使用ant,我们需要了解ant提供的一些基本元素,如属性,文件集,路径等。
2.1、project
project有三个属性:
l name指定项目的名字;
l basedir指定项目的根路径,该属性可以覆盖basedir Property属性。如果没有指定basedir和basedirProperty,则默认为build.xml文件的父目录;
l default指定默认要执行的target;
2.2、属性
在使用ant时,可以使用<property>子元素定义属性,使用方式为:${propertyName},如下
<property name="build.dir" value="build"/>
<property name="build.src" location="${build.dir}/src"/>
<property name="build.classes" location="${build.dir}/dist"/>
<property name="build.dist"location="${build.dir}/dist"/>
在定义属性时,可以使用value来指定属性的值;若属性为某个文件的路径,需要使用location来指定属性的值,使用location指定路径的值,ant可以确保平台无关的路径格式。
定义属性,目的是为了避免在target中直接使用字面值,若路径发生变化,则与此路径相关的所有字面值都要改变;而使用属性,只需更改属性值即可,如下
<?xml version="1.0" encoding="UTF-8"?>
<project>
<property name="build.dir" value="build"/>
<property name="build.src" location="${build.dir}/src"/>
<property name="build.classes" location="${build.dir}/classes"/>
<property name="build.dist" location="${build.dir}/dist"/>
<property name="jar.name" value="ssl-01"></property>
<fileset id="src.path" dir="src"includes="**/*.*"></fileset>
<target name="clean">
<delete dir="${build.dir}"></delete>
</target>
<target name="init" depends="clean">
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.src}"/>
<mkdir dir="${build.classes}"/>
<mkdir dir="${build.dist}"/>
</target>
<target name="copy">
<copy todir="${build.src}">
<fileset refid="src.path"></fileset>
</copy>
</target>
<target name="compile" depends="init">
<javac srcdir="src" destdir="${build.classes}"></javac>
</target>
<target name="jar" depends="compile,copy">
<jar basedir="${build.classes}"destfile="${build.dist}/${jar.name}.jar"></jar>
</target>
</project>
如果属性过多,可以将属性定义在.properties文件中,在build.xml文件中引入即可<propertyfile="xxx.properties"/>;但需要注意引入.properties文件,使用的name-value对,若要是路径最好在build.xml中定义。
2.3、文件集
在进行复制操作时,往往需要指明复制那些文件,此时需要使用文件集。fileset可以设定一组文件来进行操作,dir指明文件集要进行选择的路径,可以指定id属性,在使用的时候可以直接通过id进行引用。include和exclude可以设定包含和排除的范围,**表示所有目录,*.*表示所有文件,如下
<!--文件集-->
<fileset id="src.path" dir="src">
<include name="**/*.*"/>
<exclude name="**/*.properties"/>
</fileset>
2.4、path、classpath
path、classpath元素用来表示一个类路径,在path标签内可以嵌套path标签,表示引用其他路径;也可以使用fileset子标签来指定路径。
<!--指定编译源文件所需的jar包-->
<pathid="compile.path">
<filesetdir="${lib.dir}"includes="*.jar"></fileset>
</path>
<!--指定编译单元源测试所需的jar包,单元测试以来源文件的class和jar包-->
<pathid="test.compile.path">
<pathrefid="compile.path"/>
<pathelementlocation="${build.classes}"/>
</path>
l pthelement中location 表示一个文件或目录,ant会将其扩展为绝对路径;而pathelement中path可以表示多个目录,多个路径之间可以用分号分割;
l refid是对当前构建文件中定义path的引用;
2.5、ID引用
在定义类路径时可以引用其他已定义的类路径。
2.6、新建文件
可以使用<mkdir>元素来创建文件,如下
<target name="init" depends="clean">
<mkdir dir="build"/>
<mkdir dir="build/src"/>
<mkdir dir="build/classes"/>
<mkdir dir="build/dist"/>
</target>
2.7、删除文件
可以使用<delete>元素删除文件,如下
<!--清除文件-->
<target name="clean">
<delete dir="build"/>
</target>
l file表示要删除的文件;
l dir表示要删除的目录;
2.8、复制文件
可以使用<copy>元素来复制文件,但需要指明需要复制那些文件,如下
<!--文件集-->
<fileset id="src.path" dir="src">
<include name="**/*.*"/>
<exclude name="**/*.properties"/>
</fileset>
<!--复制源代码-->
<target name="copy" depends="init">
<copy todir="build/src">
<filesetrefid="src.path"/>
</copy>
</target>
l file表示源文件
l tofile表示目标文件;
l todir表示目标目录;
2.9、编译
使用<javac>元素来进行编译,需要指明编译的源文件路径,以及编译后class文件的存放地址,如下
<!--编译-->
<target name="compile" depends="init">
<javac srcdir="src" destdir="build/classes"/>
</target>
l srcdir表示源文件的目录
l destdir表示class文件的输出目录
l classpath表示所使用的类路径
2.10、打包
使用<jar>元素对文件进行打包,需要指定打包的源文件地址和打包后jar文件的存放地址,如下
<target name="jar" depends="compile">
<jar destfile="build/dist/Main.jar"basedir="build/classes"/>
</target>
使用<jar>元素对文件进行打包,需要指定打包的源文件地址和打包后jar文件的存放地址,如下
若打包的jar文件中包含main函数,则该jar文件是可以运行的jar文件,但需要在jar文件中添加MAINFEST文件,该文件指明了main函数所在的类,在build.xml中可以使用<manifest>元素来为jar文件添加MAINFEST文件,并添加相应的属性,如下
<target name="jar" depends="compile">
<jar destfile="build/dist/Main.jar" basedir="build/classes">
<manifest>
<attributename="Main-Class"value="main.Main"/>
<attribute name="Build-By" value="ssl"/>
</manifest>
</jar>
</target>
l destfile表示jar文件名
l basedir表示被归档的文件夹
l includes表示被归档的文件
2.11、运行
运行分为两种情况,一种是运行class文件,另一种是运行jar文件;在运行是可以通过<arg>元素来指定参数,如下
<!--运行-->
<target name="execute" depends="copy,jar">
<echo>基于class文件执行</echo>
<java classname="main.Main" classpath="build/classes">
<arg value="ssl"/>
<arg value="lff"/>
</java>
<echo>基于jar文件执行</echo>
<java jar="build/dist/Main.jar" fork="true">
<arg value="ssl"/>
<arg value="lff"/>
</java>
</target>
l classpath表示所用到的类路径;
l fork表示在一个新的虚拟机中运行该类;
l failonerror表示出现错误时自动停止;
2.12、环境变量
<property environment="env"/>
<echo> ${env.ANT_HOME}</echo>
通过propert元素,可以将系统环境变量的所有参数存储到env中,以便在使用的时候进行引用。如在发布web项目时,需要将war包发布在tomcat目录中,此时就需要获取tomcat的根目录。
2.13、依赖
任务之间是可以依赖的,在执行该任务之前会先执行其所依赖的所有任务,如下
<!--清除文件-->
<target name="clean">
<delete dir="build"/>
</target>
<!--构建文件结构-->
<target name="init" depends="clean">
<mkdir dir="build"/>
<mkdir dir="build/src"/>
<mkdir dir="build/classes"/>
<mkdir dir="build/dist"/>
</target>
3、 单元测试
我们可以使用ant来进行自动化测试,并生成测试报告。使用Ant进行单元测试的过程如下:
l 创建文件组织结构
l 编译源文件
在编译源文件时,若第三方库文件(如junit)是由IDE管理的,ant是不能链接这些库文件的。因此在使用第三方库文件时,需要在项目根目录添加lib文件,将需要的库文件都放在lib中。在编译时,添加classpath指定库文件路径,如下
<!--指定编译源文件所需的jar包-->
<pathid="compile.path">
<filesetdir="${lib.dir}"includes="*.jar"></fileset>
</path>
<target name="compile" depends="init">
<javac includeantruntime="true" failοnerrοr="true" srcdir="${src.dir}" destdir="${build.classes}" classpathref="compile.path"></javac>
</target>
l 编译测试文件
编译测试文件不仅需要其他库文件还需要源文件对应的class文件,所以在编译测试文件时,不仅需要在路径中指定其他库文件的位置,还要包含源文件class的位置,如下
<!--指定编译源文件所需的jar包-->
<pathid="compile.path">
<filesetdir="${lib.dir}"includes="*.jar"></fileset>
</path>
<!--指定编译单元源测试所需的jar包,单元测试以来源文件的class和jar包-->
<pathid="test.compile.path">
<pathrefid="compile.path"/>
<pathelementlocation="${build.classes}"/>
</path>
<target name="test-compile" depends="test-init">
<javac failοnerrοr="true" includeantruntime="true" srcdir="${test.dir}" destdir="${build.test.classes}" classpathref="test.compile.path"></javac>
</target>
l 运行单元测试
在运行单元测试时,不经需要指明单元测试类的class文件位置,还需要指定编译单元测试时所需要的class文件,如下
<!--指定编译源文件所需的jar包-->
<pathid="compile.path">
<filesetdir="${lib.dir}"includes="*.jar"></fileset>
</path>
<!--指定编译单元源测试所需的jar包,单元测试以来源文件的class和jar包-->
<pathid="test.compile.path">
<pathrefid="compile.path"/>
<pathelementlocation="${build.classes}"/>
</path>
<pathid="test.run.path">
<pathrefid="test.compile.path"/>
<pathelementlocation="${build.test.classes}"/>
</path>
<!--运行单元测试-->
<target name="test-run" depends="test-compile">
<junit printsummary="true">
<classpathrefid="test.run.path"></classpath>
<formatter type="brief" usefile="false"/>
<formattertype="xml"/>
<!--测试结构输出目录-->
<batchtesttodir="${build.test.report}">
<filesetdir="${build.test.classes}"includes="**/*.class"></fileset>
</batchtest>
</junit>
<junitreport todir="${build.test.report}">
<fileset dir="${build.test.report}" includes="*.xml"></fileset>
<report format="frames" todir="${build.test.report}/html"/>
</junitreport>
</target>
l 生成测试报告
运行测试单元之后,可以使用<junitreport>来生成单元测试报告,需要指定生成报告的位置,以及生成报告的依赖文件。这些依赖文件是在运行单元测试时生成的文件,这些文件一般是xml文件格式。
一个简单的java se项目,编译,测试,打包的ant文件如下
<?xml version="1.0" encoding="UTF-8"?>
<project>
<!--定义属性-->
<property name="src.dir" location="src"></property>
<property name="build.dir" value="build"/>
<property name="build.src" location="${build.dir}/src"/>
<property name="build.classes" location="${build.dir}/classes"/>
<property name="build.lib" location="${build.dir}/lib"/>
<property name="build.doc" location="${build.dir}/doc"/>
<property name="test.dir" location="test"/>
<property name="build.test.dir" location="${build.dir}/test"/>
<property name="build.test.src" location="${build.test.dir}/src"/>
<property name="build.test.classes" location="${build.test.dir}/classes"/>
<property name="build.test.report" location="${build.test.dir}/report"/>
<property name="lib.dir" location="lib"/>
<property name="jar.name" value="ssl"/>
<property name="jar.version" value="1.0"/>
<property name="zip.dir" location="${build.dir}"/>
<property name="zip.name" value="ssl"/>
<property name="zip.version" value="1.0"/>
<!--文件集-->
<filesetid="src.path"dir="${src.dir}"includes="**/*.*"></fileset>
<filesetid="test.path"dir="${test.dir}"includes="**/*.*"></fileset>
<!--指定编译源文件所需的jar包-->
<pathid="compile.path">
<filesetdir="${lib.dir}"includes="*.jar"></fileset>
</path>
<!--指定编译单元源测试所需的jar包,单元测试以来源文件的class和jar包-->
<pathid="test.compile.path">
<pathrefid="compile.path"/>
<pathelementlocation="${build.classes}"/>
</path>
<pathid="test.run.path">
<pathrefid="test.compile.path"/>
<pathelementlocation="${build.test.classes}"/>
</path>
<target name="clean">
<delete dir="${build.dir}"></delete>
</target>
<target name="init" depends="clean">
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.src}"/>
<mkdir dir="${build.classes}"/>
<mkdir dir="${build.lib}"/>
<mkdir dir="${build.doc}"/>
</target>
<target name="copy">
<copy todir="${build.src}">
<fileset refid="src.path"></fileset>
</copy>
</target>
<target name="compile" depends="init">
<javac includeantruntime="true" failοnerrοr="true" srcdir="${src.dir}" destdir="${build.classes}" classpathref="compile.path"></javac>
</target>
<target name="jar" depends="compile,copy">
<jar basedir="${build.classes}"destfile="${build.lib}/${jar.name}-${jar.version}.jar"></jar>
</target>
<!--测试-->
<target name="test-init" depends="jar">
<mkdir dir="${build.test.dir}"/>
<mkdir dir="${build.test.src}"/>
<mkdir dir="${build.test.classes}"/>
<mkdir dir="${build.test.report}"/>
</target>
<target name="test-copy">
<copy todir="${build.test.src}">
<fileset refid="test.path"></fileset>
</copy>
</target>
<target name="test-compile" depends="test-init">
<javac failοnerrοr="true" includeantruntime="true" srcdir="${test.dir}" destdir="${build.test.classes}" classpathref="test.compile.path"></javac>
</target>
<!--运行单元测试-->
<target name="test-run" depends="test-compile">
<junit printsummary="true">
<classpathrefid="test.run.path"></classpath>
<formatter type="brief" usefile="false"/>
<formattertype="xml"/>
<!--测试结构输出目录-->
<batchtesttodir="${build.test.report}">
<filesetdir="${build.test.classes}"includes="**/*.class"></fileset>
</batchtest>
</junit>
<junitreport todir="${build.test.report}">
<fileset dir="${build.test.report}" includes="*.xml"></fileset>
<report format="frames" todir="${build.test.report}/html"/>
</junitreport>
</target>
<!--打包-->
<target name="doc" depends="init">
<javadoc sourcepath="${src.dir}" private="true" use="true" packagenames="com.ssl.*"
destdir="${build.doc}"charset="UTF-8" docencoding="UTF-8" encoding="UTF-8">
<classpath path="${build.classes}"></classpath>
</javadoc>
</target>
<target name="zip" depends="jar,doc">
<zip destfile="${zip.dir}/${zip.name}-${zip.version}.zip"duplicate="preserve">
<zipfileset dir="${build.src}" includes="**/*.*" prefix="src"/>
<zipfileset dir="${build.lib}" includes="**/*.*" prefix="lib"/>
<zipfileset dir="${build.doc}" includes="**/*.*" prefix="doc/api"/>
</zip>
</target>
<target name="ftp" depends="zip">
<!--建立文件夹-->
<ftp server=""userid="" password="" action="mkdir"remotedir=""></ftp>
<!--上传文件-->
<ftp server=""userid="" password="" action="put"remotedir="">
<fileset></fileset>
</ftp>
</target>
</project>
4、 文档
若要对源文件生成api文档,可以使用<javadoc>,需要指定源文件的位置,以及对那些包内的源文件生成api文档,如下
<!--打包-->
<target name="doc" depends="init">
<javadoc sourcepath="${src.dir}" private="true" use="true" packagenames="com.ssl.*" destdir="${build.doc}"charset="UTF-8" docencoding="UTF-8" encoding="UTF-8">
<classpathpath="${build.classes}"></classpath>
</javadoc>
</target>
5、 zip
对项目进行打包一般分为src、doc、lib等目录,打包可以使用<zip>,在<zip>内需要指定对那些文件打包,以及这些文件的前缀名(会自动生成前缀名的目录,将文件集内的文件放在该目录下),如下所示
<target name="zip" depends="jar,doc">
<zipdestfile="${zip.dir}/${zip.name}-${zip.version}.zip"duplicate="preserve">
<zipfilesetdir="${build.src}"includes="**/*.*"prefix="src"/>
<zipfilesetdir="${build.lib}"includes="**/*.*"prefix="lib"/>
<zipfilesetdir="${build.doc}"includes="**/*.*"prefix="doc/api"/>
</zip>
</target>
6、 war
ant发布web项目的步骤如下:
l 设置属性
l 编译
在编译web项目时,不仅要制定项目所需的依赖包,此外还要加载服务器中的lib。
l 打包war
打war包时需要制定web-inf,lib,classes以及页面等资源文件。
l 拷贝至服务器
<?xml version="1.0" encoding="UTF-8"?>
<project default="deploy">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="build.classes" location="${build.dir}/classes"/>
<property name="build.war" location="${build.dir}/war"/>
<property name="web.name" value="ant-web"/>
<property name="web.root" value="WebRoot"/>
<property name="web.WEB-INF" location="${web.root}/WEB-INF"/>
<property name="web.lib" location="${web.WEB-INF}/lib"/>
<property name="catalina.home" value="/Users/ssl/Applications/apache-tomcat-7.0.55"/>
<property environment="env"/>
<pathid="compile.path">
<filesetdir="${web.lib}"includes="*.jar"></fileset>
<filesetdir="${catalina.home}/lib"includes="*.jar"></fileset>
</path>
<target name="init">
<delete dir="${build.dir}"></delete>
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.classes}"/>
<mkdir dir="${build.war}"/>
</target>
<target name="compile" depends="init">
<javac srcdir="${src.dir}" destdir="${build.classes}" classpathref="compile.path"></javac>
</target>
<targetname="war"depends="compile">
<wardestfile="${build.war}/${web.name}.war">
<filesetdir="${web.root}"includes="**/*.*"></fileset>
<libdir="${web.lib}"></lib>
<webinfdir="${web.WEB-INF}"></webinf>
<classesdir="${build.classes}"></classes>
</war>
</target>
<target name="deploy" depends="war">
<copy todir="${catalina.home}/webapps">
<fileset dir="${build.war}" includes="*.war"></fileset>
</copy>
</target>
</project>
7、 扩展
7.1属性文件
可以使用ant向.properties文件中写入数据,以便记录每次构建的时间、次数以及其他信息等,如下
<target name="metadata">
<buildnumber/>
<propertyfile file="build.properties">
<entry key="build-time" type="date" value="now"pattern="yyyy-MM-dd HH:mm"/>
<entry key="build-number" type="int" value="${build.number}"/>
</propertyfile>
</target>
7.2数据库
在web项目中,往往需要连接数据库,ant可以使用presetdef、sql、sql-admin、transaction等来执行sql语句,以便自动创建数据库、表等,如下
<presetdef name="sql-admin">
<sql userid="" url=""password="" driver=""></sql>
</presetdef>
<target name="init-mysql">
<sql-admin>
<transaction src="xxx.sql"/>
</sql-admin>
</target>