Ant构建

简介

Apache Ant是一个Java库和命令行工具,其任务是将构建文件中描述的进程作为相互依赖的目标和扩展点。只要使用过Linux系统的读者,应该知道 make这个命令。当编译Linux内核及一些软件源程序时,经常要用这个命令。Make命令其实就 是一个项目管理工具,而Ant所实现功能与此类似,像make,gnumake和nmake这些编译工具都有 一定的缺陷,但是Ant却克服了这些工具的缺陷。

Ant的优点

  • 跨平台性。Ant是存Java语言编写的,所示具有很好的跨平台性。

  • 操作简单。Ant是由一个内置任务和可选任务组成的。Ant运行时需要一个XML文件(构建文件)。

  • Ant通过调用target树,就可以执行各种task。每个task实现了特定接口对象。由于Ant构建文件时XML格式的文件,所以和容易维护和书写,而且结构很清晰。

  • Ant可以集成到开发环境中。由于Ant的跨平台性和操作简单的特点,它很容易集成到一些开发环境中去。

Ant的开发

Ant的构建文件

当开始一个新的项目时,首先应该编写Ant构建文件。构建文件定义了构建过程,并被团队开发中每个人使用。Ant构建文件默认命名为 build.xml,也可以取其他的名字。只不过在运行的时候把这个命名当作参数传给Ant。构建文件可以放在任何的位置。一般做法是放在项目顶层目录中,这样可以保持项目的简洁和清晰。下面是一个典型的项目层次结构。
( 注:很多项目的ant脚本中的命名基本上都是一致的,比如:编译一般叫build或者compile;打包一般叫jar或war;生成文档一般命名为 javadoc或javadocs;执行全部任务all。在每个任务的中,ANT会根据配置调用一些外部应用并配以相应参数执行。虽然ANT可调用的外部应用种类非常丰富,但其实最常用的就2,3个:比如javac javadoc jar等。)
(1) src存放文件。
(2) class存放编译后的文件。
(3) lib存放第三方JAR包。
(4) dist存放打包,发布以后的代码。

Ant构建文件是XML文件

每个构建文件定义一个唯一的项目(Project元素)。每个项目下可以定义很多目标(target元素),这些目标之间可以有依赖关系。当执行这类目标时,需要执行他们所依赖的目标。每个目标中可以定义多个任务,目标中还定义了所要执行的任务序列。Ant在构建目标时必须调用所定义的任务。任务定义了Ant实际执行的命令。Ant中的任务可以为3类。
(1) 核心任务。核心任务是Ant自带的任务。
(2) 可选任务。可选任务实来自第三方的任务,因此需要一个附加的JAR文件。
(3) 用户自定义的任务。用户自定义的任务实用户自己开发的任务。

Eclipse的集成ANT

打开Eclipse,点击导航栏的"Window"-->"Preferences"-->"Ant"

image.png

创建一个java项目

image.png

在根目录创建一个build.xml文件

image.png

切换默认的Ant版本,Ant的插件管理

  • 1、菜单栏中打开Window-Preferences-Ant-Runtime
image.png

总共需要设置两项:
1、Ant Home Entries(Default),点击Ant Home,选择ant插件路径:
2、设置Global Entries路径,即为jdk中tools.jar路径

Ant自动化构建

使用ant的主要工作就是配置它的xml文件,默认为build.xml文件。

image.png

build.xml的配置参数

1.<project>标签

每个构建文件都有一个对应<project>标签,<project>标签时构建文件的根标签有以下属性:

  • default:表示默认的运行目标,即指定默认的target(即任务),这个属性是必须的。
  • basedir:表示项目的基准目录。
  • name:表示项目名。
  • description:表示项目的描述。

每个项目对应一个构建文件,但是如果项目比较复杂,包含大量的子项目,每一个子项目都对应有自己的构建文件。

2.<property>标签

有两个特点:

  • 大小写敏感
  • 不可改变,谁先设定,之后的都不能改变。
    语法:${property}

1 、设置 name 和 value 属性值,比如: <property name="srcdir" value="${basedir}/src"/>

2 、 设置 name 和 refid 属性值,比如: <property name="srcpath" refid="dao.compile.classpath"/> ,其中dao.compile.classpath 在别的地方定义。

3 、设置 name 和 location 属性值,比如: <property name="srcdir" location="src"/> ,即将 srcdir 的值设 置为:当前项目根目录的 /src 目录。

4 、设置 file 属性值,比如: <property file="build.properties"/> , 导入 build.properties 属性文件中的属性值

5 、设置 resource 属性值,比如: <propety resource="build.properties"/>, 导入 build.properties 属性文件中的属性值

