JavaWeb--Servlet

一喷屋、基本概念

Servlet是運(yùn)行在Web服務(wù)器上的小程序琳拨,通過(guò)http協(xié)議和客戶(hù)端進(jìn)行交互。
這里的客戶(hù)端一般為瀏覽器屯曹,發(fā)送http請(qǐng)求(request)給服務(wù)器(如Tomcat)狱庇。服務(wù)器接收到請(qǐng)求后選擇相應(yīng)的Servlet進(jìn)行處理,并給出響應(yīng)(response)恶耽。

servlet

從這里可以看出Servlet并不是獨(dú)立運(yùn)行的程序密任,而是以服務(wù)器為宿主,由服務(wù)器進(jìn)行調(diào)度的偷俭。通常我們把能夠運(yùn)行Servlet的服務(wù)器稱(chēng)作Servlet容器浪讳,如Tomcat。

這里Tomcat為什么能夠根據(jù)客戶(hù)端的請(qǐng)求去選擇相應(yīng)的Servlet去執(zhí)行的呢涌萤?答案是:Servlet規(guī)范淹遵。因?yàn)镾ervlet和Servlet容器都是遵照Servlet規(guī)范去開(kāi)發(fā)的口猜。簡(jiǎn)單點(diǎn)說(shuō):我們要寫(xiě)一個(gè)Servlet,就需要直接或間接實(shí)現(xiàn)javax.servlet.Servlet透揣。并且在web.xml中進(jìn)行相應(yīng)的配置济炎。Tomcat在接收到客戶(hù)端的請(qǐng)求時(shí),會(huì)根據(jù)web.xml里面的配置去加載辐真、初始化對(duì)應(yīng)的Servlet實(shí)例须尚。這個(gè)就是規(guī)范,就是雙方約定好的侍咱。

二耐床、樣例分析

在進(jìn)一步解釋Servlet原理、分析源碼之前楔脯,我們先介紹下如何在JavaWeb中使用Servlet撩轰。方法很簡(jiǎn)單:1.編寫(xiě)自己的Servlet類(lèi),這里可以使用開(kāi)發(fā)工具(STS淤年、Myeclipse等)根據(jù)向?qū)Э焖俚纳梢粋€(gè)Servlet類(lèi)钧敞。2.在web.xml中配置servlet蜡豹。這里的知識(shí)很簡(jiǎn)單麸粮,所以不做過(guò)多贅述。直接上代碼镜廉。(這里需要注意的是弄诲,servlet3.0之后提供了注解WebServlet的方式配置servlet,這里就不做介紹了娇唯,感興趣的可以自行去百度齐遵,只是配置的形式不同而已,沒(méi)有本質(zhì)區(qū)別塔插。所以下文還是為web.xml為例)
TestServlet.java

public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public TestServlet() {
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

web.xml

<servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>com.nantang.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/test</url-pattern>
</servlet-mapping>

啟動(dòng)Tomcat梗摇,瀏覽器訪(fǎng)問(wèn)/test。將會(huì)訪(fǎng)問(wèn)TestServlet想许。返回客戶(hù)端請(qǐng)求的上下文路徑伶授。

測(cè)試結(jié)果

這里需要擴(kuò)展的有幾點(diǎn):
1.如果一個(gè)servlet需要映射多個(gè)url-pattern,那么就在<servlet-mapping></servlet-mapping>標(biāo)簽下寫(xiě)多個(gè)<url-pattern></url-pattern>流纹,如:

<servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/test1</url-pattern>
    <url-pattern>/test2</url-pattern>
</servlet-mapping>

2.對(duì)于不同的servlet糜烹,不允許出現(xiàn)相同的url-pattern。
3.如果不同的servlet漱凝,它們的url-patter存在包含關(guān)系疮蹦,那么容器會(huì)調(diào)用更具象的servlet去處理客戶(hù)端請(qǐng)求。比如有兩個(gè)servlet茸炒,servlet1的url-pattern是"/"愕乎,servlet2的url-pattern是"/test"阵苇。那么這個(gè)時(shí)候如果客戶(hù)端調(diào)用的url是http://localhost:8080/demo/test,容器會(huì)使用servlet2去處理客戶(hù)端的請(qǐng)求感论。雖然說(shuō)"/"和"/test"都匹配客戶(hù)請(qǐng)求的url慎玖,但是容器會(huì)選擇更貼切的。這里不會(huì)出現(xiàn)多個(gè)servlet處理同一個(gè)請(qǐng)求的現(xiàn)象笛粘。

三趁怔、源碼分析

上面說(shuō)過(guò),我們自己編寫(xiě)的Servlet類(lèi)都必須直接或間接實(shí)現(xiàn)javax.servlet.Servlet薪前∽∈茫可是上面的例子TestServlet繼承的是HttpServlet,那是因?yàn)镠ttpServlet間接的實(shí)現(xiàn)了javax.servlet.Servlet炭菌。下面是HttpServlet的繼承層級(jí)(類(lèi)圖中的方法并沒(méi)有一一列舉为严,因?yàn)橄旅鏁?huì)逐一解釋?zhuān)?/p>

