Jenkins使用及插件開(kāi)發(fā)介紹

Jenkins使用及插件開(kāi)發(fā)介紹

介紹

Jenkins是一個(gè)廣泛用于持續(xù)構(gòu)建的可視化web工具,就是各種項(xiàng)目的的“自動(dòng)化”編譯吝沫、打包呻澜、分發(fā)部署,將以前編譯惨险、打包羹幸、上傳、部署到Tomcat中的過(guò)程交由Jenkins辫愉,Jenkins通過(guò)給定的代碼地址栅受,將代碼拉取到j(luò)enkins宿主機(jī)上,進(jìn)行編譯恭朗、打包和發(fā)布到web容器中窘疮。Jenkins可以支持多種語(yǔ)言(比如:java、c#冀墨、php等等)闸衫,也兼容ant、maven诽嘉、gradle等多種第三方構(gòu)建工具蔚出,同時(shí)跟git、svn無(wú)縫集成虫腋,也支持直接與github直接集成骄酗。

WiseBuild也是基于jenkins進(jìn)行的開(kāi)發(fā),在下面會(huì)看到很多和WiseBuild相似的地方

安裝

  1. 到j(luò)enkins官網(wǎng)http://jenkins.io/下載war包

使用

java -jar jenkins.war

或者將war放到web容器中悦冀,啟動(dòng)web容器

啟動(dòng)war包趋翻,會(huì)自動(dòng)將war包解壓到~/.jenkins目錄下,并且生成一些目錄和配置文件盒蟆,我們?cè)趈enkins中配置的job也會(huì)保存到這個(gè)目錄下
打開(kāi)瀏覽器踏烙,輸入localhost:8080 就可以訪問(wèn)到j(luò)enkins的web界面了

Untitled Image

新建項(xiàng)目

用個(gè)小例子簡(jiǎn)單示范一下jenkins的使用


Untitled Image
源碼配置

將源碼信息配置上去,我選擇一個(gè)github上面的項(xiàng)目历等,如果源碼管理中沒(méi)有g(shù)it這個(gè)選項(xiàng)讨惩,只需要到系統(tǒng)管理中添加git這個(gè)插件即可


Untitled Image
構(gòu)建命令
Untitled Image

在構(gòu)建階段輸入以下命令:

cd ${WORKSPACE} && ./gradlew build && mv ${WORKSPACE}/docker/jpetstore.war /usr/local/tomcat9/webapps

該命令分為三個(gè)部分:

  1. cd ${WORKSPACE} WORKSPACE是jenkins的定義的環(huán)境變量,代表該項(xiàng)目對(duì)應(yīng)的文件路徑寒屯,該項(xiàng)目檢出的源碼也是該目錄栅迄。類似的環(huán)境變量還有BUILD_NUMBER, BUILD_ID, JOB_NAME, JENKINS_HOME等等
  2. ./gradlew build使用gradle 執(zhí)行構(gòu)建命令,將檢出的源碼編譯打包為war包奢米,這里我們使用的構(gòu)建工具是gradle痴怨,如果是使用maven,可以mvn clean package
  3. mv {WORKSPACE}/docker/jpestore.war /usr/local/tomcat9/webapps/
    將打包好的war包手動(dòng)放到tomcat的webapps目錄下,以便Tomcat能啟動(dòng)該項(xiàng)目了

最后,點(diǎn)擊保存回到主面板上。

構(gòu)建

點(diǎn)擊右邊的立即構(gòu)建

Untitled Image

開(kāi)始執(zhí)行構(gòu)建农渊,可以看見(jiàn)構(gòu)建的進(jìn)度,旁邊的#12 就是本次構(gòu)建的構(gòu)建號(hào)(BUILD_NUMBER)
Untitled Image

也可以在查看console output
Untitled Image

console output 會(huì)顯示出本次構(gòu)建的一些日志信息
Untitled Image