6 、设置 url 属性值,比如: <property url="http://www.blogjava.net/wiflish/build.properties"/>, 导入http://www.blogjava.net/wiflish/build.properties 属性文件中的属性值。

7 、设置环境变量,比如: <property environment="env"/> ,设置系统的环境变量为前缀 env.
<property name="tomcat.home" value="${env.CATALINA_HOME}"/> 将系统的 tomcat 安装目录设置到 tomcat.home 属性中。

3.<import>标签

  • 引入别的xml文件,提高复用性

  • 含有相同的 target,最终调用哪个target都是以 调用的那个xml文件为基础。若当前xml中没有target,就会从import中寻找。

4.<target>标签

任务,一个project标签下有一个或多个target标签,代表任务,任务间可以存在依赖关系。有如下属性:

  • name表示目标名,这个属性是必须的。
  • depends表示依赖的任务目标。
  • if表示仅当属性设置时才执行,用于验证指定的属性是否存在,若不存在,所在target将不会被执行。
  • unless表示当属性没有设置时才执行。
  • description表示项目的描述。

5.<echo>标签

控制台显示,用于打印/输出信息,类似于log4j的info方法

  • <echo message="hello!"/>
  • <echo message="${msg}"/>
  • <echo>${msg}</echo>
  • <echo>hello!</echo>

以上四种方式均可以显示相应信息

6.<delete>标签

该标签用于删除文件或文件目录,有如下属性:

  • file:删除文件
  • dir:删除目录
  • includeEmptyDirs:值得是否删除空目录,默认是true
  • failonerror:报错是否停止,默认是true
  • verbose:是否列出删除的文件,默认是false
<!--clean other dir-->
    <target name="clean_other_dir">
        <echo message="begin clean_other_dir..."/>
        <delete dir="${basedir}/${compress.dir}"/>
        <delete dir="${basedir}/pub"/>
        <echo message="begin clean html module-xx..."/>
        <delete includeemptydirs="true">
            <fileset dir="${basedir}/src/html" >
                <include name="**/module-*/**"/>
            </fileset>
        </delete>
        <echo message="begin clean res/module-xx、component-xx、res-base..."/>
        <delete includeemptydirs="true">
            <fileset dir="${basedir}/res" >
                <include name="module-*/**"/>
                <include name="component-*/**"/>
                <include name="res-base/**"/>
            </fileset>
        </delete>
    </target

7.<mkdir>标签

该标签用于创建一个目录,它有一个属性dir用来指定所创建的目录名,其代码如下:

  • <mkdir dir=”${class.root}”/>

通过以上代码就创建了一个目录,这个目录已经被前面的property标签所指定。

8.<copy>标签

该标签用于拷贝文件或文件目录,属性如下:

  • file:表示源文件
  • tofile:表示目标文件。
  • todir:表示目标目录。
  • overwrite:是否覆盖目标文件,默认为false
  • includeEmptyDirs:是否拷贝空目录,默认为true
  • failonerror:如目标没有发现是否自动停止,默认值true
  • verbose:是否显示详细信息,默认值false
<target name="cp">
    <copy todir="${compress.dir}" overwrite="true">
         <fileset dir="${ob_baseline.dir}">
            <include name="pub/" />
            <include name="res/" />
            <include name="mail_template/" />
         </fileset>
    </copy>
</target>

9.<fileset>标签

文件集标签,通常与任务结合来使用,用于批量cope和delete

  • dir:指定目录
  • include:包含的子目录

10.<exec>执行文件

用来执行系统命令,或者指定环境的命令

打开命名行,并转到c盘执行dir命令

<target name="test">
    <exec executable="cmd.exe">
        <arg line="/c dir"/>
    </exec>
</target>

能够执行系统命令,就相当于可以执行各种环境比如node、gulp、bower等等:

<!--build style-->
<target name="build_style">
    <echo message="begin build_style..."/>
    <exec dir="." executable="gulp" failonerror="true">
        <arg line="scss"/>
    </exec>
</target>

<!--bower cache clean if必须是${]才是判断true,false, 否则只要有设定值即可执行-->
<target name="bower_cache_clean" if="${is_bower_cache_clean}">
    <echo message="begin bower_cache_clean ..."/>
    <exec dir="." executable="bower" failonerror="true">
        <arg line="cache clean" />
    </exec>
</target>

11.<jar>标签

该标签用来生成一个JAR文件,其属性如下

  • destfile表示JAR文件名
  • basedir表示被归档的文件名
  • includes表示被归档的文件模式
  • excludes表示被排除的文件模式

