Spring 學(xué)習(xí)筆記(十一)Spring MVC的高級(jí)技術(shù)

Spring MVC 配置的替代方案

自定義 DispatcherServlet 配置

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;

public class MyServletInitializer implements WebApplicationInitializer{

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException{
        Dynamic myServlet = servletContext.addServlet("myServlet",MyServlet.class);
        myServlet.addMapping("/custom/**");
    }
}

雖然從代碼外觀上不一定能夠看得出來(lái)蛹尝,但是 Abstract-AnnotationConfigDispatcherServletInitializer 所完成的事情其實(shí)比看上去要多戈擒。在 SpittrWebAppInitializer 中我們所編寫的三個(gè)方法僅僅是必須要重載的abstract方法切心。但實(shí)際上還有更多的方法可以進(jìn)行重載,從而實(shí)現(xiàn)額外的配置。

此類的方法之一就是 customizeRegistration()。在 AbstractAnnotation-
ConfigDispatcherServletInitializer 將 DispatcherServlet 注冊(cè)到 Servlet 容器中之后,就會(huì)調(diào)用 customizeRegistration()温兼,并將 Servlet 注冊(cè)后得到的 Registration.Dynamic 傳遞進(jìn)來(lái)。通過(guò)重載 customizeRegistration() 方法武契,我們可以對(duì) DispatcherServlet 進(jìn)行額外的配置募判。

在稍后的內(nèi)容中,我們將會(huì)看到如何在 SpringMVC 中處理 multipart 請(qǐng)求和文件上傳咒唆。如果計(jì)劃使用 Servlet 3.0 對(duì) multipart 配置的支持届垫,那么需要使用 DispatcherServlet 的 registration 來(lái)啟用 multipart 請(qǐng)求。我們可以重載 customizeRegistration() 方法來(lái)設(shè)置 MultipartConfigElement全释,如下所示:

@Override
protected void customizeRegistration(Dynamic registration){
    registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
}

借助 customizeRegistration() 方法中的 ServletRegistration.Dynamic装处,我們能夠完成多項(xiàng)任務(wù),包括通過(guò)調(diào)用 setLoadOnStartup() 設(shè)置 load-on-startup 優(yōu)先級(jí)浸船,通過(guò) setInitParameter() 設(shè)置初始化參數(shù)妄迁,通過(guò)調(diào)用setMultipartConfig() 配置 Servlet 3.0 對(duì) multipart 的支持。在前面的樣例中李命,我們?cè)O(shè)置了對(duì) multipart 的支持登淘,將上傳文件的臨時(shí)存儲(chǔ)目錄設(shè)置在 “/tmp/spittr/uploads” 中。

添加其他的Servlet和Filter

基于Java的初始化器(initializer)的一個(gè)好處就在于我們可以定義任意數(shù)量的初始化器類封字。因此形帮,如果我們想往 Web 容器中注冊(cè)其他組件的話,只需創(chuàng)建一個(gè)新的初始化器就可以了周叮。最簡(jiǎn)單的方式就是實(shí)現(xiàn) Spring 的WebApplicationInitializer 接口。
開頭的程序清單展現(xiàn)了如何創(chuàng)建 WebApplicationInitializer 實(shí)現(xiàn)并注冊(cè)一個(gè) Servlet界斜。

類似地仿耽,我們還可以創(chuàng)建新的 WebApplicationInitializer 實(shí)現(xiàn)來(lái)注冊(cè) Listener 和 Filter。例如各薇,如下的程序清單展現(xiàn)了如何注冊(cè) Filter项贺。

@Override
public void onStartup(ServletContext servletContext) throws ServletException{
    javax.servlet.FilterRegistration.Dynamic filter = servletContext.addFilter("myFilter",MyFilter.class);
    filter.addMappingForUrlPatterns(null,false,"/custom/**");
}