Servlet源碼

下面我們由上往下層層分析:

1 ServletContext

一個(gè)web應(yīng)用對(duì)應(yīng)一個(gè)ServletContext實(shí)例,關(guān)于ServletContext的詳細(xì)介紹垛膝,可以參考另一篇博文ServletContext鳍侣。

2.ServletConfig

ServletConfig實(shí)例是由servlet容器構(gòu)造的,當(dāng)需要初始化servlet的時(shí)候吼拥,容器根據(jù)web.xml中的配置以及運(yùn)行時(shí)環(huán)境構(gòu)造出ServletConfig實(shí)例倚聚,并通過(guò)回調(diào)servlet的init方法傳遞給servlet(這個(gè)方法后面會(huì)講到)。所以一個(gè)servlet實(shí)例對(duì)應(yīng)一個(gè)ServletConfig實(shí)例凿可。

Servlet和ServletContext的關(guān)系
public interface ServletConfig {

    public String getServletName();

    public ServletContext getServletContext();

    public String getInitParameter(String name);

    public Enumeration getInitParameterNames();
}

2.1 getServletName

getServletName方法返回servlet實(shí)例的名稱(chēng)惑折,這個(gè)就是我們?cè)趙eb.xml中<servlet-name>標(biāo)簽中配置的名字,當(dāng)然也可以在服務(wù)器控制臺(tái)去配置枯跑。如果這兩個(gè)地方都沒(méi)有配置servlet名稱(chēng)惨驶,那么將會(huì)返回servlet的類(lèi)名。

2.2 getServletContext

getServletContext方法返回ServletContext實(shí)例敛助,也就是我們上面說(shuō)的應(yīng)用上下文粗卜。

2.3 getInitParameter和getInitParameterNames

這兩個(gè)方法是用來(lái)獲取servlet的初始化參數(shù)的,這個(gè)參數(shù)是在web.xml里面配置的(如下所示)纳击。getInitParameter是根據(jù)參數(shù)名獲取參數(shù)值续扔,getInitParameterNames獲取參數(shù)名集合。

這里需要注意的是當(dāng)需要配置多個(gè)初始化參數(shù)時(shí)评疗,應(yīng)該寫(xiě)多個(gè)<init-param></init-param>對(duì)测砂,而不是在一個(gè)<init-param></init-param>對(duì)里面寫(xiě)多個(gè)<param-name></param-name>和<param-value></param-value>對(duì)。

<servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>com.nantang.servlet.TestServlet</servlet-class>
    <init-param>
        <param-name>a</param-name>
        <param-value>1</param-value>
    </init-param>
    <init-param>
        <param-name>b</param-name>
        <param-value>2</param-value>
    </init-param>
</servlet>

3 Servlet

最原始最簡(jiǎn)單的JaveWeb模型百匆,就是一個(gè)servlet容器上運(yùn)行著若干個(gè)servlet用來(lái)處理客戶(hù)端的請(qǐng)求砌些。所以說(shuō)servlet是JavaWeb最核心的東西,我們的業(yè)務(wù)邏輯基本上都是通過(guò)servlet實(shí)現(xiàn)的(雖然現(xiàn)在有各種框架,不用去直接編寫(xiě)servlet存璃,但本質(zhì)上還是在使用servlet)仑荐。

public interface Servlet {
    
    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    public String getServletInfo();

    public void destroy();
}

所有的servlet都是javax.servlet.Servlet的子類(lèi),就像Java里面所有的類(lèi)都是Object的子類(lèi)一樣纵东。Servlet類(lèi)規(guī)定了每個(gè)servlet應(yīng)該實(shí)現(xiàn)的方法粘招,這個(gè)是遵循Servlet規(guī)范的。但是自定義的servlet一般不用直接實(shí)現(xiàn)Servlet偎球,而是繼承javax.servlet.GenericServlet或者javax.servlet.http.HttpServlet就行了洒扎。我們上面的TestServlet就是繼承HttpServlet,這是因?yàn)镠ttpServlet間接實(shí)現(xiàn)了Servlet衰絮,提供了通用的功能袍冷。所以我們?cè)谧远x的TestServlet里面只需要專(zhuān)注實(shí)現(xiàn)業(yè)務(wù)邏輯就行了。