<war>标签

该标签用来生成一个WAR包,其属性如下:

  • destfile表示生产JAR文件名。
  • dir表示被归档的文件目录。
  • includes表示别归档的文件模式。
  • exchudes表示被排除的文件模式。

12.<javac标签>

该标签用于编译一个或一组java文件,其属性如下

  • srcdir表示源程序的目录,必须的
  • destdir表示class文件的输出目录,默认是当前文件夹
  • include表示被编译的文件的模式
  • excludes表示被排除的文件的模式
  • classpath表示所使用的类路径
  • debug表示包含的调试信息
  • optimize表示是否使用优化
  • verbose 表示提供详细的输出信息
  • fileonerror表示当碰到错误就自动停止

13.<java>标签

该标签用来执行编译生成的.class文件其属性如下

  • classname 表示将执行的类名
  • jar表示包含该类的JAR文件名
  • classpath所表示用到的类路径
  • fork表示在一个新的虚拟机中运行该类
  • failonerror表示当出现错误时自动停止
  • output 表示输出文件
  • append表示追加或者覆盖默认文件

14.<antcall>标签

AntCall 任务的作用是允许在一个target的执行过程中调用并执行其他的target,AntCall任务必须在target元素内执行,这个任务不能在target元素外执行。

需要从一个target传递参数到被调用的target时,可以使用<param> 类型进行传递,对于param 类型只有两个属性:name和value

<target name="sync_module_teach" if="${is_teach}">
    <antcall target="sync_module_item">
        <param name="html.dir" value="org"/>
    </antcall>
</target>

执行sync_module_item任务,并设置参数html.dir的值为org。
该任务定义如下:

<target name="sync_module_item">
    <echo message="begin sync_module ${html.dir}..."/>
    <copy todir="${basedir}/src/html/${html.dir}" overwrite="true" includeEmptyDirs="true">
        <fileset dir="${basedir}/lib">
            <include name="module-*/**" />
        </fileset>
    </copy>
</target>

或者更为简单的表达:

<target name="deploy">
    <echo message="begin auto deploy......"/>
    <antcall target="clean"/>
    <antcall target="bower_install"/>
    <antcall target="cnpm_install"/>
    <antcall target="sync_module"/>
    <antcall target="build_style"/>
    <antcall target="nej_build" />
    <antcall target="cp"/>
</target>

15.<parallel>标签

并行执行多个子任务

通过failonany控制如果一个失败,则不执行。通过并行执行,来提升性能,降低构建花费的时间

<parallel failonany="true">
    <antcall target="sync_module_corp"/>
    <antcall target="sync_module_main"/>
    <antcall target="sync_module_teach"/>
    <antcall target="sync_module_backend"/>
    <antcall target="sync_module_passport"/>
    <antcall target="sync_module_business"/>
    <antcall target="sync_module_k12_teach"/>
    <antcall target="sync_module_k12_backend"/>

    <antcall target="build_style"/>
</parallel>

**16.<regexp>标签

用于正则的定义的使用,可以与matches结合使用。
比如,定义正则:

<regexp id="regexp_env_test" pattern="^${root_dir}/(${test_dir}|${test_k12_dir})/.+"/>
<regexp id="regexp_env_pre" pattern="^${root_dir}/(${pre_dir}|${pre_k12_dir})/.+"/>

通过pattern指定正则内容,通过id标识。
在需要匹配的时候,使用之:

<condition property="is_test">
    <matches string="${basedir}">
        <regexp refid="regexp_env_test"/>
    </matches>
</condition>

**17.<condition>标签

用来判断,如果包含的内容符合条件,则将property指定的属性设置为true,否则为false。
比如上面的例子中,就是将basedir变量的值和regexp_env_test对应的正则匹配,如果正确,就将is_test设置为true,然后后面的流程再去判断。
与之配合的标签有很多,下面一一介绍:

  • istrue,isfalse:断言
<condition property="is_test_backend">
    <and>
        <istrue value="${is_test}"/>
        <istrue value="${is_backend}"/>
    </and>
</condition>

只有is_test和is_backend变量的值均为true,is_test_backend的值才为true。

  • and:逻辑与,需要都满足条件才行,如上例所述。
  • not:逻辑非,反过来的结果。
  • or,xor:逻辑或和逻辑异或。
  • isset:指定属性是否存在:
<condition property="scondition">
    <!--如果属性name不存在则返回false-->
    <isset property="name"/>
</condition>
  • equils:指定属性是否相等:
<condition property="scondition">
    <!--如果arg1的值与arg2的值相等返回true,否则为false-->
    <equals arg1="${name}" arg2="this is name"/>
