理解Servlet

前言

這篇文章的出發(fā)點(diǎn)是為了整理Servlet相關(guān)知識(shí)點(diǎn),以免在相關(guān)概念混淆或分不清的時(shí)候到處查閱資料。

一梆造、什么是Servlet

  • ServletJavaWeb的三大組件(Servlet剥扣、FilterListener)中最重要的組件适滓,它屬于動(dòng)態(tài)資源敦迄。
  • Servlet的作用是處理請求,服務(wù)器會(huì)把接收到的請求交給Servlet來處理凭迹,在Servlet中通常需要:接收請求數(shù)據(jù)罚屋;處理請求;完成響應(yīng)嗅绸。
  • 每個(gè)Servlet都是唯一的脾猛,不同的Servlet處理不同的請求,用下圖說明:
Servlet是什么.png

說明:假如兩個(gè)瀏覽器同時(shí)發(fā)送a請求鱼鸠,并不會(huì)創(chuàng)建兩個(gè)相同的Servlet猛拴,這兩個(gè)請求使用同一Servlet實(shí)例:Servlet是線程不安全的

二蚀狰、Servlet生命周期

Servlet的生命周期要從Servlet接口來認(rèn)識(shí)愉昆,Servlet接口一共5個(gè)方法,其中前三個(gè)是生命周期方法:

(1) void init(ServletConfig)
(2) void service(ServletRequest,ServletResponse)
(3) void destory()
(4) ServletConfig getServletConfig()
(5) String getServletInfo()
出生:服務(wù)器創(chuàng)建Servlet
  • 當(dāng)Servlet第一次被請求時(shí)麻蹋,或服務(wù)器啟動(dòng)時(shí)跛溉,服務(wù)器會(huì)創(chuàng)建Servlet實(shí)例。
  • 默認(rèn)情況下扮授,服務(wù)器會(huì)在某個(gè)Servlet第一次收到請求時(shí)創(chuàng)建它芳室。也可以在web.xml中對Servlet進(jìn)行配置,使服務(wù)器啟動(dòng)時(shí)就創(chuàng)建Servlet刹勃。
(1)在<servlet>元素中配置<load-on-startup>元素可以讓服務(wù)器在啟動(dòng)時(shí)就創(chuàng)建該Servlet

(2)假如多個(gè)<servlet>元素都?xì)W配置了<load-on-startup>元素堪侯,那么就會(huì)按照數(shù)字大小順序來啟動(dòng),數(shù)字越小荔仁,啟動(dòng)越早伍宦!

(3)<load-on-startup>元素的值必須是大于等于0的整數(shù)芽死。

<servlet>
        <servlet-name>hello2</servlet-name>
        <servlet-class>cn.itcast.servlet.Hello2Servlet</servlet-class>
        <load-on-startup>1</load-on-startup>
</servlet>

服務(wù)器默認(rèn)是在servlet第一次被請求時(shí)創(chuàng)建Servlet實(shí)例,如果希望服務(wù)器啟動(dòng)時(shí)就創(chuàng)建Servlet實(shí)現(xiàn)需要在web.xml中配置雹拄。

  • 服務(wù)器只為一個(gè)類型的Servlet創(chuàng)建一個(gè)實(shí)例對象收奔,所以Servlet是單例的。
長大:服務(wù)器初始化Servlet
  • 當(dāng)服務(wù)器創(chuàng)建Servlet實(shí)例后會(huì)馬上調(diào)用Servlet的init(ServletConfig)方法滓玖,完成對Servlet的初始化坪哄;
  • init(ServletConfig)只會(huì)被調(diào)用一次
  • 服務(wù)器會(huì)在調(diào)用init()方法時(shí)傳遞ServletConfig參數(shù)

工作:服務(wù)器使用Servlet處理請求

  • 當(dāng)Servlet被請求時(shí),服務(wù)器會(huì)調(diào)用Servlet的service(ServletRequest,ServletResponse)方法势篡;
  • 該方法每處理一次請求翩肌,就會(huì)被調(diào)用一次,所以它可能會(huì)被調(diào)用N次禁悠;
  • 因?yàn)镾ervlet是單例的念祭,所以可能在同一時(shí)刻一個(gè)Servlet對象會(huì)被多個(gè)請求同時(shí)訪問,所以這可能出現(xiàn)線程安全問題碍侦;
  • Servlet不是線程安全的粱坤,這有助與提高效率,但不能讓Servlet具有狀態(tài)瓷产,以免多個(gè)線程爭搶數(shù)據(jù)站玄;