這里我們web容器和jenkins都是在同一臺(tái)服務(wù)器上或颊,可以利用shell命令來(lái)進(jìn)行手動(dòng)部署砸紊,如果jenkins的宿主機(jī)和web服務(wù)器不是同一臺(tái),我們也可以利用gradle和maven的部署功能囱挑,例如使用mvn deploy來(lái)將項(xiàng)目部署到遠(yuǎn)程服務(wù)器上
到此醉顽,我們的一個(gè)持續(xù)集成的一個(gè)項(xiàng)目就已經(jīng)搭建好了,現(xiàn)在一旦我們對(duì)代碼修改進(jìn)行提交平挑,然后jenkins就會(huì)獲取最新的代碼然后按照我們上面配置的命令進(jìn)行構(gòu)建和部署游添。


jenkins插件

在前面我們看見(jiàn)jenkins可以支持git, svn, maven等很多功能,這些都是Jenkins的插件通熄,jenkins本身不提供很多功能唆涝,我們可以通過(guò)使用插件來(lái)滿足我們的使用,接下來(lái)就介紹一下插件的原理以及我們?cè)趺赐ㄟ^(guò)寫(xiě)一個(gè)自己的插件來(lái)滿足我們的需求唇辨。

擴(kuò)展點(diǎn)

但是jenkins有很多的擴(kuò)展點(diǎn)ExtensitonPoint)廊酣,它是Jenkins系統(tǒng)的某個(gè)方面的接口或抽象類。這些接口定義了需要實(shí)現(xiàn)的方法赏枚,而Jenkins插件需要實(shí)現(xiàn)這些方法亡驰,也可以叫做在此擴(kuò)展點(diǎn)之上進(jìn)行擴(kuò)展Jenkins。有關(guān)擴(kuò)展點(diǎn)的詳細(xì)信息饿幅,請(qǐng)參閱Jenkins 官方ExtentionPoints文檔凡辱。通過(guò)這些擴(kuò)展點(diǎn)我們可以寫(xiě)插件來(lái)實(shí)現(xiàn)自己的需求。
下面是一些常用的擴(kuò)展點(diǎn):

  • Scm :代表源碼管理的一個(gè)步驟栗恩,如下面的Git透乾,Subversion就是擴(kuò)展的Scm

    Untitled Image

  • Builder : 代表構(gòu)建的一個(gè)步驟,如下圖中在構(gòu)建過(guò)程中磕秤,我們可以增加一個(gè)構(gòu)建步驟乳乌,而每一個(gè)選項(xiàng)都是對(duì)應(yīng)一個(gè)Builder,在每一個(gè)Builder中都有自己不同的功能亲澡。如Execute shell钦扭,這就是一個(gè)ShellBuilder,意味著在構(gòu)建過(guò)程中會(huì)執(zhí)行一個(gè)shell命令

    Untitled Image

  • Trigger:代表一個(gè)構(gòu)建的觸發(fā)床绪,當(dāng)滿足一個(gè)什么樣的條件時(shí)觸發(fā)這個(gè)項(xiàng)目開(kāi)始構(gòu)建。比較常用的觸發(fā)就是當(dāng)代碼變更時(shí)觸發(fā),如果我們需要實(shí)現(xiàn)一些比較復(fù)雜的觸發(fā)邏輯癞己,就需要擴(kuò)展Trigger這個(gè)擴(kuò)展點(diǎn)

    Untitled Image

  • Publisher:Publisher代表一個(gè)項(xiàng)目構(gòu)建完成后需要執(zhí)行的步驟膀斋,如選項(xiàng)中的E-Mail Notifaction就是一個(gè)Publisher插件,選擇這個(gè)選項(xiàng)后痹雅,當(dāng)項(xiàng)目構(gòu)建完成仰担,就會(huì)使用email來(lái)通知用戶,假如想要在項(xiàng)目構(gòu)建完成后將構(gòu)建目標(biāo)產(chǎn)物發(fā)送到服務(wù)器上绩社,則可以擴(kuò)展此擴(kuò)展點(diǎn)摔蓝。

    Untitled Image

上面簡(jiǎn)單描述了一下插件和擴(kuò)展點(diǎn),接著我們可以搭建一個(gè)插件的開(kāi)發(fā)環(huán)境

插件開(kāi)發(fā)環(huán)境搭建

首先需要安裝:

  1. maven3
  2. jdk6+

安裝完成后愉耙,修改maven目錄下的settings.xml文件

  • linux : ~/.m2/settings.xml
  • windows : %USERPROFILE%\.m2\setttings.xml