如果要將應(yīng)用部署到支持 Servlet 3.0 的容器中,那么 WebApplicationInitializer 提供了一種通用的方式峭判,實(shí)現(xiàn)在Java中注冊(cè) Servlet开缎、Filter 和 Listener。不過(guò)林螃,如果你只是注冊(cè) Filter奕删,并且該 Filter 只會(huì)映射到 DispatcherServlet 上的話,那么在 AbstractAnnotationConfigDispatcherServletInitializer 中還有一種快捷方式疗认。

為了注冊(cè) Filter 并將其映射到 DispatcherServlet完残,所需要做的僅僅是重載 AbstractAnnotationConfigDispatcherServletInitializer 的 getServlet-Filters() 方法伏钠。例如,在如下的代碼中谨设,重載了 AbstractAnnotationConfig-DispatcherServletInitializer 的 getServletFilters() 方法以注冊(cè) Filter:

@Override
protected Filter[] getServletFilters(){
    return new Filter[] {new MyFilter()};
}

我們可以看到熟掂,這個(gè)方法返回的是一個(gè) javax.servlet.Filter 的數(shù)組。在這里它只返回了一個(gè) Filter扎拣,但它實(shí)際上可以返回任意數(shù)量的 Filter赴肚。在這里沒(méi)有必要聲明它的映射路徑,getServletFilters() 方法返回的所有 Filter 都會(huì)映射到 DispatcherServlet 上二蓝。

處理 multipart 形式的數(shù)據(jù)

在 Web 應(yīng)用中誉券,允許用戶上傳內(nèi)容是很常見的需求。Spittr 應(yīng)用在兩個(gè)地方需要文件上傳侣夷。當(dāng)新用戶注冊(cè)應(yīng)用的時(shí)候横朋,我們希望他們能夠上傳一張圖片,從而與他們的個(gè)人信息相關(guān)聯(lián)百拓。當(dāng)用戶提交新的 Spittle 時(shí)琴锭,除了文本消息以外,他們可能還會(huì)上傳一張照片衙传。

一般表單提交所形成的請(qǐng)求結(jié)果是很簡(jiǎn)單的决帖,就是以“&”符分割的多
個(gè)name-value對(duì)。例如蓖捶,當(dāng)在Spittr應(yīng)用中提交注冊(cè)表單時(shí)地回,請(qǐng)求會(huì)如
下所示:

firstName=Charles&lastName=Xavier&email=porfessorx%40xmen.org
&username=professorx&password=letmein01

盡管這種編碼形式很簡(jiǎn)單,并且對(duì)于典型的基于文本的表單提交也足夠滿足要求俊鱼,但是對(duì)于傳送二進(jìn)制數(shù)據(jù)刻像,如上傳圖片,就顯得力不從心了并闲。與之不同的是细睡,multipart 格式的數(shù)據(jù)會(huì)將一個(gè)表單拆分為多個(gè)部分(part),每個(gè)部分對(duì)應(yīng)一個(gè)輸入域帝火。在一般的表單輸入域中溜徙,它所對(duì)應(yīng)的部分中會(huì)放置文本型數(shù)據(jù),但是如果上傳文件的話犀填,它所對(duì)應(yīng)的部分可以是二進(jìn)制蠢壹,下面展現(xiàn)了 multipart 的請(qǐng)求體:

image.png

配置 multipart 解析器

DispatcherServlet 并沒(méi)有實(shí)現(xiàn)任何解析 multipart 請(qǐng)求數(shù)據(jù)的功能。它將該任務(wù)委托給了 Spring 中 MultipartResolver 策略接口的實(shí)現(xiàn)九巡,通過(guò)這個(gè)實(shí)現(xiàn)類來(lái)解析 multipart 請(qǐng)求中的內(nèi)容图贸。從 Spring 3.1 開始,Spring 內(nèi)置了兩個(gè) MultipartResolver 的實(shí)現(xiàn)供我們選擇:
-CommonsMultipartResolver:使用 Jakarta CommonsFileUpload 解析 multipart 請(qǐng)求;
-StandardServletMultipartResolver:依賴于 Servlet 3.0 對(duì) multipart 請(qǐng)求的支持(始于 Spring 3.1)求妹。

