Tomcat的配置解析工具Apache Commons Digester

開篇

?最近開始看Tomcat的源碼,在catalina. createStartDigester方法中,Tomcat開發(fā)人員采用了Digester來(lái)讀取conf/server.xml文件,以前讀取xml文件一般采用Dom4j和SAX,因此對(duì)Digester比較陌生,順便就抽時(shí)間研究了一下Digester是如何解析xml文件的。

?先簡(jiǎn)單闡述下Dom4j和SAX解析XML的區(qū)別:

  • Dom4j是把一個(gè)xml文件全部讀取到內(nèi)存中,構(gòu)建成一個(gè)DOM樹來(lái)解析,所以Dom4j適合讀取比較小的xml文件。
  • SAX是基于文件流來(lái)解析xml文件的,在讀取xml文件流時(shí),SAX會(huì)通過(guò)節(jié)點(diǎn)來(lái)觸發(fā)相應(yīng)的操作,也可以說(shuō)SAX是基于文件流的事情觸發(fā)機(jī)制來(lái)解析xml文件的。
  • Digeter是apache的common項(xiàng)目,作用是將XML轉(zhuǎn)化成對(duì)象,使用者直接從對(duì)象中獲取xml的節(jié)點(diǎn)信息。Digester是對(duì)SAX的包裝,它也是基于文件流來(lái)解析xml文件,只不過(guò)這些解析操作對(duì)用戶是透明的。
  • Tomcat的配置文件conf/server.xml就是用Digester來(lái)讀取的。

?Digester的來(lái)源

  • Digester本來(lái)僅僅是Jakarta Struts中的一個(gè)工具,用于處理struts-config.xml配置文件。顯然,將XML文件轉(zhuǎn)換成相應(yīng)的Java對(duì)象是一項(xiàng)很通用的功能,這個(gè)工具理應(yīng)具有更廣泛的用途,所以很快它就在Jakarta Commons項(xiàng)目(用于提供可重用的Java組件庫(kù))中有了一席之地。

  • 如今Digester隨著Struts的發(fā)展以及其的公用性而被提到commons中獨(dú)自立項(xiàng),是apache的一個(gè)組件 apache commons-digester.jar,通過(guò)它可以很方便的從xml文件生成java對(duì)象。

?Digester工作原理:

  • Digester由"事件"驅(qū)動(dòng),通過(guò)調(diào)用預(yù)定義的規(guī)則操作對(duì)象棧,將XML文件轉(zhuǎn)換為Java對(duì)象。

  • Digester底層采用SAX解析XML文件,所以很自然的,對(duì)象轉(zhuǎn)換由"事件"驅(qū)動(dòng),即在識(shí)別出特定XML元素時(shí)(實(shí)際被細(xì)分為begin、body、end、finish四個(gè)時(shí)點(diǎn)),將執(zhí)行特定的動(dòng)作,比如創(chuàng)建特定的Java對(duì)象,或調(diào)用特定對(duì)象的方法等。此處的XML元素根據(jù)匹配模式(matching pattern)識(shí)別,而相關(guān)操作由規(guī)則(rule)定義。

  • 在轉(zhuǎn)換過(guò)程中,Digester維持了一個(gè)對(duì)象棧,可以看作對(duì)象轉(zhuǎn)換的工作臺(tái),用來(lái)存放轉(zhuǎn)換中生成的、或是為轉(zhuǎn)換臨時(shí)創(chuàng)建的Java對(duì)象。對(duì)輸入XML文件作了一趟完整的掃描后,對(duì)象棧的棧頂元素即為目標(biāo)對(duì)象。由于Digester屏蔽了SAX解析的細(xì)節(jié),使用者僅需關(guān)注轉(zhuǎn)換操作本身,大大簡(jiǎn)化了轉(zhuǎn)換操作。

?以下的內(nèi)容都是分享自文末參考文章的內(nèi)容,對(duì)于一些API的使用非常建議直接下載jar包看源碼注釋

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-digester3</artifactId>
            <version>3.2</version>
        </dependency>