<settings>
  <pluginGroups>
    <pluginGroup>org.jenkins-ci.tools</pluginGroup>
  </pluginGroups>

  <profiles>
    <!-- Give access to Jenkins plugins -->
    <profile>
      <id>jenkins</id>
      <activation>
        <activeByDefault>true</activeByDefault> <!-- change this to false, if you don't like to have it on per default -->
      </activation>
      <repositories>
        <repository>
          <id>repo.jenkins-ci.org</id>
          <url>https://repo.jenkins-ci.org/public/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>repo.jenkins-ci.org</id>
          <url>https://repo.jenkins-ci.org/public/</url>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>
  <mirrors>
    <mirror>
      <id>repo.jenkins-ci.org</id>
      <url>https://repo.jenkins-ci.org/public/</url>
      <mirrorOf>m.g.o-public</mirrorOf>
    </mirror>
  </mirrors>
</settings>

使用如下命令創(chuàng)建一個(gè)新的插件

mvn org.jenkins-ci.tools:maven-hpi-plugin:create (或者 mvn hpi:create)

需要輸入插件的groupId贮尉,artifactId, 然后會(huì)在當(dāng)前目錄創(chuàng)建一個(gè)jenkins插件的骨架目錄(熟悉maven的同學(xué)知道這個(gè)一個(gè)標(biāo)準(zhǔn)的maven項(xiàng)目目錄結(jié)構(gòu))

Untitled Image

插件目錄結(jié)構(gòu):

  • pom.xml: maven使用這個(gè)文件來(lái)構(gòu)建插件,所有的插件都是基于Plugin Parent Pom
<parent>
    <groupId>org.jenkins-ci.plugins</groupId>
    <artifactId>plugin</artifactId>
    <version>2.2</version>
</parent>
  • src/main/java:java源碼
  • src/main/resources:jelly視圖文件朴沿,用于在web界面上顯示
  • src/main/webapp: 靜態(tài)的資源文件猜谚,例如圖片和html文件

導(dǎo)入到IDE

  • intellij idea:直接在ide中導(dǎo)入pom文件就能導(dǎo)入
  • eclipse:運(yùn)行如下命令
 mvn -DdownloadSources=true -DdownloadJavadocs=true -DoutputDirectory=target/eclipse-classes -Declipse.workspace=/path/to/workspace eclipse:eclipse eclipse:configure-workspace

調(diào)試插件

  • linux
export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"
mvn hpi:run
  • windows
set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n
mvn hpi:run

輸入命令過(guò)后可以打開(kāi)瀏覽器,輸入:http://localhost:8080/jenkins,就可以看見(jiàn)你的插件在jenkins中運(yùn)行起來(lái)了赌渣,現(xiàn)在就可以開(kāi)始進(jìn)行調(diào)試了魏铅。

修改端口

mvn hpi:run -Djetty.port =8090

設(shè)置上下文路徑

mvn hpi:run -Dhpi.prefix=/jenkins

打包發(fā)布插件

mvn package

該命令會(huì)在target目錄創(chuàng)建出 ‘插件名稱’.hpi 文件,其他用戶可以直接將這個(gè)插件上傳安裝到Jenkins中使用(或者放到$JENKINS_HOME/plugins目錄中)坚芜。


Jenkins插件之HelloWorld

在之前我們使用mvn hpi:create創(chuàng)建插件目錄時(shí)览芳,Jenkins在我們的項(xiàng)目中生成了一個(gè)HelloWorldBuilder的插件,這是一個(gè)官方示例鸿竖,下面帶大家分析一下這個(gè)插件的示例源碼

public class HelloWorldBuilder extends Builder implements SimpleBuildStep {
    
}

首先創(chuàng)建一個(gè)類繼承于Builder路操,代表使用這個(gè)插件是一個(gè)構(gòu)建插件(如果繼承于Scm,代表這個(gè)插件是一個(gè)源碼插件千贯,例如Git屯仗,Svn插件),然后實(shí)現(xiàn)SimpleBuildStep接口