Servlet里面有三個(gè)比較重要的方法:init猫牡、service胡诗、destroy。它們被稱(chēng)作是servlet生命周期的方法淌友,它們都是由servlet容器調(diào)用煌恢。另外兩個(gè)方法用于獲取servlet相關(guān)信息的,需要根據(jù)業(yè)務(wù)邏輯進(jìn)行實(shí)現(xiàn)和調(diào)用震庭。

servlet生命周期

3.1 init

init方法是servlet的初始化方法瑰抵,當(dāng)客戶(hù)端第一次請(qǐng)求servlet的時(shí)候,JVM對(duì)servlet類(lèi)進(jìn)行加載和實(shí)例化归薛。(如果需要容器啟動(dòng)時(shí)就初始化servlet谍憔,可以在web.xml配置<load-on-startup>1</load-on-startup>)

這里需要注意的是,servlet會(huì)先執(zhí)行默認(rèn)的構(gòu)造函數(shù)主籍,然后回調(diào)servlet實(shí)例的init方法,傳入ServletConfig參數(shù)逛球。這個(gè)參數(shù)上面說(shuō)過(guò)千元,是servlet容器根據(jù)web.xml中的配置和運(yùn)行時(shí)環(huán)境構(gòu)造的實(shí)例。通過(guò)init方法注入到servlet颤绕。init方法在servlet的生命周期中只會(huì)被調(diào)用一次幸海,在客戶(hù)端的后續(xù)請(qǐng)求中將不會(huì)再調(diào)用。

3.2 service

service方法是處理業(yè)務(wù)邏輯的核心方法奥务。當(dāng)servlet容器接收到客戶(hù)端的請(qǐng)求后物独,會(huì)根據(jù)web.xml中配置的<url-pattern>找到相應(yīng)的servlet,回調(diào)service方法處理客戶(hù)端的請(qǐng)求并給出響應(yīng)氯葬。

3.3 destroy

JDK文檔解釋這個(gè)方法說(shuō):這個(gè)方法會(huì)在所有的線(xiàn)程的service()方法執(zhí)行完成或者超時(shí)后執(zhí)行挡篓。這里只是說(shuō)明了,當(dāng)servlet容器要去調(diào)用destroy方式的時(shí)候,需要等待一會(huì)官研,等待所有線(xiàn)程都執(zhí)行完或者達(dá)到超時(shí)的限制秽澳。

這里并沒(méi)有說(shuō)清楚什么情況下servlet容器會(huì)觸發(fā)這個(gè)動(dòng)作。How Tomcat Works一書(shū)中對(duì)這個(gè)做了解釋?zhuān)寒?dāng)servlet容器關(guān)閉或需要更多內(nèi)存的時(shí)候戏羽,會(huì)銷(xiāo)毀servlet担神。這個(gè)方法就使得servlet容器擁有回收資源的能力。

同樣地始花,destroy方法在servlet的生命周期中只會(huì)被調(diào)用一次妄讯。

3.4 getServletConfig

這個(gè)方法返回ServletConfig實(shí)例,這個(gè)對(duì)象即為servlet容器回調(diào)init方法的時(shí)候傳入的實(shí)例酷宵。所以自定義的Servlet一般的實(shí)現(xiàn)方式為:在init方法里面把傳入的ServletConfig存儲(chǔ)到servlet的屬性字段捞挥。在getServletConfig的實(shí)現(xiàn)里返回該實(shí)例。這個(gè)在后續(xù)解釋javax.servlet.GenericServlet的源碼時(shí)忧吟,能夠看到砌函。

3.5 getServletInfo

返回關(guān)于servlet的信息,這個(gè)由自定義的servlet自行實(shí)現(xiàn)溜族,不過(guò)一般建議返回servlet的作者讹俊、版本號(hào)、版權(quán)等信息煌抒。

4.GenericServlet

GenericServlet從名字就能看的出來(lái)是servlet的一般實(shí)現(xiàn)仍劈,實(shí)現(xiàn)了servlet具有的通用功能,所以我們自定義的servlet一般不需要直接實(shí)現(xiàn)Servlet接口寡壮,只需要集成GenericServlet贩疙。GenericServlet實(shí)現(xiàn)了Servlet和ServletConfig接口。