</condition>
  • filesmatch:指定文件是否相等:
<condition property="scondition">
    <!--如果file1所代表的文件与file2所代表的文件相等返回true,否则为false-->
    <filesmatch file1="testfile1.txt" file2="testfile2.txt"/>
</condition>

实例

 <?xml version="1.0" encoding="utf-8"?>

<project name="project name" default="init" basedir=".">

<description>builds, tests, and runs the project. </description>

<!-- ********************************************************

引入资源和定义资源

******************************************************** -->

<!--   引入资源                                  -->

<property file="build.properties"/>

<property environment="env"/>

<!--定义源程序文件夹-->

<property name="src.dir" location="src/java"/>

<property name="test.dir" location="test"/>

<property name="web.dir" location="web"/>

<!--定义目标程序文件夹-->

<property name="build.dir" location="build"/>

<property name="build.classes.dir" location="${build.dir}/classes"/>

<property name="build.test.dir" location="${build.dir}/test"/>

<property name="dist.dir" location="dist"/>

<!--定义其他文件夹-->

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

<property name="doc.dir" location="doc"/>

<property name="index.dir" location="index"/>

<property name="deploy.dir" location="${env.catalina_home}"/>

<property name="deploy.lib.dir" location="${deploy.dir}/lib"/>

<!--定义其他文件-->

<property name="dist.jar" location="${dist.dir}/web-inf/lib/${project.name}-${project.version}.jar"/>

<property name="deploy.war" location="${deploy.dir}/webapps/${project.name}.war"/>

<!--定义其他属性-->

<available file="${dist.dir}/enduser.agreement" property="final.version"/>

<!-- ********************************************************

设置path

******************************************************** -->

<path id="project.classpath">

<pathelement location="${java.home}/jre/lib/rt.jar"/>

<pathelement location="${build.classes.dir}"/>

<pathelement location="${build.test.dir}"/>

<fileset dir="${deploy.lib.dir}">

<include name="**/*.jar"/>

</fileset>

<fileset dir="${lib.dir}">

<include name="**/*.jar"/>

</fileset>

</path>

<target name="init" description=" 信息 : 显示项目基本信息.">

<tstamp>

<format property="now" pattern="yyyy-mm-dd hh:mm"/>

</tstamp>

<echo> ==================================================


  显示项目基本信息.


  项目名称: ${project.name}

  项目版本: ${project.version}

  作者 : ${author}

   时戳 : ${dstamp}-${tstamp}



  用法:

     ant -buildfile build.xml compile 或

     ant compile 或

     ant 甚至

     ant clean dist

   帮助:

     ant -projecthelp



==================================================</echo>

</target>

<target name="prepare" depends="init" description=" 准备 : 创建各种文件夹.">

<echo> ==================================================



   创建各种文件夹.



================================================== </echo>

<!--  创建源程序文件夹  -->

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

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

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

<mkdir dir="${web.dir}/web-inf"/>

<!--  创建目标程序文件夹  -->

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

<mkdir dir="${build.classes.dir}"/>

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

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

<mkdir dir="${dist.dir}/web-inf"/>

<mkdir dir="${dist.dir}/web-inf/lib"/>

<!--  创建其他文件夹  -->

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

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

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

</target>

<target name="javadoc" depends="prepare" description="生成文档: 生成帮助文档.">

<echo> ==================================================



   生成帮助文档.



==================================================</echo>

<javadoc packagenames="*.*" sourcepath="${src.dir}" destdir="${doc.dir}" author="true" version="true" use="true" encoding="utf-8">

<classpath refid="project.classpath"/>

</javadoc>

</target>

<target name="compile" depends="prepare" description=" 编译 : 编译所有源程序." unless="final.version">

<echo> ==================================================



  编译所有源程序.



==================================================</echo>

<javac srcdir="${src.dir}" destdir="${build.classes.dir}" debug="on" deprecation="on" encoding="utf-8">

<compilerarg value="-xlint:unchecked"/>

<classpath refid="project.classpath"/>

</javac>

<javac srcdir="${test.dir}" destdir="${build.test.dir}" encoding="utf-8">

<compilerarg value="-xlint:unchecked"/>

<classpath refid="project.classpath"/>

</javac>

</target>

<target name="test" depends="compile" description=" 测试 : 运行所有测试程序.">

<echo> ==================================================



   运行所有测试程序.



==================================================</echo>

<junit haltonfailure="true">

<classpath refid="project.classpath"/>

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

<batchtest>

<fileset dir="${build.test.dir}" includes="**/*test.class"/>