StandardServletMultipartResolver 沒(méi)有構(gòu)造器參數(shù)乏盐,也沒(méi)有要設(shè)置的屬性。這樣制恍,在 Spring 應(yīng)用上下文中父能,將其聲明為 bean 就會(huì)非常簡(jiǎn)單,如下所示:

@Bean
public MultipartResolver multipartResolver() throws IOException{
    return new StandardServletMultipartResolver();
}

既然這個(gè) @Bean 方法如此簡(jiǎn)單净神,你可能就會(huì)懷疑我們到底該如何限制
StandardServletMultipartResolver 的工作方式呢何吝。如果我們想要限制用戶上傳文件的大小,該怎么實(shí)現(xiàn)鹃唯?如果我們想要指定文件在上傳時(shí)爱榕,臨時(shí)寫入目錄在什么位置的話,該如何實(shí)現(xiàn)坡慌?因?yàn)闆](méi)有屬性和構(gòu)造器參數(shù)黔酥,StandardServletMultipartResolver 的功能看起來(lái)似乎有些受限。

其實(shí)并不是這樣洪橘,我們是有辦法配置 StandardServletMultipartResolver 的限制條件的跪者。只不過(guò)不是在 Spring 中配置 StandardServletMultipartResolver,而是要在 Servlet 中指定 multipart 的配置熄求。至少渣玲,我們必須要指定在文件上傳的過(guò)程中,所寫入的臨時(shí)文件路徑弟晚。如果不設(shè)定這個(gè)最基本配置的話忘衍,StandardServlet-MultipartResolver 就無(wú)法正常工作。具體來(lái)講,我們必須要在 web.xml 或 Servlet 初始化類中,將 multipart 的具體細(xì)節(jié)作為 DispatcherServlet 配置的一部分鹅髓。

如果我們采用 Servlet 初始化類的方式來(lái)配置 DispatcherServlet 的話,這個(gè)初始化類應(yīng)該已經(jīng)實(shí)現(xiàn)了 WebApplicationInitializer搀捷,那我們可以在 Servlet registration 上調(diào)用 setMultipartConfig() 方法,傳入一個(gè) MultipartConfig-Element 實(shí)例勉耀。如下是最基本的 DispatcherServlet multipart 配置,它將臨時(shí)路徑設(shè)置為 “/tmp/spittr/uploads”:

DispatcherServlet ds = new DispatcherServlet();
Dynamic registration = context.addServlet("appServlet",ds);
registration.addMapping("/");
registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));

如果我們配置 DispatcherServlet 的 Servlet 初始化類繼承了Abstract AnnotationConfigDispatcherServletInitializer 或 AbstractDispatcher-ServletInitializer 的話蹋偏,那么我們不會(huì)直接創(chuàng)建 DispatcherServlet 實(shí)例并將其注冊(cè)到 Servlet 上下文中便斥。這樣的話,將不會(huì)有對(duì) Dynamic Servlet registration 的引用供我們使用了威始。但是枢纠,我們可以通過(guò)重載 customizeRegistration() 方法(它會(huì)得到一個(gè) Dynamic 作為參數(shù))來(lái)配置 multipart 的具體細(xì)節(jié):

@Override
protected void customizeRegistration(Dynamic registration){
    registration.seMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
}