4.1 GenericServlet對(duì)Servlet接口的實(shí)現(xiàn)

private transient ServletConfig config;

public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
}

public void init() throws ServletException {}

public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

public void destroy() {}

public ServletConfig getServletConfig() {
    return config;
}

public String getServletInfo() {
    return "";
}

可以說(shuō)况既,GenericServlet對(duì)Servlet方法的實(shí)現(xiàn)邏輯非常簡(jiǎn)單这溅。就是把一些必要的邏輯寫(xiě)了下。

1.init方法就是把容器傳入的ServletConfig實(shí)力存儲(chǔ)在類(lèi)的私有屬性conifg里面棒仍,然后調(diào)用一個(gè)init無(wú)參的空方法悲靴。這么做的意義在于,我們?nèi)绻朐谧远x的servlet類(lèi)里面在初始化的時(shí)候添加些業(yè)務(wù)邏輯莫其,只需要重寫(xiě)無(wú)參的init方法就好了癞尚,我們不需要關(guān)注ServletConfig實(shí)例的存儲(chǔ)細(xì)節(jié)了。

2.service和destroy方法并未實(shí)現(xiàn)具體邏輯乱陡。

3.getServletConfig就是返回init方法里面存儲(chǔ)的config浇揩。getServletInfo就是返回空字符串,如果有業(yè)務(wù)需要憨颠,可以在子類(lèi)里面重寫(xiě)胳徽。

4.2 GenericServlet對(duì)于ServletConfig接口的實(shí)現(xiàn)

public String getServletName() {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
        throw new IllegalStateException(
            lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getServletName();
}

public ServletContext getServletContext() {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
        throw new IllegalStateException(
            lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getServletContext();
}

public String getInitParameter(String name) {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
        throw new IllegalStateException(
            lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getInitParameter(name);
}

public Enumeration getInitParameterNames() {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
        throw new IllegalStateException(
            lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getInitParameterNames();
}

這四個(gè)方法的實(shí)現(xiàn)就跟一個(gè)模子刻出來(lái)的一樣,都是取得ServletConfig實(shí)例,然后調(diào)用相應(yīng)的方法膜廊。其實(shí)GenericServlet完全沒(méi)有必要實(shí)現(xiàn)ServletConfig乏沸,這么做僅僅是為了方便。當(dāng)我們集成GenericServlet寫(xiě)自己的servlet的時(shí)候爪瓜,如果需要獲取servlet的配置信息如初始化參數(shù)蹬跃,就不需要寫(xiě)形如:“ServletConfig sc = getServletConfig();if (sc == null) ...;return sc.getInitParameterNames();”這些冗余代碼了。除此之外铆铆,沒(méi)有別的意義蝶缀。

5 HttpServlet

HttpServlet是一個(gè)針對(duì)HTTP協(xié)議的通用實(shí)現(xiàn),它實(shí)現(xiàn)了HTTP協(xié)議中的基本方法get薄货、post等翁都,通過(guò)重寫(xiě)service方法實(shí)現(xiàn)方法的分派。

分派
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{
    HttpServletRequest    request;
    HttpServletResponse    response;
    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException("non-HTTP request or response");
    }
    service(request, response);
}

重寫(xiě)的service方法將參數(shù)轉(zhuǎn)換成HttpServletRequest和HttpServletResponse谅猾,并調(diào)用自己的另一個(gè)重載service方法柄慰。

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    String method = req.getMethod();
    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            doGet(req, resp);
        } else {
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }
    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);
    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);        
    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);            
    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);        
    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);        
    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);        
    } else {
        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);        
        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

這個(gè)方法的的邏輯也很簡(jiǎn)單,就是解析出客戶(hù)端的request是哪種中方法税娜,如果是get方法則調(diào)用doGet坐搔,如果是post則調(diào)用doPost等等。這樣我們?cè)诶^承HttpServlet的時(shí)候就無(wú)需重寫(xiě)service方法敬矩,我們可以根據(jù)自己的業(yè)務(wù)重寫(xiě)相應(yīng)的方法概行。一般情況下我們的應(yīng)用基本就是get和post調(diào)用。那么我們只需要重寫(xiě)doGet和doPost就行了弧岳。