使用Digester的基本步驟

  • 1、創(chuàng)建一個(gè) org.apache.commons.digester3.Digester 類的實(shí)例對(duì)象。這里補(bǔ)充說(shuō)明下,只要我們已經(jīng)完成XML解析操作,并且不在多個(gè)線程中使用同一個(gè)Digester對(duì)象,那么就可以安全的重復(fù)使用我們預(yù)先創(chuàng)建的這個(gè)Digester實(shí)例;不過(guò)重用Digester實(shí)例并不是非常推薦,最好每個(gè)XML解析對(duì)應(yīng)一個(gè)單獨(dú)的Digester實(shí)例;

  • 2、為Digester實(shí)例配置屬性值,通過(guò)配置屬性值,我們可以改變Digester 的解析行為,具體有哪些屬性值可以配置,待會(huì)會(huì)介紹;

  • 3、可選的, 可以將我們的一些初始對(duì)象push到Digester棧里;

  • 4、在輸入的XML文檔中,給所有需要觸發(fā)規(guī)則(rule)處理的元素匹配模式(pattern)注冊(cè)規(guī)則;針對(duì)任何一個(gè)模式,你可以注冊(cè)任意數(shù)量的規(guī)則;補(bǔ)充說(shuō)明下,如果一個(gè)模式對(duì)應(yīng)多個(gè)規(guī)則,則begin和body事件方法會(huì)按照它們注冊(cè)的順序依次執(zhí)行,而end事件方法是倒序執(zhí)行的;

  • 5、最后,調(diào)用digester.parse()方法,該方法需要傳入XML文件的引用作為參數(shù),該參數(shù)支持多種格式的文件流;另外需要注意的是,該方法會(huì)拋出IOException or SAXException異常,以及各種可能的在規(guī)則解析處理時(shí)遇到的異常,如NoSuchMethodException、IllegalAccessException…

?了解基本步驟后,來(lái)看一個(gè)簡(jiǎn)單的示例,如下所示,是我們即將要解析的xml文件:

<foo name="The Parent">
    <bar id="123" title="The First Child" />
    <bar id="456" title="The Second Child" />
    <bar id="789" title="The Second Child" />
</foo>

?首先,創(chuàng)建兩個(gè)java bean對(duì)應(yīng)xml中的元素信息:

?Foo類

package apache.commons.digester3.example.pojo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author http://www.cnblogs.com/chenpi/
 * @version 2017年6月3日
 */
public class Foo
{
    private String name;
    private List<Bar> barList = new ArrayList<Bar>();

    public void addBar(Bar bar)
    {
        barList.add(bar);
    }

    public Bar findBar(int id)
    {
        for (Bar bar : barList)
        {
            if (bar.getId() == id)
            {
                return bar;
            }
        }
        return null;
    }

    public Iterator<Bar> getBars()
    {
        return barList.iterator();
    }

    /**
     * @return the name
     */
    public String getName()
    {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name)
    {
        this.name = name;
    }

    /**
     * @return the barList
     */
    public List<Bar> getBarList()
    {
        return barList;
    }

    /**
     * @param barList the barList to set
     */
    public void setBarList(List<Bar> barList)
    {
        this.barList = barList;
    }
}

?Bar類

package apache.commons.digester3.example.pojo;

/**
 * @author    http://www.cnblogs.com/chenpi/
 * @version   2017年6月3日
 */
public class Bar
{

    private int id;
    private String title;