在Jenkins的插件中搔谴,每一個(gè)插件類中都必須要有一個(gè)Descriptor內(nèi)部靜態(tài)類魁袜,它代表一個(gè)類的’描述者‘,用于指明這是一個(gè)擴(kuò)展點(diǎn)的實(shí)現(xiàn)敦第,Jenkins是通過(guò)這個(gè)描述者才能知道我們自己寫(xiě)的插件
每一個(gè)‘描述者’靜態(tài)類都需要被@Extension注解峰弹,Jenkins內(nèi)部會(huì)掃描@Extenstion注解來(lái)知道注冊(cè)了有哪些插件。

    @Extension
    public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
   
        private boolean useFrench;
        
        public DescriptorImpl() {
            load();
        }
    
        public boolean isApplicable(Class<? extends AbstractProject> aClass) {
            return true;
        }

        public String getDisplayName() {
            return "Say hello world";
        }

        @Override
        public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
            save();
            return super.configure(req,formData);
        }
        
        public boolean getUseFrench() {
            return useFrench;
        }
    }

在Desciptor類中有兩個(gè)方法需要我們必須要進(jìn)行重寫(xiě)

public boolean isApplicable(){
     return true;
}

這個(gè)方法的返回值代表這個(gè)Builder在Project中是否可用芜果,我們可以將我們的邏輯寫(xiě)在其中鞠呈,例如判斷一些參數(shù),最后返回true或者false來(lái)決定這個(gè)Builder在此處是否可用

public String getDisplayName(){
    return "Say hello world";
}

這個(gè)方法返回的是一個(gè)String類型的值右钾,這個(gè)名稱會(huì)用在web界面上顯示的名稱


Untitled Image

如果我們?cè)诓寮行枰@取一些系統(tǒng)設(shè)置參數(shù)蚁吝,我們可以在Descriptor中獲取
一個(gè)參數(shù)對(duì)應(yīng)Descriptor中的一個(gè)屬性旱爆,其中的userFrench屬性是一個(gè)全局配置,可以在系統(tǒng)設(shè)置里面看到這個(gè)屬性


Untitled Image
private boolean useFrench;

public DescriptorImpl() {
     load();
}

在Descirptor構(gòu)造函數(shù)中使用load()進(jìn)行加載全局配置窘茁,然后我們就可以在插件中獲取到配置信息

 @Override
 public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
      useFrench = formData.getBoolean("useFrench");
      save();
      return super.configure(req,formData);
  }

當(dāng)在全局配置修改屬性后怀伦,需要在configure()方法中調(diào)用save()將全局配置信息持久化到xml,我們可以在workspace的插件名.xml中看到持久化的數(shù)據(jù)

Untitled Image

在每個(gè)插件的perform()方法中山林,是perform真正開(kāi)始執(zhí)行的地方房待,我們?nèi)绻诓寮型瓿墒裁词拢a邏輯也是寫(xiě)在perform方法中驼抹,perform方法參數(shù)中build代表當(dāng)前構(gòu)建桑孩,workspace代表當(dāng)前工作目錄,通過(guò)workspace可以獲取到當(dāng)前工作目錄的信息框冀,并可以做些操作流椒,如workspace.copyTo("/home"),launcher代表啟動(dòng)進(jìn)程左驾,可以通過(guò)launcher執(zhí)行一些命令镣隶,如launcher.launch().stdout(listener).cmds("pwd").start();,listener代表一個(gè)監(jiān)聽(tīng)器诡右,可以將運(yùn)行的內(nèi)容信息通過(guò)listener輸出到前臺(tái)console output安岂。

public class HelloWorldBuilder extends Builder implements SimpleBuildStep {
     @Override
     public void perform(Run<?,?> build, FilePath workspace, Launcher launcher, TaskListener listener) {
          //yuor code...
          listener.getLogger().println("Hello World" + name);
     }
 }

如上面的代碼所示,在perform方法中我們通過(guò)listener打印了一行”Hello World“ + name帆吻,name是一個(gè)變量域那,這個(gè)變量的值從哪里來(lái)下面我會(huì)介紹一下給大家。在web界面上的控制臺(tái)可以看見(jiàn) Hello World kinder猜煮,而kinder這個(gè)值是由我們自己定義的次员。


Untitled Image

在jenkins插件中,如果我們需要一些自定義的參數(shù)信息王带,如構(gòu)建時(shí)執(zhí)行一些命令淑蔚,命令的內(nèi)容是由用戶輸入,這個(gè)時(shí)候需要一個(gè)變量來(lái)記錄用戶輸入的信息
所以在HelloWorkdBuilder中定義一個(gè)屬性與用于輸入的信息相對(duì)應(yīng)愕撰,如上面的name屬性

