ant配置文件的编写


http://blog.csdn.net/wqjsir/article/details/5691185

http://blog.csdn.net/wqjsir/article/details/5691185

http://blog.csdn.net/wqjsir/article/details/5691185





ant配置文件的编写

分类: 项目管理   1202人阅读  评论(0)  收藏  举报

(收藏)一下内容是从网络中摘抄的:

是apache的java子项目"jakarta"的子项目.你可以选择当前的版本,,window版解压后ant_home用来方便访问。并确保你也设置了java_home 。
set ant_home=D:/java/kit/ant/jakarta-ant-1.5.1 这是我的目录hello ant
我们要开发一个java类:其内容只有一句,输出"hello ant"字符串。并使用ant完成编译和运行工作,这个例子只是为了跑通ant,不附加多余的东西。

下面是:“hello.ant.HelloAnt.java”文件。

package hello.ant;

public class HelloAnt{
public static void main(String[] args){
System.out.println("hello ant,ant 的第一次接触,好棒!");

}

在项目根目录(hello-ant/)写1个文件:ant执行配置文件build.xml

“build.xml”文件

<?xml version="1.0" encoding="GB2312" ?>

<!-- 一个项目,可包含很多任务组(target) -->
<project default="main" basedir=".">

<!-- 项目中的一个任务组,可包含很多任务(task:javac,java...) -->
<target name="main">

<!--编译-->
<javac srcdir="src/main/hello/ant" destdir="build/classes"/>

<!--运行-->
<java classname="hello.ant.HelloAnt">
<classpath>
<pathelement path="build/classes"/>
</classpath>
</java>

</target>
</project>


ok,一切大功告成,哦,不,还没有运行它。

dos下进入hello-ant的目录,即build.xml所在的目录,我们要用ant工具执行它 ,

执行: %ant_home%/bin/ant -file build.xml 用ant工具执行当前目录下的配置文件build.xml

或 :ant -file build.xml 你如果设置%ant_home%/bin到path中

这次ok了,这是答案:

命令提示符窗口
D:/temp/hello-ant>ant -file build.xml
Build build.xml

main:
[javac] Compiling 1 source file to D:/temp/hello-ant/build/classes
[java] hello ant,ant 的第一次接触,好棒!

BUILD SUCCESSFUL
Total time: 2 seconds
D:/temp/hello-ant> 
检查一下build/classes目录,哦,看到编译过的文件就在这里:
build/classes/hello/ant/HelloAnt.class.

hello ant 进级

我们要改进build.xml,让它做更多的事情:

定义全局变量 
初始化,主要是建立目录 
编译 (已有) 
打包为jar 
建立API documentation 
生成distribution产品 
凡事都讲究平衡,你要ant给你做更多事,当然要累一点点,不过只用累一次,以后的代码修改后的构建都是"一键式"完成,我们制作一个hello的简单例子,你可以自己做j2ee的练习。

我们要扩充目录结构,使它更像回事:

:/src,/docs,/lib是自己组织的文件结构,/build,/dist是ant动态生成的成品。

/src 源文件:java源,源,jsp源,xml配置.....
/src/main java源
/src/ window,unix,liunx的执行,我们的简单只有一个:
run.bat: java hello.ant.HelloAnt

/docs 手写说明文档
/lib 程序所需类库的jar,比如j2ee.jar,mail,jar...

/build 用ant动态生成的构建目录
/build/classes 编译的类文件
/build/docs copy "/docs"的手写说明文档,和ant生成的api文档
/build/lib 放置我们自己的HelloAnt.class打包成品hello-ant.jar

/dist/bin copy "/src/" 得执行文件
/dist/docs copy "/build/docs" 的文档
/dist/lib 除了copy "/build/lib"下的hello-ant.jar外,
还应copy "/lib"的程序所需jar,这里我们没有。

以上是我学老外的文件组织,大家可以按照自己的爱好组织

我们编写必要的文件:

hello.ant. HelloAnt.java

src/.bat

@echo off
echo ========================================================
echo 请先设置 Environment
echo .
echo JAVA_HOME: %JAVA_HOME%
echo ======================================================

%java_home%/bin/java -classpath ../lib/hello-ant.jar hello.ant.HelloAnt

pause

/docs/index.html 随便写一个手写的文档 
hello ant 软件项目手册docs
--------------------------------------------------------------------------------访问api文档
/build.xml 配置文件

<?xml version="1.0" encoding="GB2312" ?>
<!--
=======================================================================
hello-ant 项目 ,学习ant工具的第2个build file.
参照ant的jakarta-ant-1.6alpha的build.xml

Copyright (c) 2002 The Neusoft Software Foundation. All rights
reserved.

=======================================================================
-->

<!--
文档结构为:
<project>
<property/> 全局变量的定义
<property/>...

<target name="1"> 任务组(tasks)
<javac></javac> 一项javac任务
...
<oneTask></ontTask> 一项其它任务
</target>

<target name="2">
<javac></javac>
...
<oneTask></ontTask>
</target>
</project>

project代表一个项目,
default:运行到名称为"dist"的target(任务组)
basedir:基准路径。
-->
<project default="dist" basedir=".">

<!--
===================================================================
定义属性(property tasks)
最好把用到的路径呀,名称呀都在这里定义成全局变量
例:定义
<property name="a" ="hello"/>
以后就可以这样用它:
<property name="b" ="${a}/b"/>
现在:b=="hello/b"
===================================================================
-->

<!--主要的系统环境属性-->
<property environment="env"/><!--取window,unix...的环境变量-->
<property name="java.home" ="${env.JAVA_HOME}"/>
<property name="ant.home" ="${env.ANT_HOME}"/>

<!--主要的app环境属性-->
<property name="app.name" ="hello-ant"/>
<property name="app.jar" ="${app.name}.jar"/>
<property name="app.copyright" =" Copyright (c) 2002 The Neusoft Software Foundation. All rights reserved."/>


<!--app中src的属性-->
<property name="src.dir" ="src" />
<property name="src.main" ="${src.dir}/main"/>
<property name="src." ="${src.dir}/"/>

<!--app用到的lib-->
<property name="lib.dir" ="lib"/>

<!--app的build目录中-->
<property name="build.dir" ="build" />
<property name="build.classes" ="${build.dir}/classes"/>
<property name="build.docs" ="${build.dir}/docs"/>
<property name="build.docs.api" ="${build.docs}/api"/>
<property name="build.lib" ="${build.dir}/lib"/>

<!--app的dist (distribution) 目录中-->
<property name="dist.dir" ="dist"/>
<property name="dist.bin" ="${dist.dir}/bin"/>
<property name="dist.docs" ="${dist.dir}/docs"/>
<property name="dist.lib" ="${dist.dir}/lib"/>

<!--app的docs目录中-->
<property name="docs.dir" ="docs"/>

<!--
定义一组路径以后可以通过id重用这组路径 ,例:
<javac srcdir="src/main" destdir="build/classes">
<classpath refid="classpath"/>
</javac>
-->
<path id="classpath">
<!--本项目只有一个java,用不上classpath,这里只是做个例子-->
<pathelement location="${build.classes}"/>
<pathelement path="${java.home}/lib/tools.jar"/>
</path>

<!--
===================================================================
init 准备目录(File Tasks)
主要的目录结构通常是不会变的,一起生成他们
===================================================================
-->
<target name="init">
<!--清除以前目录-->
<delete dir="${build.dir}" fail="false" />
<delete dir="${dist.dir}" fail="false"/>

<!--准备目录-->
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.classes}"/>
<mkdir dir="${build.docs}"/>
<mkdir dir="${build.docs.api}"/>
<mkdir dir="${build.lib}"/>

<mkdir dir="${dist.dir}"/>
<mkdir dir="${dist.bin}"/>
<mkdir dir="${dist.lib}"/>

</target>

<!--
===================================================================
Build the code (Compile Tasks,File Tasks)
===================================================================
-->
<target name="build" depends="init">
<!--编译-->
<javac srcdir="${src.main}" destdir="${build.classes}">
<classpath refid="classpath"/>
</javac>
</target>

<!--
===================================================================
打包文档(Archive Tasks)
Create the project jars: xxx1.jar and xxx2.jar
===================================================================
-->
<target name="jars" depends="build">
<jar basedir="${build.classes}" jarfile="${build.lib}/${app.jar}"/>
</target>

<!--
===================================================================
Creates the API documentation
===================================================================
-->
<target name="javadocs"
depends="jars"
deion="--> creates the API documentation">
<!--copy docs 手册... -->
<copy todir="${build.docs}">
<fileset dir="${docs.dir}"/>
</copy>

<javadoc packagenames="hello.ant.*"
sourcepath="${src.main}"
defaultexcludes="yes"
destdir="${build.docs.api}"
author="true"
version="true"
use="true"
windowtitle="Docs API">
<doctitle><![CDATA[<h1>hello ant Docs API</h1>]]></doctitle>
<bottom><![CDATA[<i>${app.copyright}</i>]]></bottom>
<tag name="todo" scope="all" deion="To do:" />
</javadoc>
</target>

<!--
===================================================================
Create the distribution that can run (Archive Tasks)
主要是从各目录中把该copy的copy上
===================================================================
-->
<target name="dist" depends="javadocs">
<!--copy bin 执行文件 -->
<copy todir="${dist.bin}">
<fileset dir="${src.}/"/>
</copy>
<copy todir="${dist.docs}">
<fileset dir="${build.docs}/"/>
</copy>
<!-- copy lib 文件 -->
<copy todir="${dist.lib}">
<fileset dir="${build.lib}/"/>
</copy>

