无所不能的ant

.Ant简介:

       Ant----Another Neat Tool,是一个基于Java的跨平台构建工具,作为一个优秀的构建工具Ant有如下的优点:
Ø         语法简单,便于学习,如果你使用过XMl,就会更加感觉到这一点;
Ø         易于使用,可以减少基于Make方法的大型软件项目中编写makefile的人数;
Ø         跨平台,以一种灵巧的方式管理Java的classpath和文件的目录结构;
Ø         运行速度快,所有的Java都可以在Ant的JVM中启动;
Ø         与Junit测试框架紧密集成以实现极限编程的单元测试;
Ø         使用Java语言可以很容易的对他进行扩展;
Ø         内置对J2EE的开发的支持,如EJB的编译和打包等;
Ø         致力于解决Java项目的部署问题:如FTP,Telnet,应用服务器,SQL命令等,这些都可以自动部署.

 
Ant的官方网站: http://ant.apache.org/
Ant的最新版本:Ant 1.6.5
本文所有的例子运行的环境:JDK1.4.2,Ant1.6.2,eclipse3.0

 

.介绍AntDATATYPE和特性

       Ant的核心任务就是target,一个Ant文件有多个target组成,而这些target之间,又有相互的依赖关系--depends,运行的时候默认运行project中指定的target.在构建一个典型的Java工程时,多数的步骤用于处理文件和路径(如classpath),Ant提供的datatype可以很自然的处理这两个概念.文件集和路径以及其他的几种类型的datatype,构成了Ant的构建文件的基本结构.

 