    /**
     * @return the id
     */
    public int getId()
    {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(int id)
    {
        this.id = id;
    }

    /**
     * @return the title
     */
    public String getTitle()
    {
        return title;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(String title)
    {
        this.title = title;
    }

}

?使用Digester解析xml:

package apache.commons.digester3.example.simpletest;

import java.io.IOException;

import org.apache.commons.digester3.Digester;
import org.xml.sax.SAXException;

import apache.commons.digester3.example.pojo.Bar;
import apache.commons.digester3.example.pojo.Foo;

/**
 * 
 * @author http://www.cnblogs.com/chenpi/
 * @version 2017年6月3日
 */

public class Main
{

    public static void main(String[] args)
    {

        try
        {
            //1、創(chuàng)建Digester對(duì)象實(shí)例
            Digester digester = new Digester();

            //2、配置屬性值
            digester.setValidating(false);

            //3、push對(duì)象到對(duì)象棧
            //digester.push(new Foo());
            
            //4、設(shè)置匹配模式、規(guī)則
            digester.addObjectCreate("foo", "apache.commons.digester3.example.pojo.Foo");
            digester.addSetProperties("foo");
            digester.addObjectCreate("foo/bar", "apache.commons.digester3.example.pojo.Bar");
            digester.addSetProperties("foo/bar");
            digester.addSetNext("foo/bar", "addBar", "apache.commons.digester3.example.pojo.Bar");

            //5、開始解析
            Foo foo = digester.parse(Main.class.getClassLoader().getResourceAsStream("example.xml"));

            //6、打印解析結(jié)果
            System.out.println(foo.getName());
            for (Bar bar : foo.getBarList())
            {
                System.out.println(bar.getId() + "," + bar.getTitle());
            }

        }
        catch (IOException e)
        {

            e.printStackTrace();
        }
        catch (SAXException e)
        {

            e.printStackTrace();
        }
    }
}

?結(jié)果打印:

The Parent
123,The First Child
456,The Second Child
789,The Second Child

?注意以上代碼涉及類型的自動(dòng)轉(zhuǎn)換,如id屬性,由字符串類型轉(zhuǎn)為整型,這里所有的類型轉(zhuǎn)換都是由commons-beanutils包的ConvertUtils來(lái)完成的。


Digester屬性配置

?org.apache.commons.digester3.Digester實(shí)例對(duì)象包含若干成員屬性,這些屬性值是可以設(shè)置的,以便我們自定義解析操作;

?為了讓這些配置在XML解析前生效,這些屬性值的更改一定要在parse方法調(diào)用之前設(shè)置;下面是一些可以配置的屬性:

?另外,我們可以通過(guò)Digester的register方法,讓Digester在遇到DOCTYPE聲明時(shí),使用本地dtd,而不是從網(wǎng)上獲取,如下所示:

URL url = new URL("/org/apache/struts/resources/struts-config_1_0.dtd");
digester.register("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN", url.toString());


Digester對(duì)象棧

?Digester使用的一個(gè)核心技術(shù)就是動(dòng)態(tài)構(gòu)建一顆java對(duì)象樹,在構(gòu)建的過(guò)程中,一個(gè)重要的輔助數(shù)據(jù)結(jié)構(gòu)即對(duì)象棧;

?以如下xml為例:

<foo name="The Parent">
    <bar id="123" title="The First Child" />
    <bar id="456" title="The Second Child" />
    <bar id="789" title="The Second Child" />
</foo>

?在解析的時(shí)候,首先會(huì)創(chuàng)建一個(gè)foo對(duì)象,并壓入對(duì)象棧,然后設(shè)置foo屬性值name,緊接著,創(chuàng)建bar對(duì)象并壓入棧,然后設(shè)置bar的屬性值,然后將該bar對(duì)象添加的到foo對(duì)象的barlist屬性集合中,然后bar對(duì)象彈出對(duì)象棧;

?以此類推,遇到起始標(biāo)記的元素創(chuàng)建對(duì)象入棧,遇到結(jié)尾標(biāo)記的元素做出棧操作,出棧前,需要將出棧對(duì)象并關(guān)聯(lián)到上一個(gè)棧頂對(duì)象;

?最終,解析完xml后,留在棧頂?shù)木完P(guān)聯(lián)了所有在xml解析中創(chuàng)建的動(dòng)態(tài)對(duì)象了;

?Digester暴露出的與對(duì)象棧操作API如下所示:

  • clear() - 清除對(duì)象棧.
  • peek() - 返回棧頂對(duì)象引用,但是不彈出.
  • pop() - 返回棧頂對(duì)象,并彈出.
  • push() - 入棧操作.


Digester元素匹配模式

?Digester的一個(gè)關(guān)鍵特性是可以自動(dòng)識(shí)別xml的層次結(jié)構(gòu),程序員只需要關(guān)心遇到匹配到某個(gè)元素后需要做哪些操作即可;

?如下是一個(gè)示例,其中a, a/b, a/b/c為匹配模式,對(duì)應(yīng)xml中特定位置的元素:

<a>         -- Matches pattern "a"
    <b>       -- Matches pattern "a/b"
      <c/>    -- Matches pattern "a/b/c"
      <c/>    -- Matches pattern "a/b/c"
    </b>
    <b>       -- Matches pattern "a/b"
      <c/>    -- Matches pattern "a/b/c"
      <c/>    -- Matches pattern "a/b/c"
      <c/>    -- Matches pattern "a/b/c"
    </b>
  </a>


Digester規(guī)則處理

?當(dāng)匹配到模式時(shí),會(huì)觸發(fā)規(guī)則處理,具體的規(guī)則處理機(jī)制是由這個(gè)org.apache.commons.digester3.Rule接口封裝的,該接口定義了以下幾個(gè)方法:

  • begin() - 匹配到xml元素開始標(biāo)記時(shí),調(diào)用該方法;
  • body() - 匹配到xml元素body時(shí),調(diào)用該方法;
  • end() - 匹配到xml元素結(jié)束標(biāo)記時(shí),調(diào)用該方法;
  • finish() - 當(dāng)所有解析方法解析完畢后,調(diào)用該方法,用于清楚臨時(shí)數(shù)據(jù)等;

?默認(rèn)情況下,Digester提供了以下Rule接口的實(shí)現(xiàn)類,我們?cè)诰幋a的時(shí)候可以直接使用,詳見API文檔:

?如下是一個(gè)SetNextRule規(guī)則實(shí)現(xiàn)類的示例(兩種寫法):

Rule rule = new SetNextRule("addBar",Bar.class);
digester.addRule("foo/bar", rule );

//digester.addSetNext("foo/bar", "addBar", Bar.class.getName());


Digester日志

?日志是調(diào)試、排查錯(cuò)誤非常關(guān)鍵的一個(gè)環(huán)節(jié),Digester記錄了非常詳細(xì)的日志,我們可以按如下方式來(lái)開啟日志打印功能,這里的日志實(shí)現(xiàn)選擇log4j。

  • 1、首先,在pom.xml加上如下依賴:
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
  • 2、然后,編寫一個(gè)配置文件log4j.properties放到resources路徑下:
### set log levels ###
log4j.rootLogger = debug, stdout

### \u8F93\u51FA\u5230\u63A7\u5236\u53F0 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
  • 3、運(yùn)行程序,發(fā)現(xiàn)已經(jīng)可以看到DEBUG調(diào)試日志了日志:
2017-06-04 18:26:33  [ main:51 ] - [ DEBUG ]    Fire body() for SetPropertiesRule[aliases={}, ignoreMissingProperty=true]
2017-06-04 18:26:33  [ main:51 ] - [ DEBUG ]    Popping body text ''
2017-06-04 18:26:33  [ main:51 ] - [ DEBUG ]    Fire end() for SetPropertiesRule[aliases={}, ignoreMissingProperty=true]
2017-06-04 18:26:33  [ main:52 ] - [ DEBUG ]    Fire end() for ObjectCreateRule[className=apache.commons.digester3.example.pojo.Foo, attributeName=null]
2017-06-04 18:26:33  [ main:52 ] - [ DEBUG ]  [ObjectCreateRule]{foo} Pop 'apache.commons.digester3.example.pojo.Foo'
2017-06-04 18:26:33  [ main:52 ] - [ DEBUG ]  endDocument()
The Parent
123,The First Child
456,The Second Child
789,The Second Child


Digester例子

?前面我們已經(jīng)舉了一個(gè)Digester的簡(jiǎn)單使用例子,這里將繼續(xù)展示幾個(gè)示例,解析xml元素body值。
?如下XML文檔就是我們要解析內(nèi)容:

<web-app>
    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
            <init-param>
                <param-name>application</param-name>
                <param-value>org.apache.struts.example.ApplicationResources</param-value>
            </init-param>
            <init-param>
                <param-name>config</param-name>
                <param-value>/WEB-INF/struts-config.xml</param-value>
            </init-param>
    </servlet>
</web-app>
  • 1、首先,定義一個(gè)ServletBean,存儲(chǔ)以上xml信息,如下所示:
/*
 * File Name: ServletBean.java
 * Description: 
 * Author: http://www.cnblogs.com/chenpi/
 * Create Date: 2017年6月4日
 */
package apache.commons.digester3.example.pojo;

import java.util.HashMap;
import java.util.Map;

/**
 * 
 * @author    http://www.cnblogs.com/chenpi/
 * @version   2017年6月4日
 */

public class ServletBean
{

    private String servletName;
    private String servletClass;
    private Map<String, String> initParams = new HashMap<String, String>();
    
    
    public void addInitParam(String paramName, String paramValue){
        initParams.put(paramName, paramValue);
    }
    /**
     * @return the servletName
     */
    public String getServletName()
    {
        return servletName;
    }
    /**
     * @param servletName the servletName to set
     */
    public void setServletName(String servletName)
    {
        this.servletName = servletName;
    }
    /**
     * @return the servletClass
     */
    public String getServletClass()
    {
        return servletClass;
    }
    /**
     * @param servletClass the servletClass to set
     */
    public void setServletClass(String servletClass)
    {
        this.servletClass = servletClass;
    }
    /**
     * @return the initParams
     */
    public Map<String, String> getInitParams()
    {
        return initParams;
    }
    /**
     * @param initParams the initParams to set
     */
    public void setInitParams(Map<String, String> initParams)
    {
        this.initParams = initParams;
    }
}
  • 2、編寫規(guī)則解析xml,如下所示:
/*
 * File Name: Main2.java
 * Description: 
 * Author: http://www.cnblogs.com/chenpi/
 * Create Date: 2017年6月4日
 */
package apache.commons.digester3.example.simpletest;

import java.io.IOException;

import org.apache.commons.digester3.Digester;
import org.apache.commons.digester3.Rule;
import org.apache.commons.digester3.SetNextRule;
import org.xml.sax.SAXException;

import apache.commons.digester3.example.pojo.Bar;
import apache.commons.digester3.example.pojo.Foo;
import apache.commons.digester3.example.pojo.ServletBean;

/**
 * 
 * @author http://www.cnblogs.com/chenpi/
 * @version 2017年6月4日
 */

public class WebMain
{

    public static void main(String[] args)
    {
        try
        {
            // 1、創(chuàng)建Digester對(duì)象實(shí)例
            Digester digester = new Digester();

            // 2、配置屬性值
            digester.setValidating(false);

            // 3、push對(duì)象到對(duì)象棧

            // 4、設(shè)置匹配模式、規(guī)則
            digester.addObjectCreate("web-app/servlet", "apache.commons.digester3.example.pojo.ServletBean");
            digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0);
            digester.addCallMethod("web-app/servlet/servlet-class", "setServletClass", 0);
            digester.addCallMethod("web-app/servlet/init-param", "addInitParam", 2);
            digester.addCallParam("web-app/servlet/init-param/param-name", 0);
            digester.addCallParam("web-app/servlet/init-param/param-value", 1);

            // 5、開始解析
            ServletBean servletBean = digester
                .parse(ExampleMain.class.getClassLoader().getResourceAsStream("web.xml"));

            // 6、打印解析結(jié)果
            System.out.println(servletBean.getServletName());
            System.out.println(servletBean.getServletClass());
            for(String key : servletBean.getInitParams().keySet()){
                System.out.println(key + ": " + servletBean.getInitParams().get(key));
            }

        }
        catch (IOException e)
        {

            e.printStackTrace();
        }
        catch (SAXException e)
        {

            e.printStackTrace();
        }

    }
}
  • 3、結(jié)果打印:
action
org.apache.struts.action.ActionServlet
application: org.apache.struts.example.ApplicationResources
config: /WEB-INF/struts-config.xml


參考資料

http://commons.apache.org/proper/commons-digester/guide/core.html


示例代碼

https://github.com/peterchenhdu/apache-commons-digester-example


參考文章

Apache Commons Digester 一 (基礎(chǔ)內(nèi)容、核心API)
Apache Commons Digester 二(規(guī)則模塊綁定-RulesModule、異步解析-asyncParse、xml變量Substitutor、帶參構(gòu)造方法)
Apache Commons Digester 三(規(guī)則注解)
tomcat源碼解析(三)——Digester類源碼解析及Rule分析
tomcat源碼解讀一 Digester的解析方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評(píng)論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,786評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,438評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,796評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,995評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,230評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,697評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374

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

  • “千載古柏樹,百年尊經(jīng)閣”,書臺(tái)文宗子昂在,盛世金中譜新篇。金華中學(xué)承歷史之厚蘊(yùn),擔(dān)社會(huì)之重任,跟時(shí)代之...
    遠(yuǎn)方山谷里的思念閱讀 783評(píng)論 0 5
  • 《只想告訴你》 有了春天,才會(huì)有春花 有了夏天,才會(huì)有夏韻 有了秋天,才會(huì)有秋意 有了冬天,才會(huì)有孕育 飽食終日,...
    喜璞兒閱讀 171評(píng)論 0 1
  • 優(yōu)秀作家的作品都有共同的特點(diǎn):一是對(duì)于事物的細(xì)節(jié)描寫細(xì)膩且傳神,二是用了很多比喻的方法幫助讀者建立畫面感。 一月前...
    承謙閱讀 979評(píng)論 0 0