</target>
<!--
===================================================================
Cleans everything(File Tasks)
例如可以删除build中的文件,留给你发挥吧
===================================================================
-->

</project>


build.xml多了些,但其实很简单:(注释比较详细可以参照,这里再简单说一下)

一个build.xml包含一个工程的自动化处理的完整xml说明,并且基本由3种东东组成:

<project >

1.全局变量的定义
<property/>

2.任务组
<target>
3.许多单项任务... 像copy,delete,javac,jar...
<task1/>
<task2/>
<task3/>
</target>

</project>
 








http://blog.csdn.net/wqjsir/article/details/5749907

http://blog.csdn.net/wqjsir/article/details/5749907



分类:  项目管理2010-07-20 15:42  339人阅读  评论(0)  收藏  举报

目录(?)[+]

         Ant是一个Apache基金会下的跨平台的构件工具,它可以实现项目的自动构建和部署等功能。在本文中,主要让读者熟悉怎样将Ant应用到Java项目中,让它简化构建和部署操作。

一.安装与配置

下载地址:http://ant.apache.org/,在本文中下载的是1.7.0版本。解压到某个目录(例如E:"apache-ant-1.7.0),即可使用。

添加系统环境变量:ANT_HOME,该变量指向Ant解压后的根目录,在此为E:"apache-ant-1.7.0

安装与配置完毕后,读者可以测试一下Ant是否可用,首先进入Antbin目录,运行命令ant –version,若安装和配置成功,则会显示Ant版本信息,如下图所示:
   

由上可以看出,读者运行Ant的命令时,需要进入到Antbin目录,如何才能让系统自动找到Ant呢?这时需要读者在系统环境变量path中添加Antbin目录。设置完成后,我们就可以在任何目录(例如C:"Documents and Settings"AmigoXie目录)输入Ant的命令,来获得命令的运行结果。

二. Ant的关键元素

Ant的构件文件是基于XML编写的,默认名称为build.xml。为了更清楚的了解Ant,在这里编写一个简单的Ant程序,用来展现Ant的功能,让读者对Ant有一个初步的了解。首先在E盘下建立一个build.xml文件,内容如下:

<?xml version="1.0"?>
<project name="helloWorld">
       <target name="sayHelloWorld">
              <echo message="Hello,Amigo"/>
       </target>
</project>

读者可以进入E盘,然后运行ant sayHelloWorld,可以看到如下的运行结果:
    

其中sayHelloWorld为需要执行的任务的名称。如果文件名不为build.xml,而为hello.xml时,读者运行同样的命令时,命令窗口会出现如下错误:

Buildfile: build.xml does not exist!

Build failed

由上面的命令的错误提示可以看出,ant命令默认寻找build.xml文件。若文件名为hello.xml时,读者还需要对命令做少许改变,改为:ant –f hello.xml sayHelloWorldant –buildfile hello.xml sayHelloWorldant –file hello.xml sayHelloWorld

接下来开始向读者讲解本节的重点:Ant的关键元素projecttargetpropertytask

1. project元素

project元素是Ant构件文件的根元素,Ant构件文件至少应该包含一个project元素,否则会发生错误。在每个project元素下,可包含多个target元素。接下来向读者展示一下project元素的各属性。

1name属性

用于指定project元素的名称。

2default属性

用于指定project默认执行时所执行的target的名称。

3basedir属性

用于指定基路径的位置。该属性没有指定时,使用Ant的构件文件的附目录作为基准目录。

下面给读者一个简单的例子来展示project的各元素的使用。修改E:"build.xml文件,修改后的内容如下:

<?xml version="1.0"?>
<project name="projectStudy" default="sayBaseDir" basedir="E:"apache-ant-1.7.0">
       <target name="sayBaseDir">
              <echo message="The base dir is: ${basedir}"/>
       </target>
</project>

从上面的内容我们可以看出,在这里定义了default属性的值为sayBaseDir,即当运行ant命令时,若未指明执行的target时,默认执行的targetsayBaseDir,同时还定义了basedir属性的值为E:"apache-ant-1.7.0,进入E盘后运行ant命令,可看到运行的结果,如下图所示:
   

因为设定了basedir的值,所以basedir属性的值变成了读者设置的值。读者可以自行将project元素的basedir属性去掉后运行ant看看运行结果,此时basedir的值变成了E:",即为Ant构件文件的父目录。

有的时候,读者可能有这种需求,即想得到某个project下所有的target的名称,读者可以通过在ant命令里加上-proecthelp来达到该目的。例如针对上述的例子我们运行ant –projecthelp,输出结果如下:

Buildfile: build.xml

Main targets:

Other targets:

 sayBaseDir

Default target: sayBaseDir

2.target元素

它为Ant的基本执行单元,它可以包含一个或多个具体的任务。多个target可以存在相互依赖关系。它有如下属性:

1name属性

指定target元素的名称,这个属性在一个project元素中是唯一的。我们可以通过指定target元素的名称来指定某个target

2depends属性

用于描述target之间的依赖关系,若与多个target存在依赖关系时,需要以“,”间隔。Ant会依照depends属性中target出现的顺序依次执行每个target。被依赖的target会先执行。

3if属性

用于验证指定的属性是否存在,若不存在,所在target将不会被执行。

4unless属性

该属性的功能与if属性的功能正好相反,它也用于验证指定的属性是否存在,若不存在,所在target将会被执行。

5description属性

该属性是关于target功能的简短描述和说明。

下面带领读者来看一个各属性综合使用的例子。修改E:"build.xml文件,修改后的内容如下:

<?xml version="1.0"?>
<project name="targetStudy">
       <target name="targetA" if="ant.java.version">
              <echo message="Java Version: ${ant.java.version}"/>
       </target>
       <target name="targetB" depends="targetA" unless="amigo">
              <description>
                            a depend example!
              </description>
              <echo message="The base dir is: ${basedir}"/>
       </target>
</project>

进入E盘后运行ant targetB,可看到如下图所示的运行结果:
   

读者分析结果后可以看到,我们运行的是名为targetBtarget,因该target依赖于targetA,所以targetA将首先被执行,同时因为系统安装了java环境,所以ant.java.version属性存在,执行了targetA这个target,输出信息:[echo] Java Version: 1.5targetA执行完毕后,接着执行targetB,因为amigo不存在,而unless属性是在不存在时进入所在的target的,由此可知targetB得以执行,输出信息:The base dir is: E:"

3. property元素

该元素可看作参量或者参数的定义,project的属性可以通过property元素来设定,也可在Ant之外设定。若要在外部引入某文件,例如build.properties文件,可以通过如下内容将其引入:<property file="build.properties"/>

property元素可用作task的属性值。在task中是通过将属性名放在“${”和“}”之间,并放在task属性值的位置来实现的。

Ant提供了一些内置的属性,它能得到的系统属性的列表与Java文档中System.getPropertis()方法得到的属性一致,这些系统属性可参考sun网站的说明。

同时,Ant还提供了一些它自己的内置属性,如下:

basedirproject基目录的绝对路径,该属性在讲解project元素时有详细说明,不再赘述;

ant.filebuildfile的绝对路径,如上面的各例子中,ant.file的值为E:"build.xml

ant.versionAnt的版本,在本文中,值为1.7.0

ant.project.name:当前指定的project的名字,即前文说到的projectname属性的值;

ant.java.versionAnt检测到的JDK的版本,在上例运行结果中可看到为1.5

下面让读者来看一个property元素使用的简单例子。修改E:"build.xml文件,内容如下:

<?xml version="1.0"?>
<project name="propertyStudy" default="example">
<property name="name" value="amigo"/>
<property name="age" value="25"/>
<target name="example">
        <echo message="name: ${name}, age: ${age}"/>
</target>
</project>

该例的运行结果如下图所示:
   

由此读者可以看出,通过如下两个语句:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <property name="name" value="amigo"/>  
  2. <property name="age" value="25"/>  

我们设置了名为nameage的两个属性,这两个属性设置后,读者在下文中可以通过${name}${age}分别取得这两个属性的值。

三.Ant的常用任务

Ant工具中每一个任务封装了具体要执行的功能,是Ant工具的基本执行单位。在本小节中,主要引导读者来看下Ant的常用任务及其使用举例。

1.copy任务

该任务主要用来对文件和目录的复制功能。举例如下:

Eg1.复制单个文件:<copy file="file.txt" tofile="copy.txt"/>

Eg2.对文件目录进行复制:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.   <copy todir="../newdir/dest_dir">  
  2.            <fileset dir="src_dir"/>  
  3. </copy>  

Eg3.将文件复制到另外的目录:

 <copy file="file.txt" todir="../other/dir"/>

2. delete任务

对文件或目录进行删除,举例如下:

Eg1.删除某个文件:<delete file="photo/amigo.jpg"/>

Eg2.删除某个目录:<delete dir="photo"/>

Eg3.删除所有的备份目录或空目录:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <delete includeEmptyDirs="true">  
  2.        <fileset dir="." includes="**/*.bak"/>  
  3. </delete>  

3. mkdir任务

创建目录。eg<mkdir dir="build"/>

4.move任务

移动文件或目录,举例如下:

Eg1.移动单个文件:<move file="fromfile" tofile=”tofile”/>