這里需要注意的是3-15行代碼凳忙,這里對(duì)資源(比如頁(yè)面)的修改時(shí)間進(jìn)行驗(yàn)證,判斷客戶(hù)端是否是第一次請(qǐng)求該資源禽炬,或者該資源是否被修改過(guò)涧卵。如果這兩個(gè)條件有一個(gè)被滿(mǎn)足那么就調(diào)用doGet方法。否則返回狀態(tài)304(HttpServletResponse.SC_NOT_MODIFIED)瞎抛,這個(gè)狀態(tài)就是告訴客戶(hù)端(瀏覽器)艺演,可以只用自己上一次對(duì)該資源的緩存。

不過(guò)HttpServlet對(duì)于判斷資源修改時(shí)間的邏輯非常簡(jiǎn)單粗暴:

protected long getLastModified(HttpServletRequest req) {
    return -1;
}

方法始終返回-1桐臊,這樣就會(huì)導(dǎo)致每次都會(huì)調(diào)用doGet方法從服務(wù)器取資源而不會(huì)使用瀏覽器的本地緩存。所以如果我們自己的servlet要使用瀏覽器的緩存晓殊,降低服務(wù)器的壓力断凶,就需要重寫(xiě)getLastModified方法。

最后我們來(lái)看一下HttpServlet對(duì)http一些方法的實(shí)現(xiàn)巫俺,在所有的方法中认烁,HttpServlet已經(jīng)對(duì)doOptions和doTrace方法實(shí)現(xiàn)了通用的邏輯,所以我們一般不用重寫(xiě)這兩個(gè)方法,感興趣的可以自己去看下源碼却嗡。

這里我們列舉下最常用的兩個(gè)方法doGet和doPost:

protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_get_not_supported");
    if (protocol.endsWith("1.1")) {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
}
    
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_post_not_supported");
    if (protocol.endsWith("1.1")) {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
}

其實(shí)這兩個(gè)實(shí)現(xiàn)里面也沒(méi)做什么有用的邏輯舶沛,所以一般情況下都要重寫(xiě)這兩個(gè)方法,就像我們最初的TestServlet那樣窗价。doHead如庭、doPut、doDelete也是這樣的代碼模板撼港,所以如果有業(yè)務(wù)需要的話(huà)坪它,我們都要重寫(xiě)對(duì)應(yīng)的方法。

四帝牡、總結(jié)

講了這么多往毡,可以這么說(shuō):Servlet是JavaWeb里面最核心的組件。只有對(duì)它完全融會(huì)貫通靶溜,才能去進(jìn)一步去理解上層框架Struts开瞭、Spring等。

另外需要明確的是:一個(gè)Web應(yīng)用對(duì)應(yīng)一個(gè)ServletContext罩息,一個(gè)Servlet對(duì)應(yīng)一個(gè)ServletConfig嗤详。每個(gè)Servlet都是單例的,所以需要自己處理好并發(fā)的場(chǎng)景扣汪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末断楷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子崭别,更是在濱河造成了極大的恐慌冬筒,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茅主,死亡現(xiàn)場(chǎng)離奇詭異舞痰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诀姚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)响牛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人赫段,你說(shuō)我怎么就攤上這事呀打。” “怎么了糯笙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵贬丛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我给涕,道長(zhǎng)豺憔,這世上最難降的妖魔是什么额获? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮恭应,結(jié)果婚禮上抄邀,老公的妹妹穿的比我還像新娘。我一直安慰自己昼榛,他們只是感情好境肾,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著褒纲,像睡著了一般准夷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上莺掠,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天衫嵌,我揣著相機(jī)與錄音,去河邊找鬼彻秆。 笑死楔绞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的唇兑。 我是一名探鬼主播酒朵,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扎附!你這毒婦竟也來(lái)了蔫耽?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤留夜,失蹤者是張志新(化名)和其女友劉穎匙铡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體碍粥,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鳖眼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚼摩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钦讳。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖枕面,靈堂內(nèi)的尸體忽然破棺而出愿卒,到底是詐尸還是另有隱情,我是刑警寧澤潮秘,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布掘猿,位于F島的核電站,受9級(jí)特大地震影響唇跨,放射性物質(zhì)發(fā)生泄漏稠通。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一买猖、第九天 我趴在偏房一處隱蔽的房頂上張望改橘。 院中可真熱鬧,春花似錦玉控、人聲如沸飞主。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)碌识。三九已至,卻和暖如春虱而,著一層夾襖步出監(jiān)牢的瞬間筏餐,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工牡拇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留魁瞪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓惠呼,卻偏偏與公主長(zhǎng)得像导俘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剔蹋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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