public class HelloWorldBuilder extends Builder implements SimpleBuildStep {

    private final String name;
    
    ....
}
Untitled Image

這個(gè)屬性的值是在job的配置過(guò)程中輸入刹衫,由Jenkins從web前端界面?zhèn)鬟f過(guò)來(lái)的值,我們還需要在HelloWorldBuilder的構(gòu)造方法中進(jìn)行參數(shù)的注入

public class HelloWorldBuilder extends Builder implements SimpleBuildStep {

    private final String name;
    
    @DataBoundConstructor
    public HelloWorldBuilder(String name) {
        this.name = name;
}

類似于Spring的依賴注入搞挣,在這里Jenkins要求進(jìn)行參數(shù)注入的構(gòu)造方法需要用@DataBoundConstructor注解標(biāo)注带迟,以便Jenkins可以找到這個(gè)構(gòu)造函數(shù),并且調(diào)用這個(gè)構(gòu)造函數(shù)囱桨,將web界面上配置的參數(shù)傳遞進(jìn)HelloWorldBuilder仓犬,這樣就可以在HelloWorldBuilder中使用這個(gè)屬性了。

到此舍肠,這個(gè)插件的后臺(tái)代碼就已經(jīng)搞定了搀继,現(xiàn)在給大家講講怎么樣編寫(xiě)這個(gè)前端配置的視圖


Untitled Image

窘面。

Jenkins中的視圖

Jenkins 使用jelly來(lái)編寫(xiě)視圖,Jelly 是一種基于 Java 技術(shù)和 XML 的腳本編制和處理引擎律歼。Jelly 的特點(diǎn)是有許多基于 JSTL (JSP 標(biāo)準(zhǔn)標(biāo)記庫(kù)民镜,JSP Standard Tag Library)啡专、Ant险毁、Velocity 及其它眾多工具的可執(zhí)行標(biāo)記。Jelly 還支持 Jexl(Java 表達(dá)式語(yǔ)言们童,Java Expression Language)畔况,Jexl 是 JSTL 表達(dá)式語(yǔ)言的擴(kuò)展版本。Jenkins的界面繪制就是通過(guò)Jelly實(shí)現(xiàn)的

在Jenkins 中的視圖的類型有三種

  • global.jelly 全局的配置視圖
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
  <f:section title="Hello World Builder">
    <f:entry title="French" field="useFrench"
      description="Check if we should say hello in French">
      <f:checkbox />
    </f:entry>
  </f:section>
</j:jelly>
Untitled Image
  • config.jelly Job的配置視圖
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
  <f:entry title="Name" field="name">
    <f:textbox />
  </f:entry>
</j:jelly>

Untitled Image

在定義一個(gè)屬性時(shí)慧库,使用<f:entry>標(biāo)簽代表這是一個(gè)屬性跷跪,其中title是指在界面上顯示的字段名,而field是指這個(gè)屬性在HelloWorldBuilder中對(duì)應(yīng)的屬性名齐板,jenkins通過(guò)這個(gè)名稱來(lái)與HelloWorldBuilder中的屬性相對(duì)應(yīng)吵瞻,從而使用@DataBoundConstructor標(biāo)注的構(gòu)造函數(shù)將這些變量注入到HelloWorldBuilder類中。