Eg2.移动单个文件到另一个目录:<move file="fromfile" todir=”movedir”/>

Eg3.移动某个目录到另一个目录:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <move todir="newdir">  
  2.      <fileset dir="olddir"/>  
  3. </move>  

5. echo任务

该任务的作用是根据日志或监控器的级别输出信息。它包括messagefileappendlevel四个属性,举例如下:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <echo message="Hello,Amigo" file="logs/system.log" append="true">  

四.利用Ant构建和部署Java工程

Ant可以代替使用javacjavajar等命令来执行java操作,从而达到轻松的构建和部署Java工程的目的。下面来看几个知识点。

1.利用Antjavac任务来编译java程序

Antjavac任务用于实现编译Java程序的功能。下面来看一个简单的例子:

首先我们建立名为antstudyJava工程,建立src目录为源代码目录,在src目录下建立HelloWorld.java这个类文件。该类文件的内容如下:

public class HelloWorld {
    public static void main(String[] args) {
       System.out.println("Hello,Amigo");
    }
}

  同时在antstudy工程的根目录下建立build.xml文件,在该文件中编译src目录下的java文件,并将编译后的class文件放入build/classes目录中,在编译前,需清除classes目录,该文件的内容如下:

<?xml version="1.0"?>
<project name="javacTest"default="compile" basedir=".">
    <target name="clean">
       <delete dir="build"/>
    </target>

    <target name="compile" depends="clean">
       <mkdir dir="build/classes"/>
    <javac srcdir="src" destdir="build/classes"/>
    </target>
</project>

    运行该build.xml文件,可在工程中看到新增了build/classes目录,并在该目录中生成了编译后的HelloWorld.class文件。

2.使用Antjava任务运行Java程序

    Ant中可以使用java任务实现运行Java程序的功能。下面在1的例子中进行如下的修改,修改后的build.xml文件的内容如下:

<?xml version="1.0"?>
<project name="javaTest" default="jar" basedir=".">
    <target name="clean">
       <delete dir="build"/>
    </target>

    <target name="compile" depends="clean">
       <mkdir dir="build/classes"/>
      <javac srcdir="src" destdir="build/classes"/>
    </target>

    <target name="run" depends="compile">
       <java classname="HelloWorld">
           <classpath>
              <pathelement path="build/classes"/>
           </classpath>
       </java>
    </target>
</project>

   运行该build.xml文件,可在控制台看到HelloWorldmain方法的输出。

3.使用Antjar任务生成jar文件

读者可以在上例的基础上更进一步,来生成jar包,可在run这个target下再加上如下target

<target name="jar" depends="run">
<jar destfile="helloworld.jar" basedir="build/classes">
           <manifest>
              <attribute name="Main-class" value="HelloWorld"/>
           </manifest>
       </jar>
</target>

此时将antprojectdefault属性设置为jar,同时运行该build.xml文件,运行完毕后,可看到在工程目录下生成了一个jarHelloWorld.jar

4.使用Antwar任务打包J2EE Web项目

建立一个J2EE Web工程,其目录结构如下图所示:

其中src为源代码目录,WebRoot为各jsp存放目录,lib为工程的包目录。在antwebproject工程目录下建立了build.xml文件,该文件为该工程的Ant构件文件。读者可以src目录下放入在前续例子中开发的HelloWorld.java文件,并在WebRoot下建立index.jsp文件,其内容很简单,就是输出Hello信息,代码如下所示:

<%@ page language="java" contentType="text/html; charset="UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
       <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
       <title>ant打包测试</title>
    </head>
    <body>
       Hello,Ant
    </body>
</html>

  接下来编写build.xml文件,其内容如下:

<?xml version="1.0"?>
<project name="antwebproject"  default="war"basedir=".">
 <property name="classes" value="build/classes"/>
    <property name="build"value="build"/>
    <property name="lib"value="WebRoot/WEB-INF/lib"/>
    <!-- 删除build路径-->
    <target name="clean">
       <delete dir="build"/>
    </target>

    <!-- 建立build/classes路径,并编译class文件到build/classes路径下-->
    <target name="compile" depends="clean">
       <mkdir dir="${classes}"/>

       <javac srcdir="src" destdir="${classes}"/>
    </target>

    <!-- 打war包-->
    <target name="war" depends="compile">
<war destfile="${build}/antwebproject.war" webxml="WebRoot/WEB-INF/web.xml">
           <!-- 拷贝WebRoot下除了WEB-INF和META-INF的两个文件夹-->
    <fileset dir="WebRoot" includes="**/*.jsp"/>

           <!-- 拷贝lib目录下的jar包-->
           <lib dir="${lib}"/>
           <!-- 拷贝build/classes下的class文件-->
           <classesdir="${classes}"/>
       </war>
    </target>
</project>

   target的作用在内容中已经进行说明,在此不再赘述。运行该build文件,更新目录后,可看到在build目录下生成了antwebproject.war文件,解开后可看到其目录结构如下:

--META-INF

     --MANIFEST.MF

--index.jsp

--WEB-INF

     --lib

            --log4j-1.2.9.jar

     --classes

            --HelloWorld.class

     --web.xml

    读者可以将该war包拷贝到Tomcat的目录下看一下运行结果。

五.总结

在本文中,笔者由浅至深详细描述了Ant的安装与配置、关键元素和常用任务。并通过实例讲述了Ant在我们Java项目中的应用,讲述了编译、运行java程序,以及打jar包、war包等知识,引领读者进入Ant的奇妙世界。在本文中可以看到,Ant在自动构建和部署Java程序方面方便易用,而且非常灵活,不失为我们Java开发者的绝佳帮手

 


 




http://blog.csdn.net/wqjsir/article/details/5750170

http://blog.csdn.net/wqjsir/article/details/5750170

http://blog.csdn.net/wqjsir/article/details/5750170

http://blog.csdn.net/wqjsir/article/details/5750170




ant帮助


2.Ant的任务:---------------------------------------------------------------- 
          ant              在另一个build file上调用ant 
          antcall          调用一个当前build file上的target 
          antstructure     创建一个ant build filde 的DTD文档 

          apply            执行系统命令,并应用文件 
          available        设置资源属性 
          chmod            设定变更文件和文件夹的变更权限(UNIX) 
          condition        条件为真时设置属性 

          copy             拷贝文件和目录  
          copydir          instead by copy 
          copyfile         instead by copy 
          cvs              执行cvs命令 
          cvspass          添加password到.cvspass文件中 
          delete           删除文件和文件夹 
          deltree          use the delete task instead. 
          dependset        管理文件依赖关系 
         
          ear              创建EAR文件 
          echo             写出log到文件或控制台 
          exec             执行一个本地命令 
          execon           use the apply task instead. 
          fail             抛出BuildException,停止build命令 
          filter           设置令牌过滤 
          fixcrlf          清除源文件中指定的特殊字符 
          genkey           产生一个key 
          get              从一个url上取得文件(****,可以用来分发jar包) 
          gunzip           解压缩一个GZip文件 
          gzip             创建一个GZip文件 
          jar              创建一个JAR文件 
          java            
          javac            编译java项目,并不等用于JDK中的javac命令 
          javadoc 
          mail             发送邮件(****) 
          mkdir           
          move    
          parallel         在并发线程上执行多任务? 
          patch            应用一个不同的文件到原始文件上 
          pathconvert      转换ant路径到指定的平台路径 
          property 
          record           Logs output from the current build process. 
          rename           use the move task instead. 
          replace          在文件中替换字符串 
          rmic             Runs the rmic compiler. 
          sequential       顺序执行多任务,用于并行任务 
          signjar          Executes the javasign command-line tool. 
          sleep            暂停编译一段时间 
          sql              使用JDBC指定SQL命令(****,执行数据库初始化) 
          style            执行XSLT转换 
          tar              创建一个TAR文件 
          taskdef          添加定义的任务到当前项目中 
          touch            更新文件的时间戳(****,应用于文件版本) 
          tstamp           Sets the DSTAMP, TSTAMP, and TODAY properties. 
          typedef          Adds a DataType to the current project. 
          unjar            Expands a ZIP file, WAR file, or JAR file. 
          untar   
          unwar 
          unzip 
          uptodate         Sets a property if one or more target files are up-to-date with respect to corresponding source files. 
          war 
          zip 