到目前為止,我們所使用是只有一個(gè)參數(shù)的 MultipartConfigElement 構(gòu)造器黎棠,這個(gè)參數(shù)指定的是文件系統(tǒng)中的一個(gè)絕對(duì)目錄晋渺,上傳文件將會(huì)臨時(shí)寫入該目錄中镰绎。但是,我們還可以通過(guò)其他的構(gòu)造器來(lái)限制上傳文件的大小木西。除了臨時(shí)路徑的位置畴栖,其他的構(gòu)造器3所能接受的參數(shù)如下:
-上傳文件的最大容量(以字節(jié)為單位)。默認(rèn)是沒(méi)有限制的八千。
-整個(gè) multipart 請(qǐng)求的最大容量(以字節(jié)為單位)吗讶,不會(huì)關(guān)心有多少個(gè) part 以及每個(gè) part 的大小。默認(rèn)是沒(méi)有限制的恋捆。
-在上傳的過(guò)程中照皆,如果文件大小達(dá)到了一個(gè)指定最大容量(以字節(jié)為單位),將會(huì)寫入到臨時(shí)文件路徑中沸停。默認(rèn)值為 0膜毁,也就是所有上傳的文件都會(huì)寫入到磁盤上。

例如愤钾,假設(shè)我們想限制文件的大小不超過(guò) 2MB瘟滨,整個(gè)請(qǐng)求不超過(guò) 4MB,而且所有的文件都要寫到磁盤中绰垂。下面的代碼使用 MultipartConfigElement 設(shè)置了這些臨界值:

@Override
protected void customizeRegistration(Dynamic registration){
    registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads",2097152,4194304,0));
}

配置 Jakarta Commons FileUpload multipart 解析器

通常來(lái)講室奏,StandardServletMultipartResolver 會(huì)是最佳的選擇,但是如果我們需要將應(yīng)用部署到非 Servlet 3.0 的容器中劲装,那么就得需要替代的方案胧沫。如果喜歡的話,我們可以編寫自己的 MultipartResolver 實(shí)現(xiàn)占业。不過(guò)绒怨,除非想要在處理 multipart 請(qǐng)求的時(shí)候執(zhí)行特定的邏輯,否則的話谦疾,沒(méi)有必要這樣做南蹂。Spring 內(nèi)置了 CommonsMultipartResolver,可以作為 StandardServletMultipartResolver 的替代方案念恍。
將 CommonsMultipartResolver 聲明為 Spring bean 的最簡(jiǎn)單方式如下:

@Bean
public MultipartResolver multipartResolver(){
    return new CommonsMultipartResolver();
}

與 StandardServletMultipartResolver 有所不同六剥,CommonsMultipart-Resolver 不會(huì)強(qiáng)制要求設(shè)置臨時(shí)文件路徑。默認(rèn)情況下峰伙,這個(gè)路徑就是 Servlet 容器的臨時(shí)目錄疗疟。不過(guò),通過(guò)設(shè)置 uploadTempDir 屬性瞳氓,我們可以將其指定為一個(gè)不同的位置:

@Bean
public MultipartResolver multipartResolver() throws IOException{
    CommonMultipartResolver multipartResolver = new CommonMultipartResolver();
    multipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spittr/uploads"));
    return multipartResolver;
}

實(shí)際上策彤,我們可以按照相同的方式指定其他的 multipart 上傳細(xì)節(jié),也就是設(shè)置 CommonsMultipartResolver 的屬性。例如店诗,如下的配置就等價(jià)于我們?cè)谇拔耐ㄟ^(guò) MultipartConfigElement 所配置的 StandardServletMultipartResolver:

@Bean
    public MultipartResolver multipartResolver() throws IOException{
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spittr/uploads"));
        multipartResolver.setMaxUploadSize(2097152);
        multipartResolver.setMaxInMemorySize(0);
        return multipartResolver;
    }

在這里裹刮,我們將最大的文件容量設(shè)置為 2MB,最大的內(nèi)存大小設(shè)置為0字節(jié)庞瘸。這兩個(gè)屬性直接對(duì)應(yīng)于 MultipartConfigElement 的第二個(gè)和第四個(gè)構(gòu)造器參數(shù)捧弃,表明不能上傳超過(guò) 2MB 的文件,并且不管文件的大小如何恕洲,所有的文件都會(huì)寫到磁盤中塔橡。但是與 MultipartConfigElement 有所不同,我們無(wú)法設(shè)定 multipart 請(qǐng)求整體的最大容量霜第。