  • help-屬性名.html 幫助視圖 html片段
<div>
  Help file for fields are discovered through a file name convention. This file is
  help for the "name" field. You can have <i>arbitrary</i> HTML here. You can write
  this file as a Jelly script if you need a dynamic content (but if you do so, change
  the extension to <tt>.jelly</tt>).
</div>

Untitled Image

這是Jenkins 中的三種視圖甘磨,上面也介紹了兩個(gè)簡(jiǎn)單的控件textbox和checkbox的使用橡羞,更多的關(guān)于Jelly的視圖使用可以查看jelly官網(wǎng)

Jenkins 數(shù)據(jù)持久化

我們之前在web界面上輸入了name济舆,這個(gè)信息在下一次構(gòu)建的時(shí)候仍然存在卿泽,說(shuō)明jenkins中需要使用數(shù)據(jù)持久化來(lái)將我們配置的信息保存下來(lái),而Jenkins 使用文件來(lái)存儲(chǔ)數(shù)據(jù)(所有數(shù)據(jù)都存儲(chǔ)在$JENKINS_HOME)滋觉,有些數(shù)據(jù)签夭,比如 console 輸出,會(huì)作為文本文件存儲(chǔ)椎侠;大多數(shù)的結(jié)構(gòu)數(shù)據(jù)第租,如一個(gè)項(xiàng)目的配置或構(gòu)建(build)記錄信息則會(huì)通過(guò) XStream 持久化為一個(gè)xml文件,如下圖所示


Untitled Image

而在需要信息的時(shí)候,jenkins又從xml文件中讀取到相應(yīng)的數(shù)據(jù)我纪,返回給應(yīng)用程序慎宾。


總結(jié)

在本文,主要介紹了Jenkins的簡(jiǎn)單使用宣羊,以及Jenkins的插件開(kāi)發(fā)環(huán)境璧诵,以及Jenkins插件結(jié)構(gòu)的一些介紹。本文主要還是做一個(gè)簡(jiǎn)單入門(mén)介紹仇冯,如果想要了解更多的關(guān)于Jenkins的東西之宿,還是需要去看Jenkins的官方wiki, 上面有詳細(xì)的關(guān)于每個(gè)擴(kuò)展點(diǎn)已經(jīng)Jenkins的api的使用介紹苛坚,同樣比被,你也可以下載Jenkins的源碼來(lái)查看內(nèi)部的一些實(shí)現(xiàn)方式色难。
Github Jenkinci也有很多的關(guān)于Jenkins插件的源碼,我們可以通過(guò)源碼了解一些擴(kuò)展點(diǎn)是怎樣使用等缀,參照別人的源碼來(lái)寫(xiě)出自己的插件枷莉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市尺迂,隨后出現(xiàn)的幾起案子笤妙,更是在濱河造成了極大的恐慌,老刑警劉巖噪裕,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹲盘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡膳音,警方通過(guò)查閱死者的電腦和手機(jī)召衔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)祭陷,“玉大人苍凛,你說(shuō)我怎么就攤上這事”荆” “怎么了醇蝴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)毒姨。 經(jīng)常有香客問(wèn)我哑蔫,道長(zhǎng),這世上最難降的妖魔是什么弧呐? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任闸迷,我火速辦了婚禮,結(jié)果婚禮上俘枫,老公的妹妹穿的比我還像新娘腥沽。我一直安慰自己,他們只是感情好鸠蚪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布今阳。 她就那樣靜靜地躺著,像睡著了一般茅信。 火紅的嫁衣襯著肌膚如雪盾舌。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天蘸鲸,我揣著相機(jī)與錄音妖谴,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛膝舅,可吹牛的內(nèi)容都是我干的嗡载。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼仍稀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼洼滚!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起技潘,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤遥巴,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后崭篡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體挪哄,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吧秕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年琉闪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砸彬。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颠毙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出砂碉,到底是詐尸還是另有隱情蛀蜜,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布增蹭,位于F島的核電站滴某,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏滋迈。R本人自食惡果不足惜霎奢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饼灿。 院中可真熱鬧幕侠,春花似錦、人聲如沸碍彭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)庇忌。三九已至舞箍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間皆疹,已是汗流浹背疏橄。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墙基,地道東北人软族。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓刷喜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親立砸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掖疮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 軟件的持續(xù)集成工具之一,易上手颗祝,功能強(qiáng)大浊闪,話不多說(shuō),干貨奉上螺戳。我的博客地址:http://blog.lzoro.c...
    格子Lin閱讀 12,222評(píng)論 10 41
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理搁宾,服務(wù)發(fā)現(xiàn),斷路器倔幼,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,071評(píng)論 25 707
  • Swift版本點(diǎn)擊這里歡迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh閱讀 25,365評(píng)論 7 249
  • 你是山外的山,你遮蔽的路遙遠(yuǎn)膏燃,車馬的夜里茂卦,不止馬夫的踽踽。你是水中的水组哩,你揉碎的月羞怯等龙,燈槳的吁里,不止銅雀的娓娓...
    白大癡閱讀 302評(píng)論 8 11