</batchtest>

<sysproperty key="doc.dir" value="${doc.dir}"/>

<sysproperty key="index.dir" value="${index.dir}"/>

</junit>

</target>

<target name="dist" depends="compile" description=" 分发 : 生成分发文件.">

<echo> ==================================================



   生成分发文件:

      ${dist.jar}



==================================================</echo>

<!-- 从打包文件排除单元测试 -->

<jar destfile="${dist.jar}" basedir="${build.classes.dir}" includes="**/*.*" excludes="**/*test.class">

<!-- manifest="manifest.mf" > -->

<manifest>

<attribute name="author" value="${author}"/>

</manifest>

</jar>

</target>
<!-- ********************************************************

用于调试

******************************************************** -->

<target name="debug" depends="dist" description=" 调试 "/>

<!-- ********************************************************

用于效验

******************************************************** -->

<target name="verify" depends="dist" description=" 效验 "/>

<target name="run-deploy" depends="dist" description=" 部署 : 把文件部署到指定位置.">

<echo> ==================================================



   把文件部署到指定位置:

      ${deploy.war}



==================================================</echo>

<copy todir="${dist.dir}/web-inf/lib">

<fileset dir="${lib.dir}" includes="*.jar"/>

</copy>

<copy todir="${dist.dir}">

<fileset dir="${web.dir}" includes="**/*.*"/>

</copy>

<jar destfile="${deploy.war}" basedir="${dist.dir}" includes="**/*.*" excludes="**/*test.class">

  <!--  manifest="manifest.mf" >  -->
</jar>
</target>

</project>

模板

以下xml依次定义了init(初始化),compile(编译),test(测试),doc(生成文档),pack(打包)任务,可以作为模板

<?xml version="1.0" encoding="utf-8"?>

<project name="Hello world" default="doc">  

<!-- properies -->  

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

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

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

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

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

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

     <!-- 定义classpath -->  

     <path id="master-classpath">  

         <fileset file="${lib.dir}/*.jar" />  

         <pathelement path="${classes.dir}"/>  

     </path>  

     <!-- 初始化任务 -->  

     <target name="init">  

     </target>  

     <!-- 编译 -->  

     <target name="compile" depends="init" description="compile the source files">  

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

         <javac srcdir="${src.dir}" destdir="${classes.dir}" target="1.4">  

             <classpath refid="master-classpath"/>  

         </javac>  

     </target>  

     <!-- 测试 -->  

     <target name="test" depends="compile" description="run junit test">  

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

         <junit printsummary="on"  

                 haltonfailure="false"  

                 failureproperty="tests.failed"  

                 showoutput="true">  

             <classpath refid="master-classpath" />  

             <formatter type="plain"/>  

             <batchtest todir="${report.dir}">  

                 <fileset dir="${classes.dir}">  

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

                 </fileset>  

             </batchtest>  

         </junit>  

         <fail if="tests.failed">  

         ***********************************************************   

         ****   One or more tests failed!   Check the output ...   ****   

         ***********************************************************   

         </fail>  

     </target>  

     <!-- 打包成jar -->  

     <target name="pack" depends="test" description="make .jar file">  

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

         <jar destfile="${dist.dir}/hello.jar" basedir="${classes.dir}">  

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

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

         </jar>  

     </target>  

     <!-- 输出api文档 -->  

     <target name="doc" depends="pack" description="create api doc">  

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

      <javadoc destdir="${doc.dir}"  

             author="true"  

             version="true"  

             use="true"  

             windowtitle="Test API">  

             <packageset dir="${src.dir}" defaultexcludes="yes">  

                 <include name="example/**" />  

             </packageset>  

             <doctitle><![CDATA[<h1>Hello, test</h1>]]></doctitle>  

             <bottom><![CDATA[<i>All Rights Reserved.</i>]]></bottom>  

             <tag name="todo" scope="all" description="To do:" />  

         </javadoc>  

     </target>  

</project>  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Ant构建文件是XML文件。每个构建文件定义一个唯一的项目(Project元素)。每个项目下可以定义很多目标(ta...
    by小杰阅读 969评论 0 0
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,717评论 6 342
  • Ant 开发Ant的构建文件当开始一个新的项目时,首先应该编写Ant构建文件。构建文件定义了构建过程,并被团队开发...
    天涯刀客01号阅读 1,093评论 0 1
  • “成为一个作家,从模仿开始”,这条箴言恐怕已不是秘密。可是,读过约翰·加德纳的《成为小说家》(孟庆玲、伊小丽译,中...
    吴玫阅读 989评论 2 7