Ant Optional Task:---------------------------------------------------------------- 
          antlr            运行ANTLR分析器,Runs the ANTLR parser and translator generator tool. 
          blgenclient      从一个已知的ejb-jar文件中创建一个JAR文件 
          cab              创建微软 .cab文件 

          cccheckin        执行ClearCase checkin 命令 
          cccheckout       执行ClearCase checkout 命令 
          ccuncheckout     执行ClearCase undocheckout 命令 
          ccupdate         执行ClearCase update 命令 

          ccmcheckin       执行一个Continuus1 ci 命令 
          ccmcheckintask   执行一个Continuus1 ci 缺省命令 
          ccmcheckout      执行一个Continuus1 co 命令 
          ccmcreatetask    执行一个Continuus1 create_task 命令 
          ccmreconfigure   执行一个Continuus1 reconfigure 命令 

          csc              编译C#源文件 
          ddcreator        创建一个EJB部署描述符 
          depend           根据时间戳判断文件是否过期 
          ejbc             执行BEA WebLogic Server's ejbc tool, 产生部署EJB组件必要的代码 
          ejbjar           创建ejb-jar文件,符合EJB1.1标准 

          ftp              实现一个基本的ftp客户端(****) 

          icontract        Executes the iContract Design By Contract preprocessor. 
          ilasm            Assembles .NET Intermediate Language files. 
          iplanet-ejbc     Compiles EJB stubs and skeletons for iPlanet Application Server Version 6.0. 
          javacc           Executes the JavaCC compiler compiler on a grammar file. 
          javah            Executes the javah tool, generating Java Native Interface (JNI) headers from one or more Java classes. 
          jdepend          Executes the JDepend tool. 
          jjtree           Executes the JJTree preprocessor for JavaCC. 

          jlink            Builds a JAR or ZIP file, optionally merging contents of existing JAR and ZIP    archives. 

          jpcoverage       Executes the JProbe Coverage tool. 
          jpcovmerge       Merges several JProbe Coverage snapshots into one. 
          jpcovreport      Creates a report from a JProbe Coverage snapshot. 

          junit            执行单元测试 
          junitreport      创建一个单元测试报告 
          maudit           执行WebGain 质量分析,分析java代码错误 
          mmetrics         执行WebGain 质量分析 

          mimemail         发送SMTP邮件,并可发送附件 
          mparse           all Executes the now obsolete Metamata MParse compiler compiler on a grammar file. 

          native2ascii     转换本地代码到ASCII代码 

          netrexxc         Compiles a set of NetRexx files. 
          p4change         Requests a new changelist from a Perforce server. 
          p4counter        Gets and sets a Perforce counter value. 
          p4edit           Opens files from Perforce for editing. 
          p4have           Lists Perforce files in the current client view. 
          p4label          Creates a label for files in the current Perforce workspace. 
          p4reopen         Moves files between Perforce changelists. 
          p4revert         Reverts opened Perforce files. 
          p4submit         Checks files in to a Perforce depot. 
          p4sync           Synchronizes a workspace with the Perforce depot. 

          propertyfile     创建或变一个java属性文件 
          pvcs             Extracts files from a PVCS repository. 

          renameext        重命名文件扩展名 

          rpm              Builds a Linux RPM file. 
          script           执行一个 BSF 脚本. 
          sound            build结束后播放一个声音文件 

          starteam         从StarTeam check Out file. 
          stylebook        Executes the Apache Stylebook documentation generator. 

          telnet           执行telnet会话 
          test             执行单元测试,基于org.apache.testlet 框架 

          vsscheckin       Checkin文件到VSS上(****) 
          vsscheckout      checkout文件从vss上 
          vssget           从vss上获取最新的文件 
          vsshistory       显示vss上文件或项目历史信息 
          vsslabel         标记 Assigns a label to files and projects in Visual SourceSafe. 

          wljspc           Precompiles JSP files using BEA WebLogic Server's JSP compiler. 
          wlrun            Starts an instance of the BEA WebLogic Server. 
          wlstop           Stops an instance of the BEA WebLogic Server. 
          xmlvalidate      验证xml文档格式,使用任何SAX分析器(**** ,验证配置文件) 


Ant和XDoclet的整合:---------------------------------------------------------------- 
          仅仅需要拷贝Xdolcet.jar到ANT_HOME/lib目录中即可 
          这样就可以集成XDoclet了 



3.1 Projects 

project有下面的属性: 
Attribute Description Required 
name 项目名称. No 
default 当没有指定target时使用的缺省target Yes 
basedir 用于计算所有其他路径的基路径。该属性可以被basedir property覆盖。当覆盖时,该属性被忽略。如果属性和basedir property都没有设定,就使用buildfile文件的父目录。 No 
项目的描述以一个顶级的〈description〉元素的形式出现(参看description小节)。 

一个项目可以定义一个或多个target。一个target是一系列你想要执行的。执行Ant时,你可以选择执行那个target。当没有给定target时,使用project的default属性所确定的target。 

3.2 Targets 

一个target可以依赖于其他的target。例如,你可能会有一个target用于编译程序,一个target用于生成可执行文件。你在生成可执行文件之前必须先编译通过,所以生成可执行文件的target依赖于编译target。Ant会处理这种依赖关系。 

然而,应当注意到,Ant的depends属性只指定了target应该被执行的顺序-如果被依赖的target无法运行,这种depends对于指定了依赖关系的target就没有影响。 

Ant会依照depends属性中target出现的顺序(从左到右)依次执行每个target。然而,要记住的是只要某个target依赖于一个target,后者就会被先执行。 
〈target name="A"/〉 
〈target name="B" depends="A"/〉 
〈target name="C" depends="B"/〉 
〈target name="D" depends="C,B,A"/〉 
假定我们要执行target D。从它的依赖属性来看,你可能认为先执行C,然后B,最后A被执行。错了,C依赖于B,B依赖于A,所以先执行A,然后B,然后C,最后D被执行。 

一个target只能被执行一次,即时有多个target依赖于它(看上面的例子)。 

如果(或如果不)某些属性被设定,才执行某个target。这样,允许根据系统的状态(java version, OS, 命令行属性定义等等)来更好地控制build的过程。要想让一个target这样做,你就应该在target元素中,加入if(或unless)属性,带上target因该有所判断的属性。例如: 
〈target name="build-module-A" if="module-A-present"/〉 
〈target name="build-own-fake-module-A" unless="module-A-present"/〉 
如果没有if或unless属性,target总会被执行。 

可选的description属性可用来提供关于target的一行描述,这些描述可由-projecthelp命令行选项输出。 

将你的tstamp task在一个所谓的初始化target是很好的做法,其他的target依赖这个初始化target。要确保初始化target是出现在其他target依赖表中的第一个target。在本手册中大多数的初始化target的名字是"init"。 

target有下面的属性: 
Attribute Description Required 
name target的名字 Yes 
depends 用逗号分隔的target的名字列表,也就是依赖表。 No 
if 执行target所需要设定的属性名。 No 
unless 执行target需要清除设定的属性名。 No 
description 关于target功能的简短描述。 No 

3.3 Tasks 

一个task是一段可执行的代码。 

一个task可以有多个属性(如果你愿意的话,可以将其称之为变量)。属性只可能包含对property的引用。这些引用会在task执行前被解析。 

下面是Task的一般构造形式: 
〈name attribute1="value1" attribute2="value2" ... /〉 
这里name是task的名字,attributeN是属性名,valueN是属性值。 

有一套内置的(built-in)task,以及一些可选task,但你也可以编写自己的task。 

所有的task都有一个task名字属性。Ant用属性值来产生日志信息。 

可以给task赋一个id属性: 
〈taskname id="taskID" ... /〉 
这里taskname是task的名字,而taskID是这个task的唯一标识符。通过这个标识符,你可以在脚本中引用相应的task。例如,在脚本中你可以这样: 
〈script ... 〉 
task1.setFoo("bar"); 
〈/script〉 
设定某个task实例的foo属性。在另一个task中(用java编写),你可以利用下面的语句存取相应的实例。 
project.getReference("task1"). 
注意1:如果task1还没有运行,就不会被生效(例如:不设定属性),如果你在随后配置它,你所作的一切都会被覆盖。 

注意2:未来的Ant版本可能不会兼容这里所提的属性,因为很有可能根本没有task实例,只有proxies。 

3.4 Properties 

一个project可以有很多的properties。可以在buildfile中用property task来设定,或在Ant之外设定。一个property有一个名字和一个值。property可用于task的属性值。这是通过将属性名放在"${"和"}"之间并放在属性值的位置来实现的。例如如果有一个property builddir的值是"build",这个property就可用于属性值:${builddir}/classes。这个值就可被解析为build/classes。 

内置属性 

如果你使用了〈property〉 task 定义了所有的系统属性,Ant允许你使用这些属性。例如,${os.name}对应操作系统的名字。 

要想得到系统属性的列表可参考the Javadoc of System.getProperties。 

除了Java的系统属性,Ant还定义了一些自己的内置属性: 
basedir project基目录的绝对路径 (与〈project〉的basedir属性一样)。 
ant.file buildfile的绝对路径。 
ant.version Ant的版本。 
ant.project.name 当前执行的project的名字;由〈project〉的name属性设定. 
ant.java.version Ant检测到的JVM的版本; 目前的值有"1.1", "1.2", "1.3" and "1.4". 

例子 
〈project name="MyProject" default="dist" basedir="."〉 

〈!-- set global properties for this build --〉 
〈property name="src" value="."/〉 
〈property name="build" value="build"/〉 
〈property name="dist" value="dist"/〉 

〈target name="init"〉 
〈!-- Create the time stamp --〉 
〈tstamp/〉 
〈!-- Create the build directory structure used by compile --〉 
〈mkdir dir="${build}"/〉 
〈/target〉 

〈target name="compile" depends="init"〉 
〈!-- Compile the java code from ${src} into ${build} --〉 
〈javac srcdir="${src}" destdir="${build}"/〉 
〈/target〉 

〈target name="dist" depends="compile"〉 
〈!-- Create the distribution directory --〉 
〈mkdir dir="${dist}/lib"/〉 
〈!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --〉 
〈jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/〉 
〈/target〉 

〈target name="clean"〉 
〈!-- Delete the ${build} and ${dist} directory trees --〉 
〈delete dir="${build}"/〉 
〈delete dir="${dist}"/〉 
〈/target〉 

〈/project〉 
3.5 Path-like Structures 
你可以用":"和";"作为分隔符,指定类似PATH和CLASSPATH的引用。Ant会把分隔符转换为当前系统所用的分隔符。 