處理multipart請(qǐng)求

現(xiàn)在已經(jīng)在 Spring 中(或 Servlet 容器中)配置好了對(duì) mutipart 請(qǐng)求的處理葛家,那么接下來(lái)我們就可以編寫控制器方法來(lái)接收上傳的文件。要實(shí)現(xiàn)這一點(diǎn)泌类,最常見的方式就是在某個(gè)控制器方法參數(shù)上添加 @RequestPart 注解癞谒。

假設(shè)我們?cè)试S用戶在注冊(cè) Spittr 應(yīng)用的時(shí)候上傳一張圖片,那么我們需要修改表單刃榨,以允許用戶選擇要上傳的圖片弹砚,同時(shí)還需要修改 SpitterController 中的 processRegistration() 方法來(lái)接收上傳的圖片。如下的代碼片段來(lái)源于 Thymeleaf 注冊(cè)表單視圖(registrationForm.html)枢希,著重強(qiáng)調(diào)了表單所需的修改:

<form method="POST" th:object="${spitter}" enctype="multipart/form-data">
...
  <label>Profile Picture</label>
      <input type="file" name="profilePicture" accept="image/jpeg,image/png,image/gif"/><br/>
...
</form>

<form> 標(biāo)簽現(xiàn)在將 enctype 屬性設(shè)置為 multipart/formdata桌吃,這會(huì)告訴瀏覽器以 multipart 數(shù)據(jù)的形式提交表單,而不是以表單數(shù)據(jù)的形式進(jìn)行提交苞轿。在 multipart 中茅诱,每個(gè)輸入域都會(huì)對(duì)應(yīng)一個(gè) part。

除了注冊(cè)表單中已有的輸入域搬卒,我們還添加了一個(gè)新的 <input> 域瑟俭,其 type 為 file。這能夠讓用戶選擇要上傳的圖片文件契邀。accept 屬性用來(lái)將文件類型限制為 JPEG摆寄、PNG 以及 GIF 圖片。根據(jù)其 name 屬性坯门,圖片數(shù)據(jù)將會(huì)發(fā)送到 multipart 請(qǐng)求中的 profilePicture part 之中微饥。

現(xiàn)在,我們需要修改 processRegistration() 方法古戴,使其能夠接受上傳的圖片欠橘。其中一種方式是添加byte數(shù)組參數(shù),并為其添加 @RequestPart 注解允瞧。如下為示例:

@RequestMapping(value="/register",method=POST)
public String processRegistration(
    @RequestPart("profilePicture") byte[] profilePicture, 
    @Valid Spitter spitter, Errors errors){
    ...
}

當(dāng)注冊(cè)表單提交的時(shí)候简软,profilePicture 屬性將會(huì)給定一個(gè) byte 數(shù)組,這個(gè)數(shù)組中包含了請(qǐng)求中對(duì)應(yīng)part的數(shù)據(jù)(通過(guò) @RequestPart 指定)述暂。如果用戶提交表單的時(shí)候沒(méi)有選擇文件痹升,那么這個(gè)數(shù)組會(huì)是空(而不是null)。獲取到圖片數(shù)據(jù)后畦韭,processRegistration() 方法剩下的任務(wù)就是將文件保存到某個(gè)位置疼蛾。

接受MultipartFile