1.路径(Path

       在javac中我们经常使用的就是classpath,一个路径定义的例子如下:

                   <classpath>

                            <pathelement location =”lib/some.jar”/>

                   </classpath>

       location允许你指定单个的文件或者目录,也可以通过另一个路径莱扩展当前的路径,使用path来代替location:

                   <classpath>

                            <pathelement path =”build/classes;lib/some.jar”/>

                   </classpath>

       路径定义中元素间的分隔符可以使用分号,冒号,路径分隔符可以使用斜杠,反斜杠,不需要考虑操作系统的差异.

 

2.文件集(Fileset)

       所有的构建过程都会隐式的对一系列文件进行操作,Ant将文件集看成一种本地的datatype,下面看一个例子,这个例子是将文件从一个目录copy到另一个目录中:

                   <copy todir=”new_web”>

                            <fileset dir=”web”/>

                   </copy>

       在构建过程中我们通常需要包含或者排除一些文件,下面是一些典型的文件集示例:

                   <fileset>                                  

                            <include name="**/*Test.java"/>    

                   </fileset>    

            <fileset>

                            <exclude name="**/*.jsp"/>

                   </fileset>  

       默认情况下,include和exclude中的值是大小写敏感的,可以通过设置casesensitive=”false”,来取消它.
还有在许多情况下,IDE和代码管理系统会生成许多的临时文件,我们不得已要在每个文件集中去设置排除子句,为了避免这种情况,Ant针对这些特殊的模式的排除模式在默认情况下是激活的(例如:**/CVS,**/#*#等),详细模式可以查找相关的文档!.

 

3.模式集(Patternset)

       在文件集中使用Ant的另一个核心datatype:模式集,来实现包含和排除功能.模式匹配功能如下:
l       *  指代从零到任意长的字符.
l       ? 指代单一字符.
l       ** 作为目录名,代表目录树上从当前节电往下的所有目录,可以是零到任意多个目录.
l       以/ 或 /结尾的模式意味着结尾是**.
      

4.选择器(Selector)                              

       Ant1.5以上的版本包含了一个精密的新特性,选择器,他用来选择包含在文件集中的文件.介绍几种常用的内建选择器:
<filename>:基于模式匹配文件,工作方式类似与模式集的include或exclude元素
<size>:以小于,大于,等于该指定值为条件来选择文件.
<date>:以最后修改时间早于,迟于或等于指定值来选择文件.
<present>:选择存在于其他目录树的文件.
<contains>选择包含指定字符串的文件.
       这些选择器都可以被合并到选择器容器中以提供分组和逻辑表达,这些容器就是<and>,<or>,<not>,<none>和<majority>
       比较两个目录,并将只在一个目录下存在的文件复制到另一个目录下,我们来结合使用<not>和<present>

                   <copy todir="newfiles">

                            <fileset dir="web">

                                     <not>

                                               <present targetdir="currebtfiles"/>

                                     </not>

                            </fileset>

                   </copy>

       使用<contains>选择器,我们可以选择只包含特定字符串的文件:

                   <copy todir="newfiles">

                            <fileset dir="web">

                                     <contains text="System"/>

                            </fileset>

                   </copy> .

 
       这里简单提一下Ant的一个特性:Property,它与java.util.Property在概念上非常相似,它允许在构建文件中自定义特性,并且允许将环境变量作为特性. Property具有特殊的权限,他可以在<target>之外执行,具体的用法,在下面将结合例子说明.

 
       以上介绍了几种Ant的常用datatype,Ant还包括很多的datatype,例如过滤集(Filterset),过滤链(filterchain),过滤阅读器(FilterReader),Mapper映射器,ZipFileset等等,可以通过相关资料来了解!
缺三

.使用Ant进行Junit测试

 

       我们除了使用java来直接运行junit之外,我们还可以使用junit提供的junit taskant结合来运行。涉及的几个主要的ant task如下:

l         <junit>,定义一个junit task

l         <batchtest>,位于<junit>中,运行多个TestCase

l         <test>,位于<junit>中,运行单个TestCase

l         <formatter>,位于<junit>中,定义一个测试结果输出格式

l         <junitreport>,定义一个junitreport task

l         <report>,位于<junitreport>中,输出一个junit report

       运行Junit需要jakarta-ant-1.4-optional.jarJunit.jar,因为这两个包用于支持ant task--<junit>,所以不能在build.xml文件中加载,需要将他们放到ANT_HOME中去.使用eclipse可以按照一下步骤加入:

Windows-Preference-Ant-Runtime-Ant Home Entries

       下面看一个Junit测试的例子:

<?xml version="1.0"?>

 

<project name="project" default="junit">

 

         <property name="run.classpath" value="bin"></property>

 

         <property name="run.srcpath" value="src"></property>

 

         <property name="test.srcpath" value="test"></property>

 

         <property name="lib.dir" value="lib"/>    

 

        

 

         <path id="compile.path">

 

                   <pathelement location="${lib.dir}/junit-3.8.1.jar"/>

 

                   <pathelement location="${lib.dir}/log4j-1.2.8.jar"/>

 

         </path>

 

        

 

         <target name="compile">

 

                   <javac destdir="${run.classpath}" srcdir="${run.srcpath}"

 

                            classpathref="compile.path"/>

 

                   <javac destdir="${run.classpath}" srcdir="${test.srcpath}"

 

                            classpathref="compile.path"/>

 

         </target>

 

        

 

         <target name="junit" depends="compile">

 

                   <junit printsummary="true">

 

                            <classpath path="${run.classpath}"></classpath>

 

                            <test name="org.ant.test.Test1"></test>

 

                   </junit>

 

         </target>

 

</project>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    可以看出Junit的使用基本和java差不多, printsummary允许输出junit信息,当然Ant提供formatter属性支持多样化的junit信息输出.Ant包含三种形式的formatter:

brief:以文本格式提供测试失败的详细内容;

plain:以文本格式提供测试失败的详细内容以及每个测试的运行统计;

xml:xml格式提供扩展的详细内容,包括正在测试时的Ant特性,系统输出,以及每个测试用      例的系统错误.

       使用formatter时建议将printsummary关闭,因为他可能对formatter的生成结果产生影响,并多生成一份同样的输出.当然我们可以使用formatter将输出结果显示在console:

<formatter type="brief" usefile="false"/>

 

Junit支持多个formatter同时存在:

<formatter type="brief" usefile="false"/>

 

<formatter type="xml"/>

 

使用xml我们可以得到扩展性更强的信息输出,这时在<test>中要设定todir来指定xml的输出路径.

       在通常情况下我们不可能一个一个来处理junit,所以Ant提供了<batchtest>,可以在他里面嵌套文件集(fileset)以包含全部的测试用例.

       对于大量的用例,使用控制台输出,或者使用文件或xml文件来作为测试结果都是不合适的,Ant提供了<junitreport>任务使用XSLTxml文件转换为HTML报告.该任务首先将生成的XML文件整合成单一的XML文件,然后再对他进行转换,这个整合的文件默认情况下被命名为:TESTS-TestSuites.xml.

             <junitreport todir="${test.xml}">

 

               <fileset dir="${test.xml}">

 

                 <include name="TEST-*.xml"/>

 

               </fileset>

 

               <report format="frames" todir="${test.report}"/>

 

             </junitreport>

 

 

 

 

 

 

 

<report>元素指示转换过程中生成有框架(frames)或者无框架的类似与javadoc格式的文件,并保存到todir所在的目录下面.(由于xalan对于JDK1.4以上的版本存在问题,所以要生成HTML文件需要以下步骤:现在最新的xalan,%JAVA_HOME%/jre/lib中建立文件夹endorsed.xalan中的jar文件copy到里面).

下面看一个完整的例子:

            

 

<?xml version="1.0"?>

 

<project name="project" default="junit">

 

    <property name="run.classpath" value="bin"></property>

 

    <property name="run.srcpath" value="src"></property>

 

    <property name="test.srcpath" value="test"></property>

 

    <property name="test.xml" value="xml"></property>

 

    <property name="test.report" value="report"></property>

 

    <property name="lib.dir" value="lib"/>

 

   

 

    <path id="compile.path">

 

       <pathelement location="${lib.dir}/junit-3.8.1.jar"/>

 

       <pathelement location="${lib.dir}/log4j-1.2.8.jar"/>

 

    </path>

 

   

 

    <target name="init">

 

       <delete dir="${test.report}"/>

 

       <mkdir dir="${test.report}"/>

 

       <delete dir="${test.xml}"/>

 

       <mkdir dir="${test.xml}"/>

 

    </target>

 

   

 

    <target name="compile" depends="init">

 

       <javac destdir="${run.classpath}" srcdir="${run.srcpath}"

 

           classpathref="compile.path"/>

 

       <javac destdir="${run.classpath}" srcdir="${test.srcpath}"

 

           classpathref="compile.path"/>

 

    </target>

 

   

 

    <target name="junit" depends="compile">

 

       <junit printsummary="false">

 

           <classpath path="${run.classpath}"></classpath>

 

           <formatter type="xml"/>

 

           <batchtest todir="${test.xml}">

 

              <fileset dir="${run.classpath}">

 

                  <include name="**/Test*.class"/>

 

              </fileset>

 

           </batchtest>

 

       </junit>

 

      

 

        <junitreport todir="${test.xml}">

 

          <fileset dir="${test.xml}">

 

            <include name="TEST-*.xml"/>

 

          </fileset>

 

          <report format="frames" todir="${test.report}"/>

 

        </junitreport>

 

    </target>

 

</project>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<?xml version="1.0"?>

 

<project name="project" default="junit">

 

    <property name="run.classpath" value="bin"></property>

 

    <property name="run.srcpath" value="src"></property>

 

    <property name="test.srcpath" value="test"></property>

 

    <property name="test.xml" value="xml"></property>

 

    <property name="test.report" value="report"></property>

 

    <property name="lib.dir" value="lib"/>

 

   

 

    <path id="compile.path">

 

       <pathelement location="${lib.dir}/junit-3.8.1.jar"/>

 

       <pathelement location="${lib.dir}/log4j-1.2.8.jar"/>

 

    </path>

 

   

 

    <target name="init">

 

       <delete dir="${test.report}"/>

 

       <mkdir dir="${test.report}"/>

 

       <delete dir="${test.xml}"/>

 

       <mkdir dir="${test.xml}"/>

 

    </target>

 

   

 

    <target name="compile" depends="init">

 

       <javac destdir="${run.classpath}" srcdir="${run.srcpath}"

 

           classpathref="compile.path"/>

 

       <javac destdir="${run.classpath}" srcdir="${test.srcpath}"

 

           classpathref="compile.path"/>

 

    </target>

 

   

 

    <target name="junit" depends="compile">

 

       <junit printsummary="false">

 

           <classpath path="${run.classpath}"></classpath>

 

           <formatter type="xml"/>

 

           <batchtest todir="${test.xml}">

 

              <fileset dir="${run.classpath}">

 

                  <include name="**/Test*.class"/>

 

              </fileset>

 

           </batchtest>

 

       </junit>

 

      

 

        <junitreport todir="${test.xml}">

 

          <fileset dir="${test.xml}">

 

            <include name="TEST-*.xml"/>

 

          </fileset>

 

          <report format="frames" todir="${test.report}"/>

 

        </junitreport>

 

    </target>

 

</project>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

生成的文档:

 

 

 

点击Properties超链接会弹出一个窗口显示在测试运行时全部的Ant特性,这对于跟踪由环境和配置造成的失败是非常便利的!

.使用Ant运行本地程序

1.使用Ant运行windows的批处理文件

 

       要在Ant内运行一个外部程序,应使用<exec>任务.它允许你执行下列操作:

l         指定程序名和要传入的参数.

l         命名运行目录.

l         使用failonerror标志来控制当应用程序失败时是否停止构建.

l         指定一个最大程序持续时间,时间超过则中止程序.任务在这时被认为是失败,但是至少构建会中止,而不是挂起,这对于自动构建是至关重要的.

l         将输出存到一个文件或特性.

l         指定java调用本地程序时需要预先设定的环境变量.

 

       下面来看一个例子:

批处理文件:

Test.bat

           
           

@echo off

 

echo Hello > test.txt

 

 

 

 

 

build.xml

           
           

<?xml version="1.0"?>

 

<project name="batch" default="extract" basedir=".">

 

    <target name="extract">

 

       <exec executable ="cmd">

 

           <arg line="/c a.bat"/>     

 

       </exec> 

 

    </target>

 

</project>

 

 

 

 

 

 

 

 

       使用executable元素标记指定使用的命令,具体用法可以在命令行下面输入help cmd查看.如果你希望在运行批处理发生错误时中止构建需要设定failοnerrοr="on".加入你的外部程序在某个时刻挂起,也许是在与远程站点对话,而你不希望构建永远被挂起,Ant提供了timeout这个属性,他是一个以毫秒为单位的数字.下面看一下如何使用Ant来运行tomcat.

       启动tomcat需要两个环境变量CATALINA_HOME, JAVA_HOME,如果你在环境变量中已经设定,Ant中就不需要进行处理,如果没有需要使用<env>属性来设定,你也可以使用<env>属性覆盖你以前的环境变量.

 

           
           

<?xml version="1.0"?>

 

<project name="batch" default="tomcat-start" basedir=".">

 

    <property name="tomcat.dir" value="C:/Tomcat5"></property>

 

   

 

    <target name="tomcat-start">

 

    <exec dir="${tomcat.dir}/bin" executable="cmd">

 

       <env key="CATALINA_HOME" path="${tomcat.dir}"/>

 

       <arg value="/C startup.bat"/>

 

    </exec>

 

    </target>

 

</project>

 

 

 

 

 

 

 

 

 

 

 

 

2.使用Ant运行shell文件

 

      由于windowsXPcmd默认没有安装ps,bash等命令,所以我们需要借助的三方的软件来实现这个功能,这里使用cgywin,cgywinbin目录加到环境变量的Path里面(下面使用Ant运行cvs也会用到).

 

           
           

<?xml version="1.0"?>

 

<project name="batch" default="shell" basedir=".">

 

    <property name="tomcat.dir" value="C:/Tomcat5"></property>

 

   

 

    <target name="shell">

 

    <exec dir="${tomcat.dir}/bin" executable="bash">

 

       <env key="CATALINA_HOME" path="${tomcat.dir}"/>

 

       <arg value="startup.sh"/>

 

    </exec>

 

    </target>

 

</project>

 

 

 

 

 

 

 

 

 

 

 

3.使用Ant运行cvs

 

       Ant内置cvs属性,可以很方便的使用cvs:

 

           
           

<?xml version="1.0"?>

 

<project name="batch" default="shell" basedir=".">

 

    <property name="cvs.root" value="..."></property>

 

   

 

    <target name="cvs">

 

       <cvs cvsroot="cvs.root" command="checkout ../.."/>

 

    </target>

 

</project>

 

 

 

 

 

 

 

 

如果你的Documents and Settings中有.cvspass文件,那么可以不用设定cvsroot,Ant会自动寻找.

 

 

 

.工程的打包部署

 

       工程的打包,主要就是文件的操作,下面通过例子简单介绍一下文件的移动,复制和删除.

 

           
           

<?xml version="1.0"?>

 

<project name="project" default="jar">

 

    <target name="copy">

 

       <tstamp>

 

           <format property="time.format"                                           pattern="yyyy-mm-dd'T'HH:mm:ss"

 

              locale="en"/>

 

       </tstamp>

 

       <copy tofile="dist/readme" file="test.txt">

 

           <filterset>

 

              <filter token="TIME" value="${time.format}"/>

 

           </filterset>

 

       </copy>

 

    </target>

 

 

    <target name="move">

 

       <move todir="dist">

 

           <fileset dir="lib">

 

              <include name="*.jar"/>

 

           </fileset>

 

       </move>   

 

    </target>

 

   

 

    <target name="delete" depends="copy,move">

 

       <delete verbose="true" failοnerrοr="false">

 

           <fileset dir="dist">

 

              <include name="*.jar"/>

 

           </fileset>   

 

       </delete>

 

    </target>

 

</project>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

       需要说明的是文件删除的时候可能这个文件正在被别人是用而无法删除,所以要用failonerror来标记,文件的复制是时间戳敏感的,如果拷贝的文件比原文件要老,那么Ant将不会执行copy,解决的办法是将overwrite属性设置为true,由于移动文件是复制文件的一个子类,所以它们的原理基本相同.

 

      

 

       前面已经例举过一个jar文件打包的例子,下面主要介绍war文件的打包.Ant提供war文件打包的属性.<war>任务是<jar>任务的子类,但是他也提供了一些特有的属性:

 

 

           
           

    <target name="deploy" depends="init">

 

           <war destfile="${war.dir}/spring.war" webxml="${web.dir}/web.xml" >

 

              <classes dir="${web.dir}/classes"></classes>

 

              <fileset dir="WebContent" excludes="web.xml"></fileset>

 

              <lib dir="${web.dir}/lib"></lib>

 

           </war>

 

       </target>

 

 

 

 

 

 

 

 

 

 

 

可以看出war任务提供了许多WEB应用程序的特有属性,只要你指定了这些文件,war任务就会自动将他们放到正确的位置.

 

 

       部署是项目发布的过程,Ant支持FTP,Email,本地和远程等几种部署模式,但是Ant并不内置对一些部署的支持,需要第三方的库.

 

optional.jar            也可能是这样的名字:  jakarta-ant-1.4.1.optional.jar

 

netcomponents.jar       <ftp><telnet>需要

 

activation.jar                   <mail>需要

 

mail.jar                           <mail>需要

 

       下面只以本地部署为例,服务器为tomcat. 

 

       由于tomcat支持热部署,可以将webapp文件下的war文件自解压缩,所以最简单的部署方式是将工程打成war包后直接copywebapp目录下面.另一种方法是使用tomcat的管理员身份,manager页面装载和删除应用,这种方法比较复杂,也比较正规,他也是远程部署的基础.

 

 

           
           

<?xml version="1.0"?>

 

<project name="project" default="deploy-local-catalina">

 

    <property name="war.dir" value="dist"></property>

 

    <property name="web.dir" value="WebContent/WEB-INF"></property>

 

    <property name="webapp.name" value="spring"></property>

 

    <property name="catalina.port" value="8080"></property>

 

    <property name="catalina.username" value="admin"></property>

 

    <property name="catalina.password" value="admin"></property>

 

   

 

    <target name="init">

 

       <mkdir dir="${war.dir}"/>

 

    </target>

 

 

    <target name="mkwar" depends="init">

 

       <war destfile="${war.dir}/spring.war" webxml="${web.dir}/web.xml" >

 

           <classes dir="${web.dir}/classes"></classes>

 

           <fileset dir="WebContent" excludes="web.xml"></fileset>

 

           <lib dir="${web.dir}/lib"></lib>

 

       </war>

 

    </target>

 

   

 

    <target name="remove-local-catalina">

 

       <property name="deploy.local.remove.url"

 

           value="http://localhost:${catalina.port}/manager/remove"></property>

 

       <get dest="deploy.local.remove.txt"

 

           src="${deploy.local.remove.url}?path=/${webapp.name}"

 

           username="admin" password="admin"/>

 

      

 

       <loadfile property="depoly.local.remove.result"

 

           srcfile="depoly.local.remove.txt"></loadfile>

 

    </target>

 

   

 

    <target name="deploy-local-catalina" depends="mkwar, remove-local-catalina">

 

       <property name="deploy.local.urlpath"

 

           value="file:///D:/MyEclipse/workspace/springstruts/dist/spring.war"></property>

 

       <property name="deploy.local.url.params"

 

           value="path=/${webapp.name}&amp;war=${deploy.local.urlpath}"></property>

 

       <property name="deploy.local.url"

 

           value="http://localhost:${catalina.port}/manager/install"></property>

 

       <get src="${deploy.local.url}?${deploy.local.url.params}"

 

           dest="deploy-local.txt"

 

           username="admin"

 

           password="admin"/>

 

       <loadfile property="deploy.local.result"

 

           srcfile="deploy-local.txt"></loadfile>

 

    </target>

 

</project>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

可以看出只要将上面的localhost换成目标的ip地址就可以实现tomcat的远程部署.

 

      终于完成了Ant初级的学习笔记,感觉到后来没有什么动力,越写越乱,很多地方解释的不清楚,只是给出build文件,然后就一笔带过,在以后的高级篇中,我会更加努力的!!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IDM全称Internet Download Manager(互联网下载管理器),是一款用于加速和管理下载任务的神器级软件。它可以稳定、快速地下载各种文件,提供了多线程下载、断点续传和安全性保障等功能,使得用户能够更加方便地下载所需的内容。 首先,IDM通过多线程技术,能够将一个下载任务分成多个线程同时下载,从而大幅度提升下载速度。无论是下载视频、音乐、文档还是软件等,IDM都能够以最快的速度将文件下载到本地,节省了用户的时间。 其次,IDM支持断点续传功能,即使因为网络中断、电脑关机等原因导致下载中断,用户不必从头再次下载,而是可以将下载任务从中断处继续进行,节省了用户的流量和时间成本。 此外,IDM还内置了智能下载逻辑和计划功能,可以根据网络状况和用户设定进行智能分配带宽,避免占用过多资源而影响其他网络活动。同时,用户还可以根据个人需求设置定时下载任务,让IDM在特定时间自动开始下载或关闭,提高了用户的使用便利性。 最重要的是,IDM不仅支持常见的HTTP、HTTPS和FTP协议,还能够有效地与各种主流浏览器无缝整合,实现一键下载。用户只需在所需下载的文件链接上右键点击,选择“IDM下载链接”,即可调用IDM进行高速下载,大大简化了文件获取过程。 综上所述,IDM不仅速度快、稳定性高,而且具有多种实用功能,是一款无所不能的下载神器,能够满足各类用户的下载需求。无论是下载工作文档、观看在线视频还是获取软件安装包,IDM都能够为用户提供快速、便捷的下载体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值