死亡:服務(wù)器銷毀Servlet

  • 服務(wù)器通常不會(huì)銷毀Servlet,通常只有在服務(wù)器關(guān)閉時(shí)才會(huì)銷毀Servlet濒旦;
  • 服務(wù)器會(huì)在銷毀Servlet之前調(diào)用Servlet的destory()方法
  • 可以在destory()方法中給出釋放Servlet占有的資源株旷,但通常Servlet是沒什么可要釋放的,所以該方法一般都是空的

三尔邓、實(shí)現(xiàn)Servlet的方式

1晾剖、實(shí)現(xiàn)Servlet有下面三種方式
  • 實(shí)現(xiàn)javax.servlet.Servlet接口;
  • 繼承javax.servlet.GenericServlet類梯嗽;

  • 繼承javax.servlet.http.HttpServlet類齿尽;(一般采用這種方式)

  • 三者關(guān)系為:GenericServletServlet接口的實(shí)現(xiàn)類;HttpServlet類是GenericServlet的子類灯节,它提供了對HTTP請求的特殊支持雕什。

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {......}

public abstract class HttpServlet extends GenericServlet {......}
2、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();
  • ServletConfig
    ServletConfig對象是由服務(wù)器創(chuàng)建的显晶,然后傳遞給Servletinit()方法,對應(yīng)web.xml文件中的<servlet>元素壹士。該對象的常用方法有如下幾個(gè):
String getServletName()
獲取Servlet在web.xml文件中的配置名稱磷雇,即<servlet-name>指定的名稱;

ServletContext getServletContext()
用來獲取ServletContext對象

String getInitParameter(String name)
用來獲取在web.xml中配置的初始化參數(shù)躏救,通過參數(shù)名來獲取參數(shù)值唯笙;

Enumeration getInitParameterNames()
用來獲取在web.xml中配置的所有初始化參數(shù)名稱螟蒸;

例如web.xml有如下servlet元素:

  <servlet>
    <servlet-name>Hello</servlet-name>
    <servlet-class>com.example.servlet.HelloServlet</servlet-class>
    <init-param>
        <param-name>paramName1</param-name>
            <param-value>paramValue1</param-value>
    </init-param>
    <init-param>
            <param-name>paramName2</param-name>
            <param-value>paramValue2</param-value>
    </init-param>
  </servlet>

那么,可以通過以下方法來獲取相應(yīng)的信息:

public class Hello implements Servlet {
    public void init(ServletConfig config) throws ServletException {
        config.getServletName();//將得到Hello
        config.getInitParameter("paramName1");//將得到paramValue1
        config.getInitParameter("paramName2");//將得到paramValue2
        ...
    }
     ...
}
  • ServletRequest
    表示請求對象崩掘,它封裝了所有與請求相關(guān)的數(shù)據(jù)七嫌,它是由服務(wù)器創(chuàng)建的;
  • ServletResponse
    表示響應(yīng)對象苞慢,在service()方法中完成對客戶端的響應(yīng)需要使用這個(gè)對象诵原;
3、GenericServlet
  • GenericServletServlet接口的實(shí)現(xiàn)類挽放,可以通過繼承GenericServlet來編寫自己的Servlet绍赛。下面是GenericServlet類的源代碼:
public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private transient ServletConfig config;
    public GenericServlet() {}
    @Override
    public void destroy() {}
    @Override
    public String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }
    @Override
    public Enumeration<String> getInitParameterNames() {
        return getServletConfig().getInitParameterNames();
    }
    @Override
    public ServletConfig getServletConfig() {
        return config;
    }
    @Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
    @Override
    public String getServletInfo() {
        return "";
    }
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
    public void init() throws ServletException {}
    public void log(String msg) {
        getServletContext().log(getServletName() + ": " + msg);
    }
    public void log(String message, Throwable t) {
        getServletContext().log(getServletName() + ": " + message, t);
    }
    @Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
    @Override
    public String getServletName() {
        return config.getServletName();
    }
}

從代碼中可以看出:

(1)GenericServlet定義了一個(gè)ServletConfig config實(shí)例變量,并在init(ServletConfig)方法中把參數(shù)ServletConfig賦給了實(shí)例變量辑畦,然后在該類的很多方法中使用了實(shí)例變量config吗蚌。子類不能覆蓋init(ServletConfig config),而應(yīng)該去覆蓋GenericServlet提供的init()方法纯出,它是沒有參數(shù)的init()方法蚯妇。
(2)GenericServlet實(shí)現(xiàn)了ServletConfig接口,所以可以直接調(diào)用getInitParameter()暂筝、getServletContext()ServletConfig的方法箩言。

4、HttpServlet
  • HttpServlet類是GenericServlet的子類乖杠,它提供了對HTTP請求的特殊支持分扎,所以通常我們都會(huì)通過繼承HttpServlet來完成自定義的Servlet
  • HttpServlet覆蓋了service()方法
    HttpServletServletRequestServletResponse強(qiáng)轉(zhuǎn)成了HttpServletRequestHttpServletResponse胧洒,HttpServletservice(HttpServletRequest,HttpServletResponse)方法會(huì)去判斷當(dāng)前請求是GET還是POST(或其他)畏吓,如果是GET請求,那么會(huì)去調(diào)用本類的doGet()方法卫漫,如果是POST請求會(huì)去調(diào)用doPost()方法菲饼,也就是說,我們在子類中去覆蓋doGet()或doPost()方法即可列赎。
  • HttpServletRequest
    HttpServletRequestServletRequest的子類
public interface HttpServletRequest extends ServletRequest {......}

HttpServletRequest的方法:

String getParameter(String paramName)
獲取指定請求參數(shù)的值宏悦;

String getMethod()
:獲取請求方法,例如GET或POST包吝;

String getHeader(String name)
:獲取指定請求頭的值饼煞;