当需要指定类似路径的值时,可以使用嵌套元素。一般的形式是 
〈classpath〉 
〈pathelement path="${classpath}"/〉 
〈pathelement location="lib/helper.jar"/〉 
〈/classpath〉 
location属性指定了相对于project基目录的一个文件和目录,而path属性接受逗号或分号分隔的一个位置列表。path属性一般用作预定义的路径--其他情况下,应该用多个location属性。 

为简洁起见,classpath标签支持自己的path和location属性。所以: 
〈classpath〉 
〈pathelement path="${classpath}"/〉 
〈/classpath〉 
可以被简写作: 
〈classpath path="${classpath}"/〉 
也可通过〈fileset〉元素指定路径。构成一个fileset的多个文件加入path-like structure的顺序是未定的。 
〈classpath〉 
〈pathelement path="${classpath}"/〉 
〈fileset dir="lib"〉 
〈include name="**/*.jar"/〉 
〈/fileset〉 
〈pathelement location="classes"/〉 
〈/classpath〉 
上面的例子构造了一个路径值包括:${classpath}的路径,跟着lib目录下的所有jar文件,接着是classes目录。 

如果你想在多个task中使用相同的path-like structure,你可以用〈path〉元素定义他们(与target同级),然后通过id属性引用--参考Referencs例子。 

path-like structure可能包括对另一个path-like structurede的引用(通过嵌套〈path〉元素): 
〈path id="base.path"〉 
〈pathelement path="${classpath}"/〉 
〈fileset dir="lib"〉 
〈include name="**/*.jar"/〉 
〈/fileset〉 
〈pathelement location="classes"/〉 
〈/path〉 
〈path id="tests.path"〉 
〈path refid="base.path"/〉 
〈pathelement location="testclasses"/〉 
〈/path〉 
前面所提的关于〈classpath〉的简洁写法对于〈path〉也是有效的,如: 
〈path id="tests.path"〉 
〈path refid="base.path"/〉 
〈pathelement location="testclasses"/〉 
〈/path〉 
可写成: 
〈path id="base.path" path="${classpath}"/〉 
命令行变量 

有些task可接受参数,并将其传递给另一个进程。为了能在变量中包含空格字符,可使用嵌套的arg元素。 
Attribute Description Required 
value 一个命令行变量;可包含空格字符。 只能用一个 
line 空格分隔的命令行变量列表。 
file 作为命令行变量的文件名;会被文件的绝对名替代。 
path 一个作为单个命令行变量的path-like的字符串;或作为分隔符,Ant会将其转变为特定平台的分隔符。 

例子 
〈arg value="-l -a"/〉 
是一个含有空格的单个的命令行变量。 
〈arg line="-l -a"/〉 
是两个空格分隔的命令行变量。 
〈arg path="/dir;/dir2:/dir3"/〉 
是一个命令行变量,其值在DOS系统上为/dir;/dir2;/dir3;在Unix系统上为/dir:/dir2:/dir3 。 

References 

buildfile元素的id属性可用来引用这些元素。如果你需要一遍遍的复制相同的XML代码块,这一属性就很有用--如多次使用〈classpath〉结构。 

下面的例子: 
〈project ... 〉 
〈target ... 〉 
〈rmic ...〉 
〈classpath〉 
〈pathelement location="lib/"/〉 
〈pathelement path="${java.class.path}/"/〉 
〈pathelement path="${additional.path}"/〉 
〈/classpath〉 
〈/rmic〉 
〈/target〉 
〈target ... 〉 
〈javac ...〉 
〈classpath〉 
〈pathelement location="lib/"/〉 
〈pathelement path="${java.class.path}/"/〉 
〈pathelement path="${additional.path}"/〉 
〈/classpath〉 
〈/javac〉 
〈/target〉 
〈/project〉 
可以写成如下形式: 
〈project ... 〉 
〈path id="project.class.path"〉 
〈pathelement location="lib/"/〉 
〈pathelement path="${java.class.path}/"/〉 
〈pathelement path="${additional.path}"/〉 
〈/path〉 
〈target ... 〉 
〈rmic ...〉 
〈classpath refid="project.class.path"/〉 
〈/rmic〉 
〈/target〉 
〈target ... 〉 
〈javac ...〉 
〈classpath refid="project.class.path"/〉 
〈/javac〉 
〈/target〉 
〈/project〉 
所有使用PatternSets, FileSets 或 path-like structures嵌套元素的task也接受这种类型的引用。 


4.1 File(Directory)类 
4.1.1 Mkdir 
? 创建一个目录,如果他的父目录不存在,也会被同时创建。 
? 例子: 
〈mkdir dir="build/classes"/〉 
? 说明: 如果build不存在,也会被同时创建 
4.1.2 Copy 
? 拷贝一个(组)文件、目录 
? 例子: 
1. 拷贝单个的文件: 
〈copy file="myfile.txt" tofile="mycopy.txt"/〉 
2. 拷贝单个的文件到指定目录下 
〈copy file="myfile.txt" todir="../some/other/dir"/〉 
3. 拷贝一个目录到另外一个目录下 
〈copy todir="../new/dir"〉 
〈fileset dir="src_dir"/〉 
〈/copy〉 
4. 拷贝一批文件到指定目录下 
〈copy todir="../dest/dir"〉 
〈fileset dir="src_dir"〉 
〈exclude name="**/*.java"/〉 
〈/fileset〉 
〈/copy〉 

〈copy todir="../dest/dir"〉 
〈fileset dir="src_dir" excludes="**/*.java"/〉 
〈/copy〉 
5. 拷贝一批文件到指定目录下,将文件名后增加。Bak后缀 
〈copy todir="../backup/dir"〉 
〈fileset dir="src_dir"/〉 
〈mapper type="glob" from="*" to="*.bak"/〉 
〈/copy〉 
6. 拷贝一组文件到指定目录下,替换其中的@标签@内容 
〈copy todir="../backup/dir"〉 
〈fileset dir="src_dir"/〉 
〈filterset〉 
〈filter token="TITLE" value="Foo Bar"/〉 
〈/filterset〉 
〈/copy〉
7、复制肯定还要涉及到同名覆盖的问题,ant在copy类的API中说明:Files are only copied if the source file is newer than the destination file,这里的newer是指文件的修改时间,即使你在修改时文件内容没有任何变化,只是导致修改时间变了,ant同样会覆盖同名文件,也就是说,ant不会检查文件内容。 

      对于是复制目录的情况,由于目录没有修改时间,ant还是通过检查目录内文件的修改时间来决定是否覆盖的,若目录内某文件修改时间有变化,则会覆盖这个文件,而不是整个目录。 

如果要强行覆盖,<copy/>有个overwrite属性,默认为false,改成true就行了 
4.1.3 Delete 
? 删除一个(组)文件或者目录 
? 例子 
1. 删除一个文件 
〈delete file="/lib/ant.jar"/〉 
2. 删除指定目录及其子目录 
〈delete dir="lib"/〉 
3. 删除指定的一组文件 
〈delete〉 
〈fileset dir="." includes="**/*.bak"/〉 
〈/delete〉 
4. 删除指定目录及其子目录,包括他自己 
〈delete includeEmptyDirs="true"〉 
〈fileset dir="build"/〉 
〈/delete〉 
4.1.4 Move 
? 移动或重命名一个(组)文件、目录 
? 例子: 
1. 移动或重命名一个文件 
〈move file="file.orig" tofile="file.moved"/〉 
2. 移动或重命名一个文件到另一个文件夹下面 
〈move file="file.orig" todir="dir/to/move/to"/〉 
3. 将一个目录移到另外一个目录下 
〈move todir="new/dir/to/move/to"〉 
〈fileset dir="src/dir"/〉 
〈/move〉 
4. 将一组文件移动到另外的目录下 
〈move todir="some/new/dir"〉 
〈fileset dir="my/src/dir"〉 
〈include name="**/*.jar"/〉 
〈exclude name="**/ant.jar"/〉 
〈/fileset〉 
〈/move〉 
5. 移动文件过程中增加。Bak后缀 
〈move todir="my/src/dir"〉 
〈fileset dir="my/src/dir"〉 
〈exclude name="**/*.bak"/〉 
〈/fileset〉 
〈mapper type="glob" from="*" to="*.bak"/〉 
〈/move〉 