使用上傳文件的原始 byte 比較簡(jiǎn)單但是功能有限。因此艺配,Spring 還提供了 MultipartFile 接口察郁,它為處理 multipart 數(shù)據(jù)提供了內(nèi)容更為豐富的對(duì)象。如下的程序清單展現(xiàn)了 MultipartFile 接口的概況转唉。
程序清單7.5 Spring 所提供的 MultipartFile 接口皮钠,用來(lái)處理上傳的文件

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public interface MultipartFile {
    String geName();
    String getOriginalFilename();
    String getContentType();
    boolean isEmpty();
    long getSize();
    byte[] getByte() throws IOException;
    InputStream getInputStream() throws IOException;
    void transferTo(File dest) throws IOException;
}

我們可以看到,MultipartFile 提供了獲取上傳文件 byte 的方式赠法,但是它所提供的功能并不僅限于此麦轰,還能獲得原始的文件名、大小以及內(nèi)容類型砖织。它還提供了一個(gè) InputStream款侵,用來(lái)將文件數(shù)據(jù)以流的方式進(jìn)行讀取
除此之外侧纯,MultipartFile 還提供了一個(gè)便利的 transferTo() 方法新锈,它能夠幫助我們將上傳的文件寫入到文件系統(tǒng)中。作為樣例眶熬,我們可以在 process-Registration() 方法中添加如下的幾行代碼妹笆,從而將上傳的圖片文件寫入到文件系統(tǒng)中:

profilePicture.transferTo(new File("/data/spittr/" + profilePicture.getOriginalFilename()));

以 Part 的形式接受上傳的文件

如果你需要將應(yīng)用部署到 Servlet 3.0 的容器中,那么會(huì)有 MultipartFile 的一個(gè)替代方案聋涨。Spring MVC 也能接受 javax.servlet.http.Part 作為控制器方法的參數(shù)晾浴。如果使用 Part 來(lái)替換 MultipartFile 的話,那么 processRegistration() 的方法簽名將會(huì)變成如下的形式:

@RequestMapping(value="/register",method=POST)
public String processRegistration(
    @RequestPart("profilePicture") Part profilePicture,
    @Valid Spitter spitter,
    Errors errors){
}

Part接口:Spring MultipartFile的替代方案:

package javax.servlet.http;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;

public interface Part {
    InputStream getInputStream() throws IOException;
    String getContentType();
    String getName();
    long getSize();
    void write(String var1) throws IOException;
    void delete() throws IOException;
    String getHeader(String var1);
    Collection<String> getHeaders(String var1);
    Collection<String> getHeaderNames();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末牍白,一起剝皮案震驚了整個(gè)濱河市脊凰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌茂腥,老刑警劉巖狸涌,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異最岗,居然都是意外死亡帕胆,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門般渡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)懒豹,“玉大人芙盘,你說(shuō)我怎么就攤上這事×郴啵” “怎么了儒老?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)记餐。 經(jīng)常有香客問(wèn)我驮樊,道長(zhǎng),這世上最難降的妖魔是什么片酝? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任囚衔,我火速辦了婚禮,結(jié)果婚禮上雕沿,老公的妹妹穿的比我還像新娘练湿。我一直安慰自己,他們只是感情好审轮,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布鞠鲜。 她就那樣靜靜地躺著,像睡著了一般断国。 火紅的嫁衣襯著肌膚如雪贤姆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天稳衬,我揣著相機(jī)與錄音霞捡,去河邊找鬼。 笑死薄疚,一個(gè)胖子當(dāng)著我的面吹牛碧信,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播街夭,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼砰碴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了板丽?” 一聲冷哼從身側(cè)響起呈枉,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎埃碱,沒(méi)想到半個(gè)月后猖辫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砚殿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年啃憎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片似炎。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辛萍,死狀恐怖悯姊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贩毕,我是刑警寧澤挠轴,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站耳幢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏欧啤。R本人自食惡果不足惜睛藻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望邢隧。 院中可真熱鬧店印,春花似錦、人聲如沸倒慧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纫谅。三九已至炫贤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間付秕,已是汗流浹背兰珍。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留询吴,地道東北人掠河。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像猛计,于是被迫代替她去往敵國(guó)和親唠摹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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