void setCharacterEncoding(String encoding)
:設(shè)置請求體的編碼。
因?yàn)閌GET`請求沒有請求體诗越,所以這個(gè)方法只只對POST請求有效砖瞧。
當(dāng)調(diào)用`request.setCharacterEncoding(“utf-8”)`之后,
再通過`getParameter()`方法獲取參數(shù)值時(shí)嚷狞,
那么參數(shù)值都已經(jīng)通過了轉(zhuǎn)碼块促,即轉(zhuǎn)換成了UTF-8編碼荣堰。
所以,這個(gè)方法必須在調(diào)用getParameter()方法之前調(diào)用竭翠!
  • HttpServletResponse
    HttpServletResponseServletResponse的子類振坚。
public interface HttpServletResponse extends ServletResponse{......}

HttpServletResponse方法:

PrintWriter getWriter()
獲取字符響應(yīng)流,使用該流可以向客戶端輸出響應(yīng)信息斋扰。
例如response.getWriter().print(“<h1>Hello JavaWeb!</h1>”)渡八;

ServletOutputStream getOutputStream()
獲取字節(jié)響應(yīng)流,當(dāng)需要向客戶端響應(yīng)字節(jié)數(shù)據(jù)時(shí)褥实,需要使用這個(gè)流呀狼;

void setCharacterEncoding(String encoding)
用來設(shè)置字符響應(yīng)流的編碼,
例如在調(diào)用setCharacterEncoding(“utf-8”);之后损离,
再response.getWriter()獲取字符響應(yīng)流對象哥艇,這時(shí)的響應(yīng)流的編碼為utf-8,
使用response.getWriter()輸出的中文都會(huì)轉(zhuǎn)換成utf-8編碼后發(fā)送給客戶端僻澎;

void setHeader(String name, String value)
向客戶端添加響應(yīng)頭信息貌踏,
例如setHeader(“Refresh”, “3;url=http://www.example.cn”),
表示3秒后自動(dòng)刷新到http://www.example.cn窟勃;

void setContentType(String contentType)
該方法是setHeader(“content-type”, “xxx”)的簡便方法祖乳,
即用來添加名為content-type響應(yīng)頭的方法。
content-type響應(yīng)頭用來設(shè)置響應(yīng)數(shù)據(jù)的`MIME`類型;

void sendError(int code, String errorMsg)
向客戶端發(fā)送狀態(tài)碼秉氧,以及錯(cuò)誤消息眷昆。
例如給客戶端發(fā)送404:response(404, “您要查找的資源不存在!”)汁咏。

四亚斋、Servlet與線程安全

因?yàn)橐粋€(gè)類型的Servlet只有一個(gè)實(shí)例對象,那么就有可能會(huì)出現(xiàn)一個(gè)Servlet同時(shí)處理多個(gè)請求的情況攘滩,那么Servlet是否為線程安全的呢帅刊?答案是:“不是線程安全的”。這說明Servlet的工作效率很高,但也存在線程安全問題:當(dāng)兩個(gè)或多個(gè)線程同時(shí)訪問同一個(gè)Servlet時(shí),可能會(huì)發(fā)生多個(gè)線程同時(shí)訪問同一資源的情況屋吨,數(shù)據(jù)可能會(huì)變得不一致。
所以我們不應(yīng)該在Servlet中隨意創(chuàng)建成員變量软瞎,因?yàn)榭赡軙?huì)存在一個(gè)線程對這個(gè)成員變量進(jìn)行寫操作,另一個(gè)線程對這個(gè)成員變量進(jìn)行讀操作。

所以:

  • 不要在Servlet中創(chuàng)建成員!創(chuàng)建局部變量即可抡爹!
  • 可以創(chuàng)建無狀態(tài)成員!
  • 可以創(chuàng)建有狀態(tài)的成員芒划,但狀態(tài)必須為只讀的冬竟!

Servlet體系結(jié)構(gòu)是建立在Java多線程機(jī)制之上的,它的生命周期是由Web容器負(fù)責(zé)的民逼。當(dāng)客戶端第一次請求某個(gè)Servlet 時(shí)泵殴,Servlet容器將會(huì)根據(jù)web.xml配置文件實(shí)例化這個(gè)Servlet類。當(dāng)有新的客戶端請求該Servlet時(shí)拼苍,一般不會(huì)再實(shí)例化該 Servlet類笑诅,也就是有多個(gè)線程在使用這個(gè)實(shí)例。Servlet容器會(huì)自動(dòng)使用線程池等技術(shù)來支持系統(tǒng)的運(yùn)行疮鲫。
有助理解的一個(gè)例子:

public class Concurrent extends HttpServlet {
    PrintWriter output;
    public void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String username;
        response.setContentType("text/html; charset=gb2312");
        username = request.getParameter("username");
        output = response.getWriter();
        try {
            Thread.sleep(5000); // 為了突出并發(fā)問題吆你,在這設(shè)置一個(gè)延時(shí)
        } catch (Exception e) {
        }
        output.println("用戶名:" + username + "<BR>");
    }
}

該Servlet中定義了一個(gè)實(shí)例變量output(servlet實(shí)例的成員變量),在service方法將其賦值為用戶的輸出俊犯。當(dāng)一個(gè)用戶訪問該Servlet時(shí)妇多,程序會(huì)正常的運(yùn)行;但當(dāng)多個(gè)用戶并發(fā)訪問時(shí)燕侠,就可能會(huì)出現(xiàn)其它用戶的信息顯示在另外一些用戶的瀏覽器上的問題者祖。
解決方法:

  • 使用Javax.servlet.SingleThreadModel(Servlet2.4中已經(jīng)廢棄該接口),此時(shí)Servlet容器將保證Servlet實(shí)例以單線程方式運(yùn)行绢彤,也就是說七问,同一時(shí)刻,只會(huì)有一個(gè)線程執(zhí)行Servlet的service()方法茫舶。但是械巡,如果一個(gè)Servlet實(shí)現(xiàn)了 SingleThreadModel接口,Servlet引擎將為每個(gè)新的請求創(chuàng)建一個(gè)單獨(dú)的Servlet實(shí)例饶氏,這將引起大量的系統(tǒng)開銷讥耗。 SingleThreadModel在Servlet2.4中已不再提倡使用;
將前面的Concurrent Test類的類頭定義更改為:

Public class Concurrent Test extends HttpServlet implements SingleThreadModel {
    ……
}
  • 去除實(shí)例變量嚷往,使用局部變量葛账。這是保證Servlet線程安全的最佳選擇。
public class Concurrent extends HttpServlet {
    public void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        PrintWriter output;
        String username;
        
        response.setContentType("text/html; charset=gb2312");
        username = request.getParameter("username");
        output = response.getWriter();
        try {
            Thread.sleep(5000); // 為了突出并發(fā)問題皮仁,在這設(shè)置一個(gè)延時(shí)
        } catch (Exception e) {
        }
        output.println("用戶名:" + username + "<BR>");
    }
}
  • 使用同步代碼塊:synchronized{…}籍琳;但是在程序中使用同步來保護(hù)要使用的共享的數(shù)據(jù),也會(huì)使系統(tǒng)的性能大大下降贷祈。這是因?yàn)楸煌降拇a塊在同一時(shí)刻只能有一個(gè)線程執(zhí)行它趋急,使得其同時(shí)處理客戶請求的吞吐量降低,而且很多客戶處于阻塞狀態(tài)势誊。另外為保證主存內(nèi)容和線程的工作內(nèi)存中的數(shù)據(jù)的一致性呜达,要頻繁地刷新緩存,這也會(huì)大大地影響系統(tǒng)的性能。在實(shí)際的開發(fā)中也應(yīng)避免或最小化 Servlet 中的同步代碼粟耻;
public void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String username;
        response.setContentType("text/html; charset=gb2312");
        username = request.getParameter("username");
        
        synchronized(this){
            output = response.getWriter();
            try {
                Thread.sleep(5000); // 為了突出并發(fā)問題查近,在這設(shè)置一個(gè)延時(shí)
            } catch (Exception e) {
            }
            output.println("用戶名:" + username + "<BR>");
        }
    }
  • 不同變量的線程安全問題
    在Servlet和JSP中眉踱,變量可以歸為下面的幾類:

  • 類變量:request,response霜威,session谈喳,config,application戈泼,以及JSP頁面內(nèi)置的page, pageContext婿禽。其中除了application外,其它都是線程安全的大猛。

  • 實(shí)例變量:實(shí)例變量是實(shí)例所有的扭倾,在堆中分配。在Servlet和JSP容器中挽绩,一般僅實(shí)例化一個(gè)Servlet和JSP實(shí)例膛壹,啟動(dòng)多個(gè)該實(shí)例的線程來處理請求。而實(shí)例變量是該實(shí)例所有的線程所共享琼牧,所以恢筝,實(shí)例變量不是線程安全的

  • 局部變量:局部變量在堆棧中分配巨坊,因?yàn)槊恳粋€(gè)線程有自己的執(zhí)行堆棧撬槽,所以,局部變量是線程安全的趾撵。

五侄柔、<url-pattern>

  • <url-pattern><servlet-mapping>的子元素,用來指定Servlet的訪問路徑占调,即URL暂题。
  • 它必須以/開頭!
  • 可以在<servlet-mapping>中給出多個(gè)<url-pattern>究珊,例如:
<servlet-mapping>
    <servlet-name>AServlet</servlet-name>
    <url-pattern>/AServlet</url-pattern>
    <url-pattern>/BServlet</url-pattern>
  </servlet-mapping>

說明一個(gè)Servlet綁定了兩個(gè)URL薪者,無論訪問/AServlet還是/BServlet,訪問的都是AServlet剿涮。

  • 在<url-pattern>中使用通配符

(1)所謂通配符就是星號(hào)*言津,使用通配符可以命名一個(gè)Servlet綁定一組URL。
(2)通配符要么為前綴取试,要么為后綴悬槽,不能出現(xiàn)在URL中間位置,也不能只有通配符瞬浓。
(3)通配符是一種模糊匹配URL的方式初婆,如果存在更具體的<url-pattern>,那么訪問路徑會(huì)去匹配具體的<url-pattern>

六磅叛、ServletContext

6.1 ServletContext概述
  • 服務(wù)器會(huì)為每個(gè)應(yīng)用創(chuàng)建唯一一個(gè)ServletContext對象屑咳;(應(yīng)用內(nèi)唯一)
  • ServletContext對象的創(chuàng)建是在服務(wù)器啟動(dòng)時(shí)完成的;(出生)
  • ServletContext對象的銷毀是在服務(wù)器關(guān)閉時(shí)完成的弊琴。(死亡)
  • ServletContext對象的作用是在整個(gè)Web應(yīng)用的動(dòng)態(tài)資源之間共享數(shù)據(jù)乔宿。(作用)
6.2 獲取ServletContext
  • 在Servlet中獲取ServletContext對象

void init(ServletConfig config)中:ServletContext context = config.getServletContext();ServletConfig類的getServletContext()方法可以用來獲取ServletContext對象访雪;

  • 在GenericeServlet或HttpServlet中獲取ServletContext對象

直接使用this.getServletContext()來獲取掂林;

6.3 ServletContext對象的作用
  • ServletContextJavaWeb四大域?qū)ο螅?code>PageContext臣缀、ServletRequestHttpSession泻帮、ServletContext)之一精置。
  • 所有域?qū)ο蠖加写嫒?shù)據(jù)的功能,因?yàn)橛驅(qū)ο髢?nèi)部有一個(gè)Map锣杂,用來存儲(chǔ)數(shù)據(jù)脂倦。
  • ServletContext對象用來操作數(shù)據(jù)的方法
void setAttribute(String name, Object value)
用來存儲(chǔ)一個(gè)對象,也可以稱之為存儲(chǔ)一個(gè)域?qū)傩裕?例如:servletContext.setAttribute(“xxx”, “XXX”)元莫,在ServletContext中保存了一個(gè)域?qū)傩岳底瑁驅(qū)傩悦Q為xxx,域?qū)傩缘闹禐閄XX踱蠢。
請注意火欧,如果多次調(diào)用該方法,并且使用相同的name茎截,那么會(huì)覆蓋上一次的值苇侵,這一特性與Map相同;

Object getAttribute(String name)
用來獲取ServletContext中的數(shù)據(jù)企锌,當(dāng)前在獲取之前需要先去存儲(chǔ)才行榆浓,
例如:String value = (String)servletContext.getAttribute(“xxx”);,獲取名為xxx的域?qū)傩裕?
void removeAttribute(String name)
用來移除ServletContext中的域?qū)傩运涸埽绻麉?shù)name指定的域?qū)傩圆淮嬖诙妇椋敲幢痉椒ㄊ裁炊疾蛔觯?
Enumeration getAttributeNames()
獲取所有域?qū)傩缘拿Q;
  • ServletContext獲取應(yīng)用初始化參數(shù)

(1)Servlet也可以獲取初始化參數(shù)打却,但它是局部的參數(shù)杉适;也就是說,一個(gè)Servlet只能獲取自己的初始化參數(shù)柳击,不能獲取別人的猿推,即初始化參數(shù)只為一個(gè)Servlet準(zhǔn)備!
(2)可以配置公共的初始化參數(shù),為所有Servlet而用蹬叭!這需要使用ServletContext才能使用藕咏!
(3)還可以使用ServletContext來獲取在web.xml文件中配置的應(yīng)用初始化參數(shù)!注意秽五,應(yīng)用初始化參數(shù)與Servlet初始化參數(shù)不同孽查。

<web-app ...>
  ...
  <context-param>
    <param-name>paramName1</param-name>
    <param-value>paramValue1</param-value>      
  </context-param>
  <context-param>
    <param-name>paramName2</param-name>
    <param-value>paramValue2</param-value>      
  </context-param>
</web-app>
  • ServletContext獲取資源(略)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市坦喘,隨后出現(xiàn)的幾起案子盲再,更是在濱河造成了極大的恐慌,老刑警劉巖瓣铣,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件答朋,死亡現(xiàn)場離奇詭異,居然都是意外死亡棠笑,警方通過查閱死者的電腦和手機(jī)梦碗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蓖救,“玉大人洪规,你說我怎么就攤上這事⊙啵” “怎么了斩例?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長巨柒。 經(jīng)常有香客問我樱拴,道長,這世上最難降的妖魔是什么洋满? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任晶乔,我火速辦了婚禮,結(jié)果婚禮上牺勾,老公的妹妹穿的比我還像新娘正罢。我一直安慰自己,他們只是感情好驻民,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布翻具。 她就那樣靜靜地躺著,像睡著了一般回还。 火紅的嫁衣襯著肌膚如雪裆泳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天柠硕,我揣著相機(jī)與錄音工禾,去河邊找鬼运提。 笑死,一個(gè)胖子當(dāng)著我的面吹牛闻葵,可吹牛的內(nèi)容都是我干的民泵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼槽畔,長吁一口氣:“原來是場噩夢啊……” “哼栈妆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起厢钧,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤鳞尔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后早直,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铅檩,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年莽鸿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拾给。...
    茶點(diǎn)故事閱讀 40,505評(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,873評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伟件。 院中可真熱鬧硼啤,春花似錦、人聲如沸斧账。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咧织。三九已至嗓袱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間习绢,已是汗流浹背渠抹。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逼肯。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓耸黑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親篮幢。 傳聞我的和親對象是個(gè)殘疾皇子大刊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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