4.2 Java相关 
4.2.1 Javac 
? 编译java原代码 
? 例子 
1. 〈javac srcdir="${src}" 
destdir="${build}" 
classpath="xyz.jar" 
debug="on" 
/〉 
编译${src}目录及其子目录下的所有。Java文件,。Class文件将放在${build}指定的目录下,classpath表示需要用到的类文件或者目录,debug设置为on表示输出debug信息 
2. 〈javac srcdir="${src}:${src2}" 
destdir="${build}" 
includes="mypackage/p1/**,mypackage/p2/**" 
excludes="mypackage/p1/testpackage/**" 
classpath="xyz.jar" 
debug="on" 
/〉 
编译${src}和${src2}目录及其子目录下的所有。Java文件,但是package/p1/**,mypackage/p2/**将被编译,而mypackage/p1/testpackage/**将不会被编译。Class文件将放在${build}指定的目录下,classpath表示需要用到的类文件或者目录,debug设置为on表示输出debug信息 
3. 〈property name="classpath" value=".;./xml-apis.jar;../lib/xbean.jar;./easypo.jar"/〉 

〈javac srcdir="${src}" 
destdir="${src}" 
classpath="${classpath}" 
debug="on" 
/〉 
路径是在property中定义的 
4.2.2 java 
? 执行指定的java类 


? 例子: 
1. 〈java classname="test.Main"〉 
〈classpath〉 
〈pathelement location="dist/test.jar"/〉 
〈pathelement path="${java.class.path}"/〉 
〈/classpath〉 
〈/java〉 
classname中指定要执行的类,classpath设定要使用的环境变量 
2. 〈path id="project.class.path"〉 
〈pathelement location="lib/"/〉 
〈pathelement path="${java.class.path}/"/〉 
〈pathelement path="${additional.path}"/〉 
〈/path〉 

〈target ... 〉 
〈rmic ...〉 
〈classpath refid="project.class.path"/〉 
〈/rmic〉 
〈/target〉 



4.3 打包相关 
4.3.1 jar 
? 将一组文件打包 
? 例子: 
1. 〈jar destfile="${dist}/lib/app.jar" basedir="${build}/classes"/〉 
将${build}/classes下面的所有文件打包到${dist}/lib/app.jar中 
2. 〈jar destfile="${dist}/lib/app.jar" 
basedir="${build}/classes" 
includes="mypackage/test/**" 
excludes="**/Test.class" 
/〉 
将${build}/classes下面的所有文件打包到${dist}/lib/app.jar中,但是包括mypackage/test/所有文件不包括所有的Test.class 
3. 〈jar destfile="${dist}/lib/app.jar" 
basedir="${build}/classes" 
includes="mypackage/test/**" 
excludes="**/Test.class" 
manifest=”my.mf” 
/〉 
manifest属性指定自己的META-INF/MANIFEST.MF文件,而不是由系统生成 
4.3.2 war 
? 对Jar的扩展,用于打包Web应用 
? 例子: 
? 假设我们的文件目录如下: 
thirdparty/libs/jdbc1.jar 
thirdparty/libs/jdbc2.jar 
build/main/com/myco/myapp/Servlet.class 
src/metadata/myapp.xml 
src/html/myapp/index.html 
src/jsp/myapp/front.jsp 
src/graphics/images/gifs/small/logo.gif 
src/graphics/images/gifs/large/logo.gif 
? 下面是我们的任务的内容: 
〈war destfile="myapp.war" webxml="src/metadata/myapp.xml"〉 
〈fileset dir="src/html/myapp"/〉 
〈fileset dir="src/jsp/myapp"/〉 
〈lib dir="thirdparty/libs"〉 
〈exclude name="jdbc1.jar"/〉 
〈/lib〉 
〈classes dir="build/main"/〉 
〈zipfileset dir="src/graphics/images/gifs" 
prefix="images"/〉 
〈/war〉 
? 完成后的结果: 
WEB-INF/web.xml 
WEB-INF/lib/jdbc2.jar 
WEB-INF/classes/com/myco/myapp/Servlet.class 
META-INF/MANIFEST.MF 
index.html 
front.jsp 
images/small/logo.gif 
images/large/logo.gif 
4.3.3 ear 
? 用于打包企业应用 
? 例子 
〈ear destfile="${build.dir}/myapp.ear" appxml="${src.dir}/metadata/application.xml"〉 
〈fileset dir="${build.dir}" includes="*.jar,*.war"/〉 
〈/ear〉 


4.4 时间戳 
在生成环境中使用当前时间和日期,以某种方式标记某个生成任务的输出,以便记录它是何时生成的,这经常是可取的。这可能涉及编辑一个文件,以便插入一个字符串来指定日期和时间,或将这个信息合并到 JAR 或 zip 文件的文件名中。 
这种需要是通过简单但是非常有用的 tstamp 任务来解决的。这个任务通常在某次生成过程开始时调用,比如在一个 init 目标中。这个任务不需要属性,许多情况下只需 〈tstamp/〉 就足够了。 
tstamp 不产生任何输出;相反,它根据当前系统时间和日期设置 Ant 属性。下面是 tstamp 设置的一些属性、对每个属性的说明,以及这些属性可被设置到的值的例子: 
属性 说明 例子 
DSTAMP 设置为当前日期,默认格式为yyyymmdd 20031217 
TSTAMP 设置为当前时间,默认格式为 hhmm 1603 
TODAY 设置为当前日期,带完整的月份 2003 年 12 月 17 日 
例如,在前一小节中,我们按如下方式创建了一个 JAR 文件: 

〈jar destfile="package.jar" basedir="classes"/〉 

在调用 tstamp 任务之后,我们能够根据日期命名该 JAR 文件,如下所示: 

〈jar destfile="package-${DSTAMP}.jar" basedir="classes"/〉 

因此,如果这个任务在 2003 年 12 月 17 日调用,该 JAR 文件将被命名为 package-20031217.jar。 
还可以配置 tstamp 任务来设置不同的属性,应用一个当前时间之前或之后的时间偏移,或以不同的方式格式化该字符串。所有这些都是使用一个嵌套的 format 元素来完成的,如下所示: 

〈tstamp〉 
〈format property="OFFSET_TIME" 
pattern="HH:mm:ss" 
offset="10" unit="minute"/〉 
〈/tstamp〉 

上面的清单将 OFFSET_TIME 属性设置为距离当前时间 10 分钟之后的小时数、分钟数和秒数。 
用于定义格式字符串的字符与 java.text.SimpleDateFormat 类所定义的那些格式字符相同 


4.5 执行SQL语句 
? 通过jdbc执行SQL语句 
? 例子: 
1. 〈sql 
driver="org.gjt.mm.mysql.Driver" 
url="jdbc:mysql://localhost:3306/mydb" 
userid="root" 
password="root" 
src="data.sql" 
/〉 
2. 〈sql 
driver="org.database.jdbcDriver" 
url="jdbc:database-url" 
userid="sa" 
password="pass" 
src="data.sql" 
rdbms="oracle" 
version="8.1." 
〉 
〈/sql〉 
只有在oracle、版本是8.1的时候才执行 


4.6 发送邮件 
? 使用SMTP服务器发送邮件 
? 例子: 
〈mail mailhost="smtp.myisp.com" mailport="1025" subject="Test build"〉 
〈from address="mailto:me@myisp.com〉 
〈to address="mailto:all@xyz.com〉 
〈message〉The ${buildname} nightly build has completed〈/message〉 
〈fileset dir="dist"〉 
〈includes name="**/*.zip"/〉 
〈/fileset〉 
〈/mail〉 
? mailhost: SMTP服务器地址 
? mailport: 服务器端口 
? subject: 主题 
? from: 发送人地址 
? to: 接受人地址 
? message: 发送的消息 
? fileset: 设置附件 





