主要介紹如何使用 Ant 打包發布項目。
Ant 是一個將軟件編譯、測試、部署等步驟聯系在一起加以自動化的一個工具,大多用於 Java 環境中的軟件開發。在實際軟件開發中,有很多地方可以用到 Ant。
優點
Ant 是 Apache 軟件基金會 JAKARTA 目錄中的一個子項目,它有以下的優點:
1、跨平台性:Ant 是純 Java 語言編寫的,所以具有很好的跨平台性。
2、操作簡單:Ant 是由一個內置任務和可選任務組成的,用 Ant 任務就像是在 dos 中寫命令行一樣。Ant 運行時需要一個 XML 文件(構建文件)。 Ant 通過調用 target 樹,就可以執行各種 task。每個 task 實現了特定接口對象。
3、維護簡單、可讀性好、集成簡單:由於 Ant 構建文件是 XML 格式的文件,所以很容易維護和書寫,而且結構很清晰。Ant 可以集成到開發環境中。由於 Ant 的跨平台性和操作簡單的特點,它很容易集成到一些開發環境中去。
Ant 可以使用單獨的 Ant 安裝,或者直接使用IDE集成的 Ant 插件(我們只需要寫 Ant 的 build.xml 文件就可以執行 Ant 打包任務)
以下是 Java 的 Web 項目實例,通過使用 Myeclipse 集成的 Ant 執行打包任務,主要介紹 build.xml 配置規則。
代碼結構:
關鍵代碼:
build.properties
#appserver.lib是tomcat的library appserver.lib=D\:\\library\\develop\\tomcat6\\lib #antwebproj.lib是antproj項目的library antwebproj.lib=D\:\\library\\develop\\struts2\\base #項目打包版本 version.num=1.0
build.xml
<?xml version="1.0" encoding="UTF-8"?> <project basedir="." default="usage" name="antproj"> <!-- 引入配置文件 --> <property file="build.properties" /> <!-- 配置引用屬性 --> <property name="src.dir" value="src" /> <property name="config.dir" value="config" /> <property name="build.dir" value="build" /> <property name="web.dir" value="WebRoot" /> <property name="name" value="antproj" /> <path id="master-classpath"> <!-- We need the servlet API classes: --> <!-- * for Tomcat 5/6 use servlet-api.jar --> <!-- * for other app servers - check the docs --> <fileset dir="${appserver.lib}"> <include name="*.jar" /> </fileset> <fileset dir="${antwebproj.lib}"> <include name="*.jar" /> </fileset> <pathelement path="${build.dir}" /> </path> <target name="usage"> <!-- 輸出信息到控制台中 --> <echo message="" /> <echo message="${name} build file" /> <echo message="-----------------------------------" /> <echo message="" /> <echo message="Available targets are:" /> <echo message="" /> <echo message="build --> Build the application" /> <echo message="" /> </target> <!-- 編譯生成class文件 --> <target name="build" description="Compile main source tree java files"> <!-- 刪除編譯存放的classes文件 --> <delete dir="${build.dir}/classes"></delete> <!-- 新建編譯存放的classes文件 --> <mkdir dir="${build.dir}/classes" /> <copy todir="${build.dir}/classes"> <!-- 將項目中除會編譯生成class文件的java文件之外其他類型的文件拷貝到對應的目錄下,指定文件名后綴 --> <fileset dir="${src.dir}"> <include name="**/*.properties" /> <include name="**/*.xml" /> <!-- 這個是不包含 <exclude/> --> </fileset> <fileset dir="${config.dir}"> <include name="**/*.properties" /> <include name="**/*.xml" /> </fileset> </copy> <!-- java編譯 --> <javac destdir="${build.dir}/classes" source="1.5" target="1.5" debug="true" deprecation="false" optimize="false" failonerror="true" encoding="utf-8"> <src path="${src.dir}" /> <!-- 編譯所需要的jar包路徑 --> <classpath refid="master-classpath" /> </javac> </target> <target name="jar" depends="build" description="Compress the java class files to jar"> <mkdir dir="${build.dir}/jar" /> <delete file="${build.dir}/jar/${name}.jar" /> <buildnumber file="${build.dir}/buildnum.txt" /> <!-- 指定時間戳 可以調用TODAY --> <tstamp> <format property="TODAY" pattern="yyyy-MM-dd HH:mm:ss" /> </tstamp> <!-- 生成清單文件 --> <manifest file="${build.dir}/MANIFEST.MF"> <attribute name="Built-By" value="${user.name}" /> <attribute name="Implementation-Version" value="${version.num}.${build.number}" /> <attribute name="Built-Date" value="${TODAY}" /> </manifest> <!-- 打包jar --> <!-- includes 包含哪些后綴文件 空格分隔 --> <jar destfile="${build.dir}/jar/${name}.jar" basedir="${build.dir}/classes" includes="**/*.class **/*.properties **/*.xml" manifest="${build.dir}/MANIFEST.MF"> <zipfileset dir="${antwebproj.lib}"> <include name="*.jar"/> </zipfileset> </jar> </target> <!-- depends指的是執行該任務,會先執行那個任務 --> <target name="deploywar" depends="build" description="Deploy application as a WAR file"> <!-- 指定時間戳 可以調用VERSIONDAY --> <tstamp> <format property="VERSIONDAY" pattern="yyyyMMdd" /> </tstamp> <delete file="${build.dir}/war/${name}.war" /> <!-- 刪除WEB路徑下的jar包 --> <delete file="${web.dir}/WEB-INF/lib/*.jar" /> <mkdir dir="${build.dir}/war" /> <copy overwrite="true" todir="${web.dir}/WEB-INF/lib"> <!-- 將實際的jar包拷到WEB路徑下 --> <fileset dir="${antwebproj.lib}"> <include name="*.jar" /> </fileset> </copy> <!-- 將之前編譯生成的classes路徑下的編譯結果拷貝到WEB路徑下 --> <copy todir="${web.dir}/WEB-INF/classes" overwrite="true"> <fileset dir="${build.dir}/classes"></fileset> </copy> <!-- 刪除版本文件 --> <delete file="${src.dir}/com/alfred/VersionResources.properties" /> <!-- 重新寫入版本文件 --> <echo file="${web.dir}/WEB-INF/classes/com/alfred/VersionResources.properties" message="antproj.version=v${version.num}.${build.number}.${VERSIONDAY}" /> <echo file="${src.dir}/com/alfred/VersionResources.properties" message="antproj.version=v${version.num}.${build.number}.${VERSIONDAY}" /> <!-- 打包war --> <war destfile="${name}.war" webxml="${web.dir}/WEB-INF/web.xml"> <fileset dir="${web.dir}"> <!-- 包括哪些文件 --> <include name="**/*.*" /> <!-- 不包括哪些文件 --> <exclude name="**/documents/**" /> <exclude name="**/logs/*.log" /> </fileset> </war> <!-- 將war包拷貝到build的war目錄下 --> <copy todir="${build.dir}/war" preservelastmodified="true"> <fileset dir="."> <include name="*.war" /> </fileset> </copy> <delete> <fileset file="${web.dir}/WEB-INF/lib/*.jar" /> <fileset file="./*.war" /> <fileset dir="${build.dir}/classes" includes="**/*.*" /> </delete> </target> <target name="cleanup"> <!-- 刪除編譯文件夾下的所有文件(不包括編譯文件夾下的文件夾) <delete> <fileset dir="${build.dir}/classes" includes="**/*.*" /> </delete> --> <!-- 刪除編譯文件夾 --> <delete dir="${build.dir}/classes" /> </target> </project>
右鍵build.xml執行jar和deploywar任務后,在build目錄下生成jar包以及war包,打包結果如下:
Ant腳本說明:使用節點、元素和屬性、命令指令
1、project 節點元素
project 元素是 Ant 構件文件的根元素, Ant 構件文件至少應該包含一個 project 元素,否則會發生錯誤。在每個 project 元素下,可包含多個 target 元素。接下來向讀者展示一下 project 元素的各屬性。
● name 屬性:用於指定 project 元素的名稱。
● default 屬性:用於指定 project 默認執行時所執行的 target 的名稱。
● basedir 屬性:用於指定基路徑的位置。該屬性沒有指定時,使用 Ant 的構件文件的附目錄作為基准目錄。
<?xml version="1.0" ?> <project name="ant-project" default="print-dir" basedir="."> <target name="print-dir"> <echo message="The base dir is: ${basedir}" /> </target> </project>
2、target節點元素
target為ant的基本執行單元或是任務,它可以包含一個或多個具體的單元/任務。多個target 可以存在相互依賴關系。它有如下屬性:
● name 屬性:指定 target 元素的名稱,這個屬性在一個 project 元素中是唯一的。我們可以通過指定 target 元素的名稱來指定某個 target 。
● depends 屬性:用於描述 target 之間的依賴關系,若與多個 target 存在依賴關系時,需要以“,”間隔。 Ant 會依照 depends 屬性中 target 出現的順序依次執行每個 target ,被依賴的target 會先執行。
● if 屬性:用於驗證指定的屬性是存在,若不存在,所在 target 將不會被執行。
● unless 屬性:該屬性的功能與 if 屬性的功能正好相反,它也用於驗證指定的屬性是否存在,若不存在,所在 target 將會被執行。
● description 屬性:該屬性是關於 target 功能的簡短描述和說明。
<?xml version="1.0" ?> <project name="ant-target" default="print"> <target name="version" if="ant.java.version"> <echo message="Java Version: ${ant.java.version}" /> </target> <target name="print" depends="version" unless="docs"> <description> a depend example! </description> <echo message="The base dir is: ${basedir}" /> </target> </project>
運行的是名為 print的target ,由於它依賴於version這個target任務,所以 version將首先被執行,同時因為系統配置了JDK,所以 ant.java.version 屬性存在,執行了version,輸出信息:"[echo] Java Version: 1.6 ",version執行完畢后,接着執行 print,因為docs不存在,而unless屬性是在不存在時進入所在target 的,由此可知 print得以執行。
3、property屬性節點元素
property元素可看作參量或者參數的定義,project 的屬性可以通過 property 元素來設定,也可在 Ant 之外設定。若要在外部引入某文件,例如 build.properties 文件,可以通過如下內容將其引:
<property file="build.properties"/>
property 元素可用作 task 的屬性值。在 task 中是通過將屬性名放在${屬性名}之間,並放在 task 屬性值的位置來實現的。
Ant 提供了一些內置的屬性,它能得到的系統屬性的列表與 Java 文檔中 System.getProperties() 方法得到的屬性一致,這些系統屬性可參考 sun 網站的說明。同時, Ant 還提供了一些它自己的內置屬性,如下:
basedir: project 基目錄的絕對路徑;
ant.file: buildfile的絕對路徑;
ant.version: Ant 的版本信息;
ant.project.name: 當前指定的project的名字,即前文說到的project的name屬性值;
ant.java.version: Ant 檢測到的JDK版本,本文為 1.6 。
<project name="ant-project" default="example"> <property name="name" value="jojo" /> <property name="age" value="25" /> <target name="example"> <echo message="name: ${name}, age: ${age}" /> </target> </project>
4、copy命令
copy主要用來對文件和目錄的復制功能。舉例如下:
● 復制單個文件:
<copy file="old.txt" tofile="new.txt"/>
● 對文件目錄進行復制:
<copy todir="../dest_dir">
<fileset dir="src_dir"/>
</copy>
● 將文件復制到另外的目錄:
<copy file="src.txt" todir="c:/base"/>
5、delete命令
對文件或目錄進行刪除,舉例如下:
● 刪除某個文件:
<delete file="/res/image/cat.jpg"/>
● 刪除某個目錄:
<delete dir="/res/image"/>
● 刪除所有的jar文件或空目錄:
<delete includeEmptyDirs="true">
<fileset dir="." includes="**/*.jar"/>
</delete>
6、 mkdir 命令
創建目錄。
<mkdir dir="/home/philander/build/classes"/>
7、 move 命令
移動文件或目錄,舉例如下:
● 移動單個文件:
<move file="sourcefile" tofile=”destfile”/>
● 移動單個文件到另一個目錄:
<move file="sourcefile" todir=”movedir”/>
● 移動某個目錄到另一個目錄:
<move todir="newdir">
<fileset dir="olddir"/>
</move>
8、echo 命令
該任務的作用是根據日志或監控器的級別輸出信息。它包括 message 、 file 、 append 和 level 四個屬性,舉例如下
<echo message="ant message" file="/logs/ant.log" append="true">
9、jar 標簽節點元素
該標簽用來生成一個JAR文件,其屬性如下。
● destfile表示JAR文件名。
● basedir表示被歸檔的文件名。
● includes表示別歸檔的文件模式。
● exchudes表示被排除的文件模式。
● compress表示是否壓縮。
<jar destfile="${webRoot}/${ash_jar}" level="9" compress="true" encoding="utf-8" basedir="${dest}"> <manifest> <attribute name="Implementation-Version" value="Version: 2.2"/> </manifest> </jar>
上面的mainfest是jar包中的MEAT-INF中的MANIFEST.MF中的文件內容
同樣打包操作的的還有war、tgz,已經解壓操作uzip
<!-- 創建zip --> <zip basedir="${basedir}\classes" zipfile="temp\output.zip"/> <!-- 創建tgz --> <gzip src="classes\**\*.class" zipfile="output.class.gz"/> <!-- 解壓zip --> <unzip src="output.class.gz" dest="extractDir"/> <!-- 建立war包 --> <war destfile="${webRoot}/ash.war" basedir="${basedir}/web" webxml="${basedir}/web/WEB-INF/web.xml"> <exclude name="WEB-INF/classes/**"/> <exclude name="WEB-INF/lib/**"/> <exclude name="WEB-INF/work/_jsp/**"/> <lib dir="${lib.dir}" includes="**/*.jar, **/*.so, **/*.dll"> <exclude name="${webRoot}\${helloworld_jar}"/> </lib> <lib file="${webRoot}/${helloworld_jar}"/> <classes dir="${dest}" includes="**/*.xml, **/*.properites, **/*.xsd"> </classes> </war>
10、javac 標簽節點元素
該標簽用於編譯一個或一組java文件,其屬性如下。
● srcdir表示源程序的目錄。
● destdir表示class文件的輸出目錄。
● include表示被編譯的文件的模式。
● excludes表示被排除的文件的模式。
● classpath表示所使用的類路徑。
● debug表示包含的調試信息。
● optimize表示是否使用優化。
● verbose 表示提供詳細的輸出信息。
● fileonerror表示當碰到錯誤就自動停止。
<javac srcdir="${src}" destdir="${dest}"/> <!-- 設置jvm內存 <javac srcdir="src" fork="true"/> <javac srcdir="src" fork="true" executable="d:\sdk141\bin\javac" memoryMaximumSize="128m"/> -->
11、java 標簽節點元素
該標簽用來執行編譯生成的.class文件,其屬性如下。
● classname 表示將執行的類名。
● jar表示包含該類的JAR文件名。
● classpath所表示用到的類路徑。
● fork表示在一個新的虛擬機中運行該類。
● failonerror表示當出現錯誤時自動停止。
● output 表示輸出文件。
● append表示追加或者覆蓋默認文件。
<java classname="com.hoo.test.HelloWorld" classpath="${hello_jar}"/>
12、arg 數據參數元素
由Ant構建文件調用的程序,可以通過<arg>元素向其傳遞命令行參數,如apply,exec和java任務均可接受嵌套<arg>元素,可以為各自的過程調用指定參數。以下是<arg>的所有屬性。
● values 是一個命令參數。如果參數中有空格,但又想將它作為單獨一個值,則使用此屬性。
● file 表示一個參數的文件名。在構建文件中,此文件名相對於當前的工作目錄。
● line 表示用空格分隔的多個參數列表。
● 表示路徑,一個作為單個命令行變量的path-like的字符串;或作為分隔符,Ant會將其轉變為特定平台的分隔符。
● pathref 引用的path(使用path元素節點定義path)的id
● prefix 前綴
● suffix 后綴
<!-- 一個含有空格的單個的命令行變量。 --> <arg value="-l -a"/> <!-- 兩個空格分隔的命令行變量。 --> <arg line="-l -a"/> <!-- 一個命令行變量,其值在DOS系統上為\dir;\dir2;\dir3;在Unix系統上為/dir:/dir2:/dir3 。 --> <arg path="/dir;/dir2:\dir3"/>
13、ervironment 類型
由Ant構建文件調用的外部命令或程序,<env>元素制定了哪些環境變量要傳遞給正在執行的系統命令,<env>元素可以接受以下屬性。
● file表示環境變量值的文件名。此文件名要被轉換位一個絕對路徑。
● path表示環境變量的路徑。Ant會將它轉換為一個本地約定。
● value 表示環境變量的一個直接變量。
● key 表示環境變量名。
注意 file path 或 value只能取一個。
14、filelist 文件集合列表
filelist 是一個支持命名的文件列表的數據類型,包含在一個filelist類型中的文件不一定是存在的文件。以下是其所有的屬性。
● dir是用於計算絕對文件名的目錄。
● files 是用逗號分隔的文件名列表。
● refid 是對某處定義的一個<filelist>的引用。
注意 dir 和 files 都是必要的,除非指定了refid(這種情況下,dir和files都不允許使用)。
<filelist id="docfiles" dir="${doc.src}" files="foo.xml,bar.xml"/> <!-- 文件集合 ${doc.src}/foo.xml和${doc.src}/bar.xml. 這些文件也許還是不存在的文件.--> <filelist id="docfiles" dir="${doc.src}" files="foo.xml bar.xml"/> <filelist refid="docfiles"/> <filelist id="docfiles" dir="${doc.src}"> <file name="foo.xml"/> <file name="bar.xml"/> </filelist>
15、fileset 文件類型
fileset 數據類型定義了一組文件,並通常表示為<fileset>元素。不過,許多ant任務構建成了隱式的fileset,這說明他們支持所有的fileset屬性和嵌套元素。以下為fileset 的屬性列表。
● dir表示fileset 的基目錄。
● casesensitive的值如果為false,那么匹配文件名時,fileset不是區分大小寫的,其默認值為true.
● defaultexcludes 用來確定是否使用默認的排除模式,默認為true。
● excludes 是用逗號分隔的需要派出的文件模式列表。
● excludesfile 表示每行包含一個排除模式的文件的文件名。
● includes 是用逗號分隔的,需要包含的文件模式列表。
● includesfile 表示每行包括一個包含模式的文件名。
<fileset id="lib.runtime" dir="${lib.path}/runtime"> <include name="**/*.jar"/> <include name="**/*.so"/> <include name="**/*.dll"/> </fileset> <fileset id="lib.container" dir="${lib.path}/container"> <include name="**/*.jar"/> </fileset> <fileset id="lib.extras" dir="${lib.path}"> <include name="test/**/*.jar"/> </fileset>
16、patternset 類型
fileset 是對文件的分組,而patternset是對模式的分組,他們是緊密相關的概念。
<patternset>支持4個屬性:includes、excludex、includexfile、excludesfile,這些與fileset相同。
patternset 還允許以下嵌套元素:include,exclude,includefile 和 excludesfile.
<!-- 黑白名單 --> <patternset id="non.test.sources"> <include name="**/*.java"/> <!-- 文件名包含Test的排除 --> <exclude name="**/*Test*"/> </patternset> <patternset id="sources"> <include name="std/**/*.java"/> <!-- 判斷條件 存在professional就引入 --> <include name="prof/**/*.java" if="professional"/> <exclude name="**/*Test*"/> </patternset> <!-- 一組文件 --> <patternset includesfile="some-file"/> <patternset> <includesfile name="some-file"/> <patternset/> <patternset> <includesfile name="some-file"/> <includesfile name="${some-other-file}" if="some-other-file"/> <patternset/>
17、filterset 類型
filterset定義了一組過濾器,這些過濾器將在文件移動或復制時完成文件的文本替換。
主要屬性如下:
● begintoken 表示嵌套過濾器所搜索的記號,這是標識其開始的字符串。
● endtoken 表示嵌套過濾器所搜索的記號這是標識其結束的字符串。
● id 是過濾器的唯一標志符。
● refid 是對構建文件中某處定義一個過濾器的引用。
<!-- 將目標文件build.dir目錄中的version.txt文件內容中的@DATE@替換成TODAY當前日期的值,並把替換后的文件存放在dist.dir目錄中 --> <copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt"> <filterset> <filter token="DATE" value="${TODAY}"/> </filterset> </copy> <!-- 自定義變量的格式 --> <copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt"> <!-- 從version.txt中的%位置開始搜索,到*位置結束,進行替換內容中的@DATE@替換成TODAY當前日期的值--> <filterset begintoken="%" endtoken="*"> <filter token="DATE" value="${TODAY}"/> </filterset> </copy> <!-- 使用外部的過濾定義文件 --> <copy toDir="${dist.dir}/docs"> <fileset dir="${build.dir}/docs"> <include name="**/*.html"> </fileset> <filterset begintoken="%" endtoken="*"> <!-- 過來文件從外部引入,過來的屬性和值配置在dist.properties文件中 --> <filtersfile file="${user.dir}/dist.properties"/> </filterset> </copy> <!-- 使用引用方式,重復利用過濾集 --> <filterset id="myFilterSet" begintoken="%" endtoken="*"> <filter token="DATE" value="${TODAY}"/> </filterset> <copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt"> <filterset refid="myFilterSet"/> </copy>
18、path類型
path元素用來表示一個類路徑,不過它還可以用於表示其他的路徑。在用作幾個屬性時,路經中的各項用分號或冒號隔開。在構建的時候,此分隔符將代替當前平台中所有的路徑分隔符,其擁有的屬性如下。
● location 表示一個文件或目錄。Ant在內部將此擴展為一個絕對路徑。
● refid 是對當前構建文件中某處定義的一個path的引用。
● path表示一個文件或路徑名列表。
<path id="buildpath"> <fileset refid="lib.runtime"/> <fileset refid="lib.container"/> <fileset refid="lib.extras"/> </path> <path id="src.paths"> <fileset id="srcs" dir="."> <include name="src/**/*.java"/> </fileset> </path>
以上是部分ant的配置項說明,如果需要其他相關配置,可以查詢ant的幫助文檔。