ANT +数据库 

  Ant 执行系统命令没有任何问题,这次实际系统命令中可以说遇到了两个问题,一个是启动服务的命令是含有空格的,第二个如何备份数据库可以自动加上日期。 
   
  首先,我们启动oracle数据库,操作有两个: 
   
  1.启动监听: 
   
  〈exec executable="lsnrctl" 〉 
   
  〈arg line=" start "/〉 
   
  〈/exec〉 
   
  2.打开数据库实例: 
   
  〈exec executable='cmd' 〉 
   
  〈arg line="/c net start oracleservice${ORA_SID} "/〉 
   
  〈/exec〉 
   
  第一个操作在这里没有什么区别,就是ant调用系统命令的标准用法,我们来看一下第二个命令, net start oracleservice${ORA_SID},如果你直接放入到executable属性中,执行结果一定会是: 
   
  BUILD FAILED: E:/java/TestAnt/build.xml:44: Execute failed: java.io.IOException: CreateProcess: "net start oracleservicemy_oracle" error=2 
   
  痛苦吧,带有空格的命令应该使用以下方法: 
   
  〈exec executable='cmd' 〉 
   
  〈arg line="/c net start oracleservice${ORA_SID} "/〉 
   
  〈/exec〉 
   
  如果在备份数据库的时候加上时间标记,我在linux下面使用教本备份oracle数据库,可以使用data 命令很方便的在备份的文件上面加上日期后缀,ant可以么? 
   
  我查了很多资料,终于搞定: 
   
  〈tstamp〉 
   
  〈format property="DB_BACKUP_TIME" pattern="yyyy-MM-dd"/〉 
   
  〈/tstamp〉 
   
  使用 tstamp target可以非常方便的定义日期属性,这样再生成需要备份文件的名字,方便的解决你的问题。 
   
  Ok,你可以参考完成的ant脚本: 
   
  附录:参考脚本 
   
  〈!-- 2005 by guipei. --〉 
   
  〈project name="TestAntOracle" default="demo" basedir="./"〉 
   
  〈!-- set global properties for this build --〉 
   
  〈property name="DB_BACKUP_DIR" value="." /〉 
   
  〈property name="ORA_SID" value="my_oracle"/〉 
   
  〈property name="ORA_USER" value="scott"/〉 
   
  〈property name="ORA_PWD" value="tiger"/〉 
   
  〈property name="ORA_RESTORE_FILE" value="db_back.dmp"/〉 
   
  〈target name="demo" 〉 
   
  〈echo〉 ant db_backup to backup db 〈/echo〉 
   
  〈echo〉 ant db_restore to restore db 〈/echo〉 
   
  〈echo〉 ant db_start to start db 〈/echo〉 
   
  〈echo〉 ant db_stop to stop db 〈/echo〉 
   
  〈/target〉 
   
  〈target name="db_backup"〉 
   
  〈tstamp〉 
   
  〈format property="DB_BACKUP_TIME" pattern="yyyy-MM-dd"/〉 
   
  〈/tstamp〉 
   
  〈property name="DB_BACKUP_FILE" value="MYDB_${DB_BACKUP_TIME}.DMP" /〉 
   
  〈echo〉will backup db at ${DB_BACKUP_FILE}〈/echo〉 
   
  〈exec dir="${DB_BACKUP_DIR}" executable="exp" 〉 
   
  〈arg line=" ${ORA_USER}/${ORA_PWD}@${ORA_SID} file=MYDB_${DB_BACKUP_TIME}.DMP "/〉 
   
  〈/exec〉 
   
  〈/target〉 
   
  〈target name="db_restore"〉 
   
  〈exec dir="${DB_BACKUP_DIR}" executable="imp" 〉 
   
  〈arg line=" ${ORA_USER}/${ORA_PWD}@${ORA_SID} file=${ORA_RESTORE_FILE} full=y"/〉 
   
  〈/exec〉 
   
  〈/target〉 
   
  〈target name="db_start"〉 
   
  〈exec executable="lsnrctl" 〉 
   
  〈arg line=" start "/〉 
   
  〈/exec〉 
   
  〈exec executable='cmd' 〉 
   
  〈arg line="/c net start oracleservice${ORA_SID} "/〉 
   
  〈/exec〉 
   
  〈/target〉 
   
  〈target name="db_stop"〉 
   
  〈exec executable="lsnrctl" 〉 
   
  〈arg line=" stop "/〉 
   
  〈/exec〉 
   
  〈exec executable='cmd' 〉 
   
  〈arg line="/c net stop oracleservice${ORA_SID} "/〉 
   
  〈/exec〉 
   
  〈/target〉 
   
  〈/project〉 


 当一个代码项目大了以后,每次重新编译,打包,测试等都会变得非常复杂而且重复,因此c语言中有make脚本来帮助这些工作的批量完成。在Java中应用是平台无关性的,当然不会用平台相关的make脚本来完成这些批处理任务了,ANT本身就是这样一个流程脚本引擎,用于自动化调用程序完成项目的编译,打包,测试等。除了基于JAVA是平台无关的外,脚本的格式是基于XML的,比make脚本来说还要好维护一些。 

  每个ant脚本(缺省叫build.xml)中设置了一系列任务(target):比如对于一个一般的项目可能需要有以下任务。 

  任务1:usage 打印本脚本的帮助信息(缺省) 
  任务2:clean <-- init 清空初始化环境 
  任务3:javadoc <-- build <-- init 生成JAVADOC 
  任务4:jar <-- build <-- init 生成JAR 
  任务5:all <-- jar + javadoc <-- build <-- init 完成以上所有任务:jar javadoc 

  而多个任务之间往往又包含了一定了依赖关系:比如把整个应用打包任务(jar)的这个依赖于编译任务(build),而编译任务又依赖于整个环境初始化任务(init)等。 

  注:我看到很多项目的ant脚本中的命名基本上都是一致的,比如:编译一般叫build或者compile;打包一般叫jar或war;生成文档一般命名为javadoc或javadocs;执行全部任务all。在每个任务的中,ANT会根据配置调用一些外部应用并配以相应参数执行。虽然ANT可调用的外部应用种类非常丰富,但其实最常用的就2,3个:比如javac javadoc jar等。 

  ANT的安装 

  解包后在系统可执行路径中加入指向ant的bin的路径就可以了,比如可以在GNU/Linux上把以下配置加入/etc/profile中: 
  export ANT_HOME=/home/ant 
  export JAVA_HOME=/usr/java/j2sdk1.4.1 
  export PATH=$PATH:$JAVA_HOME/bin:$ANT_HOME/bin 

  这样执行ant 后,如果不指定配置文件ant会缺省找build.xml这个配置文件,并根据配置文件执行任务,缺省的任务设置可以指向最常用的任务,比如:build,或指向打印帮助信息:usage,告诉用户有那些脚本选项可以使用。 

  ANT的使用 

  最好的学习过程就是看懂那些open source项目中的build.xml脚本,然后根据自己的需要简化成一个更简单的,ANT和APACHE上很多非常工程派的项目:简单易用,而且适应性非常强,因为这些项目的建立往往来源于开发人员日常最直接的需求。 
以下是的一个WebLucene应用的例子:修改自JDOM的build.xml: 

<project default="usage" basedir="."> 

<!-- =================================================================== --> 
<!-- Initialization target                                               --> 
<!-- =================================================================== --> 
<target name="init"> 
    <tstamp/> 
    <property file="${basedir}/build.properties" /> 
    <property name="Name" value="ProjectFullName"/> 
    <property name="name" value="project_name"/> 
    <property name="version" value="0.2"/> 
    <property name="year" value="2003"/> 

    <echo message="----------- ${Name} ${version} [${year}] ------------"/> 

    <property name="debug" value="off"/> 
    <property name="optimize" value="on"/> 
    <property name="deprecation" value="on"/> 

    <property name="src.dir" value="./src/WEB-INF/src"/> 
    <property name="lib.dir" value="./src/WEB-INF/lib"/> 
    <property name="packages" value="com.chedong.*,org.apache.lucene.*"/> 

    <property name="build.src" value="./src/WEB-INF/build"/> 
    <property name="build.dest" value="./src/WEB-INF/classes"/> 
    <property name="build.javadocs" value="./src/doc"/> 
   
    <path id="classpath"> 
        <pathelement path="${jsdk_jar}"/> 
        <fileset dir="${lib.dir}"> 
           <include name="**/*.jar"/> 
        </fileset> 
    </path> 
   
    <filter token="year" value="${year}"/> 
    <filter token="version" value="${version}"/> 
    <filter token="date" value="${TODAY}"/> 
    <filter token="log" value="true"/> 
    <filter token="verbose" value="true"/> 
</target> 

<!-- =================================================================== --> 
<!-- Help on usage                                                       --> 
<!-- =================================================================== --> 
<target name="usage" depends="init"> 
    <echo message="${Name} Build file"/> 
    <echo message="-------------------------------------------------------------"/> 
    <echo message=""/> 
    <echo message=" available targets are:"/> 
    <echo message=""/> 
    <echo message="   jar      --> generates the ${name}.jar file"/> 
    <echo message="   build    --> compiles the source code"/> 
    <echo message="   javadoc --> generates the API documentation"/> 
    <echo message="   clean    --> cleans up the directory"/> 
    <echo message=""/> 
    <echo message=" Please rename build.properties.default to build.properties"/> 
    <echo message=" and edit build.properties to specify JSDK 2.3 classpath."/> 
    <echo message=""/> 
    <echo message=" See the comments inside the build.xml file for more details."/> 
    <echo message="-------------------------------------------------------------"/> 
    <echo message=""/> 
    <echo message=""/> 
</target> 

<!-- =================================================================== --> 
<!-- Prepares the source code                                            --> 
<!-- =================================================================== --> 
<target name="prepare-src" depends="init"> 
    <!-- create directories --> 
    <mkdir dir="${build.src}"/> 
    <mkdir dir="${build.dest}"/> 
   
    <!-- copy src files --> 
    <copy todir="${build.src}"> 
      <fileset dir="${src.dir}"/> 
    </copy> 
</target> 

<!-- =================================================================== --> 
<!-- Compiles the source directory                                       --> 
<!-- =================================================================== --> 
<target name="build" depends="prepare-src"> 
    <javac srcdir="${build.src}" 
           destdir="${build.dest}" 
           debug="${debug}" 
           optimize="${optimize}"> 
      <classpath refid="classpath"/> 
    </javac> 
</target> 

<!-- =================================================================== --> 
<!-- Creates the class package                                           --> 
<!-- =================================================================== --> 
<target name="jar" depends="build"> 
    <jar jarfile="${lib.dir}/${name}.jar" 
         basedir="${build.dest}" 
         includes="**"/> 
</target> 

<!-- =================================================================== --> 
<!-- Creates the API documentation                                       --> 
<!-- =================================================================== --> 
<target name="javadoc" depends="build"> 
    <mkdir dir="${build.javadocs}"/> 
    <javadoc packagenames="${packages}" 
             sourcepath="${build.src}" 
             destdir="${build.javadocs}" 
             author="true" 
             version="true" 
             use="true" 
             splitindex="true" 
             windowtitle="${Name} API" 
             doctitle="${Name}"> 
      <classpath refid="classpath"/> 
    </javadoc> 
</target> 

<!-- =================================================================== --> 
<!-- Clean targets                                                       --> 
<!-- =================================================================== --> 
<target name="clean" depends="init"> 
    <delete dir="${build.src}"/> 
    <delete dir="${build.dest}/org"/> 
    <delete dir="${build.dest}/com"/> 
    <delete> 
      <fileset dir="${build.dest}" includes="**/*.class"/> 
    </delete> 
</target> 
</project> 
<!-- End of file --> 

  缺省任务:usage 打印帮助文档,告诉有那些任务选项:可用的有build, jar, javadoc和clean. 

  初始化环境变量:init 

  所有任务都基于一些基本环境变量的设置初始化完成,是后续其他任务的基础,在环境初始化过程中,有2点比较可以方便设置: 

  1 除了使用却缺省的property设置了JAVA源路径和输出路径外,引用了一个外部的build.properties文件中的设置, 

  <property file="${basedir}/build.properties" /> 
  这样大部分简单配置用户只要会看懂build.properties就可以了,毕竟XML比起key value的属性文件还是要可读性差一些。用build.properties也可以方便其他用户从编译的细节中解放出来。 

  2 CLASSPATH设置:使用了其中的: 

    <path id="classpath"> 
        <pathelement path="${jsdk_jar}"/> 
        <fileset dir="${lib.dir}"> 
           <include name="**/*.jar"/> 
        </fileset> 
    </path> 

  则相当于设置了:CLASSPATH=/path/to/resin/lib/jsdk23.jar;/path/to/project/lib/*.jar; 

  文件复制:prepare-src 

  创建临时SRC存放目录和输出目录。 

<!-- =================================================================== --> 
<!-- Prepares the source code                                            --> 
<!-- =================================================================== --> 
<target name="prepare-src" depends="init"> 
    <!-- create directories --> 
    <mkdir dir="${build.src}"/> 
    <mkdir dir="${build.dest}"/> 
   
    <!-- copy src files --> 
    <copy todir="${build.src}"> 
      <fileset dir="${src.dir}"/> 
    </copy> 
</target> 

  编译任务:build 

  编译时的CLASSPATH环境通过一下方式找到引用一个path对象 

  <classpath refid="classpath"/> 

  打包任务:jar 

  对应用打包生成项目所写名的.jar文件 


<!-- =================================================================== --> 
<!-- Creates the class package                                           --> 
<!-- =================================================================== --> 
<target name="jar" depends="build"> 
    <jar jarfile="${lib.dir}/${name}.jar" 
         basedir="${build.dest}" 
         includes="**"/> 
</target> 

  生成JAVADOC文档任务: javadoc 

<!-- =================================================================== --> 
<!-- Creates the API documentation                                       --> 
<!-- =================================================================== --> 
<target name="javadoc" depends="build"> 
    <mkdir dir="${build.javadocs}"/> 
    <javadoc packagenames="${packages}" 
             sourcepath="${build.src}" 
             destdir="${build.javadocs}" 
             author="true" 
             version="true" 
             use="true" 
             splitindex="true" 
             windowtitle="${Name} API" 
             doctitle="${Name}"> 
      <classpath refid="classpath"/> 
    </javadoc> 
</target> 

  清空临时编译文件:clean 

<!-- =================================================================== --> 
<!-- Clean targets                                                       --> 
<!-- =================================================================== --> 
<target name="clean" depends="init"> 
    <delete dir="${build.src}"/> 
    <delete dir="${build.dest}/org"/> 
    <delete dir="${build.dest}/com"/> 
    <delete> 
      <fileset dir="${build.dest}" includes="**/*.class"/> 
    </delete> 
</target> 

  TODO: 
  更多任务/扩展:(样例) 

  测试任务:JUnit测试 
  代码风格检查任务:CheckStyle,Jalopy等 
  邮件警报任务:可以把以上这些任务的输出警告发送到制定的用户列表中,这个任务可以设置每天自动运行。



















http://blog.csdn.net/wqjsir/article/details/16356089

 

SVN服务器部署

分类: 项目管理   415人阅读  评论(0)  收藏  举报

目录(?)[+]

这里主要说明构建http://IP地址/repository所在目录/子目录  格式的多版本管理库。

本地使用(个人)格式:file:///磁盘驱动器|/repository所在目录/子目录  见:TortoiseSVN 构建本地多版本管理库

window平台

环境准备

安装apache httpd

下载地址:http://httpd.apache.org/;当前版本2.4;安装成功后,在浏览器中输入:http://localhost

如果正确安装了apache服务,则会看到It works! 如图:


如果没有成功,可能是服务端口被占用了。我们打开安装目录下的配置文件:C:\Program Files\Apache SoftwareFoundation\Apache2.2\conf\httpd.conf 

找到: Listen 80 修改端口号

安装Apache Subversion

下载地址:http://subversion.apache.org/packages.html,当前版本1.8.4

安装TortoiseSVN

TortoiseSVN,下载地址:http://tortoisesvn.net/downloads.html,当前版本为:1.8.3

软件配置

添加加载模块

如果在加载模块(Apache2.2\modules)里没有mod_dav_svn.so和mod_authz_svn.so和libdb44.dll,则从subversion的安装目录subversion/bin里考到Apache2.2\modules:

  mod_dav_svn.so

  mod_authz_svn.so

libdb44.dll

然后我们再打开C:\Program Files\Apache SoftwareFoundation\Apache2.2\conf\httpd.conf文件. 

找到

#LoadModuledav_module modules/mod_dav.so

#LoadModuledav_fs_module modules/mod_dav_fs.so

去掉前面的注释符号# 

然后再下面添加

LoadModuledav_svn_module modules/mod_dav_svn.so

LoadModuleauthz_svn_module modules/mod_authz_svn.so

注意不要随意改变顺序。可能出现其它错误。

修改配置文件

模块的加载设置完成,下面我们要设置SVN的版本库目录,以使我们的apache能知道访问不同的URL的时候,它去哪里寻找这个URL所对应的SVN目录.

在httpd.conf文件中,增加如下内容:

[html]  view plain copy
  1. <Location /svn/myproject>  
  2.    DAV svn  
  3.    SVNPath D:/svnroot/myproject  
  4.   
  5.    AuthzSVNAccessFile  D:/svnroot/myproject/conf/access.auth  
  6.    Satisfy Any   
  7.    Require valid-user  
  8.   
  9.    AuthType Basic     
  10.    AuthName "welcome"  
  11.    AuthUserFile  D:/svnroot/myproject/conf/users.auth  
  12.    Require valid-user  
  13. </Location>  

上面使用了users.auth,和access.auth两个文件,我们后面创建.

创建版本库

建立统一路径

创建新文件夹作为统一svn版本库存放的路径(比如新建一个名叫svnroot的文件夹)

创建版本库

在svnroot文件夹下新建文件夹myproject,然后创建版本库。

在d:\创建svnroot文件夹,然后通过svn的svnadmin命令创建数据仓库 

 (注意:D:\svnroot\myproject这个路径是区分大小写的) 

svnadmin createD:\svnroot\myproject 

安装subversion时已经在右键添加快捷菜单,所以可以用右键菜单直接创建数据仓库:下图为在myproject目录上的右键操作。

命令行模式下如图:


创建成功后,我们看到myproject文件夹里面多了些文件,如下:


点击进入conf文件夹,用记事本(或者其他文本编辑软件)打开文件svnserve.conf,找到如下行 #password-db = passwd,把它前面的#去掉,表示myproject是需要密码验证的,再打开conf文件夹下面的passwd文件,用文本编辑器打开,在[users]下面加上我们需要的用户名和密码,比如:

[html]  view plain copy
  1. [users]  
  2. admin = admin  
  3. tom = 123456  

这样我们就启用了两个用户,一个叫admin,密码是admin,一个叫tom,密码是123456.

然后保存passwd文件。我们再建一个文件,叫access.auth,这个文件是设置访问权限的,里面的内容如下:

[html]  view plain copy
  1. [myproject:/]  
  2. Admin = rw  
  3. [myproject:/module1]  
  4. Tom = rw  
  5. Admin = rw  

rw表示可读可写,这表示,myproject下面的所有子目录admin都是具有读写权限的,但是tom只有权限读写次项目下面的module1目录,这个各自的访问权限就分的更细致了。

命令行模式下,到apache安装目录下的bin目录下,操作如下:

为admin用户设置好了密码,创建第一个用户时创建文件,添加第二个用户则不用创建,具体命令行参数有细微区别,注意-cb参数


c命令表示新建文件

创建好后,把bin目录下的user.auth文件粘贴到我们的工程conf目录下,即:d:\\svnroot\myproject\conf目录下。

重新启动apache服务,通过http://localhost:80/svn/myproject/(如果端口为80,没有修改过,则可以直接访问为:http://localhost/svn/myproject

如果成功会看到如下结果:


则表示配置成功。从列出的版本库可以看出,当前版本为0(Revision 0)

版本库创建成功了,我们就可以开始我们的工作了。

从版本库中检出到本地(Check Out)

在D盘新建一个名叫workspace的文件夹,作为我们的工作目录,进入workspace,右键菜单,如图,选择SVN Checkout. ..


在弹出的对话框中输入我们版本库的路径,如图:


点击OK,会弹出用户验证框,输入用户名和密码就可以了。

这样我们就可以再workspace目录里面添加我们的文件了。这里我们随意放入些文件:


其中.svn文件为本地svn记录的一些信息,在上一步我们checkout生成。

提交修改的文件

在workspace文件夹内,或者workspace文件夹上右键弹出菜单中选择svn commit菜单,提交我们的修改。如图:

在弹出的对话框中添加这个版本的信息,如下图:


点击OK后即确认提交,此时我们在IE浏览器中就可以查看到刚才提交的版本信息了,如下图:


外部访问版本库

    我们使用svn基本上是团队开发,所以在实际中,我们不是使用http://localhost这样来访问版本库,而是使用IP地址,这里只需吧localhost修改成我们版本库的实际IP地址就OK.比如:

htpp:// 222.211.107.171/svn/myproject;这样其他机子在访问时,就可以从这个地址中检出版本库资源了。当然你得赋予他们的权限。




  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值